为什么我的AudioQueueOutputCallback不能被调用?

我正在使用audio队列服务API播放通过iPhone上的TCP套接字连接从服务器stream式传输的audio。 我可以播放从套接字连接填充的缓冲区,我似乎无法使我的AudioQueue调用我的AudioQueueOutputCallback函数,我不知道。

高层次的devise

  1. 数据从套接字连接传递给播放器,并立即写入内存中的循环缓冲区。
  2. 随着AudioQueueBuffers变得可用,将数据从循环缓冲区复制到可用的AudioQueueBuffer中,并立即重新排队。 (或者,如果我的callback发生了)

怎么了

缓冲区全部被填满并成功排队,我清楚地听到了audiostream。 为了进行testing,我使用了大量的缓冲区(15),并且所有的缓冲区都可以无缝地播放,但是AudioQueueOutputCallback从来没有被调用过,所以我从来不会重新排列任何这些缓冲区,尽pipe事实似乎一切正常。 如果我不等我的callback,假设它永远不会被调用,而是根据写入的数据驱动缓冲区的排队,我可以无限期地播放audiostream,重用和重新排列缓冲区,就好像它们一样已经明确地回到了我的callback。 事实是:我可以在需要时重复使用缓冲区的情况下完美地播放stream,这使我最困惑。 为什么不调用callback?

可能有关的代码

stream的格式是16位线性PCM,8kHz,单声道:

_streamDescription.mSampleRate = 8000.0f; _streamDescription.mFormatID = kAudioFormatLinearPCM; _streamDescription.mBytesPerPacket = 2; _streamDescription.mFramesPerPacket = 1; _streamDescription.mBytesPerFrame = sizeof(AudioSampleType); _streamDescription.mChannelsPerFrame = 1; _streamDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType) _streamDescription.mReserved = 0; _streamDescription.mFormatFlags = (kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked); 

我的原型和callback的实现如下。 没有什么特别的,几乎和我目前看到的每个例子都一样:

 // Prototype, declared above the class's @implementation void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer); // Definition at the bottom of the file. void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) { printf("callback\n"); [(MyAudioPlayer *)inUserData audioQueue:inAudioQueue didAquireBufferForReuse:inAudioQueueBuffer]; } 

我创build了这样的AudioQueue:

 OSStatus status = 0; status = AudioQueueNewOutput(&_streamDescription, AQBufferCallback, // <-- Doesn't work... self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_audioQueue); if (status) { // This is not called... NSLog(@"Error creating new audio output queue: %@", [MyAudioPlayer stringForOSStatus:status]); return; } 

我排队这样的缓冲区。 此时,已知本地缓冲区包含正确的复制数据量:

 memcpy(aqBuffer->mAudioData, localBuffer, kAQBufferSize); aqBuffer->mAudioDataByteSize = kAQBufferSize; OSStatus status = AudioQueueEnqueueBuffer(_audioQueue, aqBuffer, 0, NULL); if (status) { // This is also not called. NSLog(@"Error enqueueing buffer %@", [MyAudioPlayer stringForOSStatus:status]); } 

请救我

这是执行在主线程或后台线程? 如果CFRunLoopGetCurrent()返回一个可能消失的线程的运行循环(线程池等),或者是一个不关心kCFRunLoopCommonModes的运行循环,那么可能不太好。

尝试将CFRunLoopGetCurrent()更改为CFRunLoopGetMain()或者确保AudioQueueNewOutput()CFRunLoopGetCurrent()在主线程或已控制的线程上执行,并具有适当的运行循环。

尝试改变self (void*)self 。 喜欢这个:

status = AudioQueueNewOutput(&_streamDescription, AQBufferCallback, (void*)self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_audioQueue);