为什么我的AudioQueueOutputCallback不能被调用?
我正在使用audio队列服务API播放通过iPhone上的TCP套接字连接从服务器stream式传输的audio。 我可以播放从套接字连接填充的缓冲区,我似乎无法使我的AudioQueue调用我的AudioQueueOutputCallback函数,我不知道。
高层次的devise
- 数据从套接字连接传递给播放器,并立即写入内存中的循环缓冲区。
- 随着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);