播放和录制流媒体音频

时间:2010-06-15 09:58:44

标签: iphone

我正在开发一款能够同时播放和录制音频流数据的iPhone应用。它真的可能吗?我正在尝试混合SpeakHere和AudioRecorder示例,并获得一个没有音频数据的空文件......

这是我的.m代码:

#import "AzRadioViewController.h"

@implementation azRadioViewController

static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted |
kCFStreamEventHasBytesAvailable |
kCFStreamEventEndEncountered |
kCFStreamEventErrorOccurred;

void MyAudioQueueOutputCallback( void* inClientData, 
AudioQueueRef inAQ, 
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime, 
UInt32 inNumberPacketDescriptions, 
const AudioStreamPacketDescription* inPacketDesc
)
{
NSLog(@"start MyAudioQueueOutputCallback");


MyData* myData = (MyData*)inClientData;


NSLog(@"--- %i", inNumberPacketDescriptions);

if(inNumberPacketDescriptions == 0 && myData->dataFormat.mBytesPerPacket != 0)
{
inNumberPacketDescriptions = inBuffer->mAudioDataByteSize / myData->dataFormat.mBytesPerPacket;
}


OSStatus status = AudioFileWritePackets(myData->audioFile, FALSE, inBuffer->mAudioDataByteSize,
inPacketDesc, myData->currentPacket, &inNumberPacketDescriptions, inBuffer->mAudioData);


if(status == 0)
{
myData->currentPacket += inNumberPacketDescriptions;
}

NSLog(@"status:%i curpac:%i pcdesct: %i", status, myData->currentPacket, inNumberPacketDescriptions);


unsigned int bufIndex = MyFindQueueBuffer(myData, inBuffer);

pthread_mutex_lock(&myData->mutex);
myData->inuse[bufIndex] = false;
pthread_cond_signal(&myData->cond);
pthread_mutex_unlock(&myData->mutex);
}


OSStatus StartQueueIfNeeded(MyData* myData)
{

NSLog(@"start StartQueueIfNeeded");

OSStatus err = noErr;
if (!myData->started) { 
err = AudioQueueStart(myData->queue, NULL);
if (err) { PRINTERROR("AudioQueueStart"); myData->failed = true; return err; } 
myData->started = true;
printf("started\n");
}
return err;
}



OSStatus MyEnqueueBuffer(MyData* myData)
{
NSLog(@"start MyEnqueueBuffer");


OSStatus err = noErr;
myData->inuse[myData->fillBufferIndex] = true; 

AudioQueueBufferRef fillBuf = myData->audioQueueBuffer[myData->fillBufferIndex];
fillBuf->mAudioDataByteSize = myData->bytesFilled; 
err = AudioQueueEnqueueBuffer(myData->queue, fillBuf, myData->packetsFilled, myData->packetDescs);
if (err) { PRINTERROR("AudioQueueEnqueueBuffer"); myData->failed = true; return err; } 



StartQueueIfNeeded(myData);

return err;
}


void WaitForFreeBuffer(MyData* myData)
{
NSLog(@"start WaitForFreeBuffer");

if (++myData->fillBufferIndex >= kNumAQBufs) myData->fillBufferIndex = 0;
myData->bytesFilled = 0; 
myData->packetsFilled = 0; 

printf("->lock\n");
pthread_mutex_lock(&myData->mutex); 
while (myData->inuse[myData->fillBufferIndex]) {
printf("... WAITING ...\n");
pthread_cond_wait(&myData->cond, &myData->mutex);
}
pthread_mutex_unlock(&myData->mutex);
printf("<-unlock\n");
}


int MyFindQueueBuffer(MyData* myData, AudioQueueBufferRef inBuffer)
{
NSLog(@"start MyFindQueueBuffer");

for (unsigned int i = 0; i < kNumAQBufs; ++i) {
if (inBuffer == myData->audioQueueBuffer[i]) 
return i;
}
return -1;
}


