我正在使用音频队列服务 API http://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/uid/TP40005117-CH1-SW1在 iPhone 上通过 TCP 套接字连接播放从服务器流式传输的音频。我可以播放从套接字连接填充的缓冲区,我似乎无法让我的 AudioQueue 调用我的 AudioQueueOutputCallback 函数,而且我没有想法。
高层次设计
- 数据从套接字连接传递到播放器,并写入
立即进入内存中的循环缓冲区。
- 当 AudioQueueBuffers 变得可用时,数据从循环缓冲区复制到
可用的 AudioQueueBuffer,立即重新排队。 (或者,如果我的回调发生的话)
会发生什么
缓冲区已全部填充并成功排队,我可以清楚地听到音频流。为了进行测试,我使用了大量缓冲区 (15),并且所有缓冲区都无缝播放,但从未调用 AudioQueueOutputCallback,因此我从未对任何缓冲区重新排队,尽管事实上一切似乎都运行良好。如果我不等待回调,假设它永远不会被调用,而是根据写入的数据驱动缓冲区排队,我可以无限期地播放音频流,重用和重新排队缓冲区,就像它们一样已通过回调明确返回给我。事实是:我可以完美地播放流,同时根据需要重用缓冲区,这让我最困惑。为什么回调没有被调用?
可能相关的代码
流的格式为 16 位线性 PCM、8 kHz、单声道:
_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);
我的回调的原型和实现如下。没什么特别的,并且与我迄今为止看到的每个示例几乎相同:
// 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];
}
我像这样创建 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]);
}
请救救我。