iphone - 为什么我的 AudioQueueOutputCallback 不会被调用?

标签 iphone ios core-audio audioqueueservices

我正在使用 Audio Queue Services API在 iPhone 上通过 TCP 套接字连接播放从服务器流式传输的音频。我可以播放从套接字连接填充的缓冲区,我似乎无法让我的 AudioQueue 调用我的 AudioQueueOutputCallback 函数,而且我没有想法。

高层设计

  1. 数据从套接字连接传递给播放器,并写入 立即进入内存中的循环缓冲区。
  2. 当 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)和实现如下。没什么特别的,而且与我目前看到的每个示例几乎相同:

// 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]);
}

请救救我

最佳答案

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

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

关于iphone - 为什么我的 AudioQueueOutputCallback 不会被调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7575670/

相关文章:

iphone - 我可以在 TabBarController 上添加超过 8 个选项卡吗?

ios - 带有 "Bearer Token"的 Twitter 仅应用程序身份验证

ios - Xcode 8,由于前导和尾随约束,未显示 TableView

ios - 如何使用 NSCache 并从 Url 下载图像并在 CollectionViewCell 中显示图像?

ios - 如何将应用程序中的音乐编程为在特定时间播放?

iPhone 将我网站上的日期转换为电话号码——我该如何防止这种情况发生?

iphone - 如何设置一个 NSPredicate 来使用 NSFetchedResultsController 过滤指定组中的项目

iphone - UIImagePNGRepresentation() 返回不同的字节

c++ - 开源声音引擎

ios - Novocaine - 如何循环播放文件? (iOS)