void MyAudioQueueIsRunningCallback( void* inClientData, 
AudioQueueRef inAQ, 
AudioQueuePropertyID inID)
{
NSLog(@"start MyAudioQueueIsRunningCallback");

MyData* myData = (MyData*)inClientData;

UInt32 running;
UInt32 size;
OSStatus err = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &running, &size);
if (err) { PRINTERROR("get kAudioQueueProperty_IsRunning"); return; }
if (!running) {
pthread_mutex_lock(&myData->mutex);
pthread_cond_signal(&myData->done);
pthread_mutex_unlock(&myData->mutex);
}
}


void MyPropertyListenerProc( void * inClientData,
AudioFileStreamID inAudioFileStream,
AudioFileStreamPropertyID inPropertyID,
UInt32 * ioFlags)
{ 
NSLog(@"start MyPropertyListenerProc");

MyData* myData = (MyData*)inClientData;
OSStatus err = noErr;

printf("found property '%c%c%c%c'\n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255);


switch (inPropertyID) {
case kAudioFileStreamProperty_ReadyToProducePackets :
{

AudioStreamBasicDescription asbd;
UInt32 asbdSize = sizeof(asbd);



err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
if (err) { PRINTERROR("get kAudioFileStreamProperty_DataFormat"); myData->failed = true; break; }

err = AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->queue);
if (err) { PRINTERROR("AudioQueueNewOutput"); myData->failed = true; break; }


for (unsigned int i = 0; i < kNumAQBufs; ++i) {
err = AudioQueueAllocateBuffer(myData->queue, kAQBufSize, &myData->audioQueueBuffer[i]);
if (err) { PRINTERROR("AudioQueueAllocateBuffer"); myData->failed = true; break; }
}

UInt32 cookieSize;
Boolean writable;
err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable);
if (err) { PRINTERROR("info kAudioFileStreamProperty_MagicCookieData"); break; }
printf("cookieSize %d\n", cookieSize);

void* cookieData = calloc(1, cookieSize);
err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData);
if (err) { PRINTERROR("get kAudioFileStreamProperty_MagicCookieData"); free(cookieData); break; }

err = AudioQueueSetProperty(myData->queue, kAudioQueueProperty_MagicCookie, cookieData, cookieSize);
free(cookieData);
if (err) { PRINTERROR("set kAudioQueueProperty_MagicCookie"); break; }

err = AudioQueueAddPropertyListener(myData->queue, kAudioQueueProperty_IsRunning, MyAudioQueueIsRunningCallback, myData);
if (err) { PRINTERROR("AudioQueueAddPropertyListener"); myData->failed = true; break; }





break;
}
}
}


static void
ReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo) {

NSLog(@"start ReadStreamClientCallBack");

if(type == kCFStreamEventHasBytesAvailable) {

UInt8 buffer[2048];
CFIndex bytesRead = CFReadStreamRead(stream, buffer, sizeof(buffer));


if (bytesRead < 0) {
}

else if (bytesRead) {
OSStatus err = AudioFileStreamParseBytes(globalMyData->audioFileStream, bytesRead, buffer, 0);
if (err) { PRINTERROR("AudioFileStreamParseBytes"); }
}
}
}


void MyPacketsProc(void * inClientData,
UInt32 inNumberBytes,
UInt32 inNumberPackets,
const void * inInputData,
AudioStreamPacketDescription *inPacketDescriptions)
{
NSLog(@"start MyPacketsProc");
MyData* myData = (MyData*)inClientData;

printf("got data. bytes: %d packets: %d\n", inNumberBytes, inNumberPackets);

for (int i = 0; i < inNumberPackets; ++i) {
SInt64 packetOffset = inPacketDescriptions[i].mStartOffset;
SInt64 packetSize = inPacketDescriptions[i].mDataByteSize;

size_t bufSpaceRemaining = kAQBufSize - myData->bytesFilled;
if (bufSpaceRemaining < packetSize) {
MyEnqueueBuffer(myData);
WaitForFreeBuffer(myData);
}

AudioQueueBufferRef fillBuf = myData->audioQueueBuffer[myData->fillBufferIndex];
memcpy((char*)fillBuf->mAudioData + myData->bytesFilled, (const char*)inInputData + packetOffset, packetSize);
myData->packetDescs[myData->packetsFilled] = inPacketDescriptions[i];
myData->packetDescs[myData->packetsFilled].mStartOffset = myData->bytesFilled;
myData->bytesFilled += packetSize;
myData->packetsFilled += 1;


size_t packetsDescsRemaining = kAQMaxPacketDescs - myData->packetsFilled;
if (packetsDescsRemaining == 0) {
MyEnqueueBuffer(myData);
WaitForFreeBuffer(myData);
}
} 




}

- (IBAction)buttonPlayPressedid)sender
{

label.text = @"Buffering";
[self connectionStart];
}




- (IBAction)buttonSavePressedid)sender
{
NSLog(@"save");

AudioFileClose(myData.audioFile);
AudioQueueDispose(myData.queue, TRUE);

}

bool getFilename(char* buffer,int maxBufferLength)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
NSUserDomainMask, YES); 
NSString* docDir = [paths objectAtIndex:0];
NSString* file = [docDir stringByAppendingString:@"/rec.caf"];
return [file getCString:buffer maxLength:maxBufferLength encoding:NSUTF8StringEncoding];
}

-(void)connectionStart {


@try {

MyData* myData = (MyData*)calloc(1, sizeof(MyData));

globalMyData = myData;

pthread_mutex_init(&myData->mutex, NULL);
pthread_cond_init(&myData->cond, NULL);
pthread_cond_init(&myData->done, NULL);

NSLog(@"Start");


myData->dataFormat.mSampleRate = 16000.0f;
myData->dataFormat.mFormatID = kAudioFormatLinearPCM;
myData->dataFormat.mFramesPerPacket = 1;
myData->dataFormat.mChannelsPerFrame = 1;
myData->dataFormat.mBytesPerFrame = 2;
myData->dataFormat.mBytesPerPacket = 2;
myData->dataFormat.mBitsPerChannel = 16;
myData->dataFormat.mReserved = 0;
myData->dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;


int i, bufferByteSize;
UInt32 size;



AudioQueueNewInput(
&myData->dataFormat,
MyAudioQueueOutputCallback,
&myData,
NULL /* run loop */, kCFRunLoopCommonModes /* run loop mode */,
0 /* flags */, &myData->queue);



size = sizeof(&myData->dataFormat);
AudioQueueGetProperty(&myData->queue, kAudioQueueProperty_StreamDescription, 
&myData->dataFormat, &size);




CFURLRef fileURL;
char path[256];
memset(path,0,sizeof(path));
getFilename(path,256);

fileURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)path, strlen(path), FALSE);

AudioFileCreateWithURL(fileURL,
kAudioFileCAFType,
&myData->dataFormat,
kAudioFileFlags_EraseFile,
&myData->audioFile);

OSStatus err = AudioFileStreamOpen(myData, MyPropertyListenerProc, MyPacketsProc, 
kAudioFileMP3Type, &myData->audioFileStream);
if (err) { PRINTERROR("AudioFileStreamOpen"); return 1; }

CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};

CFStringRef bodyData = CFSTR(""); // Usually used for POST data
CFStringRef headerFieldName = CFSTR("X-My-Favorite-Field");
CFStringRef headerFieldValue = CFSTR("Dreams");

CFStringRef url = CFSTR(RADIO_LOCATION);
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);

CFHTTPMessageSetBody(myRequest, bodyData);
CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);


CFReadStreamRef stream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);

if (!stream) {
NSLog(@"Creating the stream failed");
return;
}



if (!CFReadStreamSetClient(stream, kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
CFRelease(stream);
NSLog(@"Setting the stream's client failed.");
return;
}

CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

if (!CFReadStreamOpen(stream)) {
CFReadStreamSetClient(stream, 0, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFRelease(stream);
NSLog(@"Opening the stream failed.");
return;
}

}
@catch (NSException *exception) {
NSLog(@"main: Caught %@: %@", [exception name], [exception reason]); 
}
}


- (void)viewDidLoad {
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
[super viewDidLoad];
}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}


- (void)dealloc {
[super dealloc];
}

@end

0 个答案:

没有答案