为什么在音频队列播放代码中调用CFRunLoopRunInMode()?

时间:2013-01-08 16:14:44

标签: ios playback audioqueueservices cfrunloop

我正在关注iOS“音频队列编程指南 - 播放音频”。在指南的末尾,步骤Start and Run an Audio Queue中有CFRunLoopRunInMode()来电:

do {                                               // 5
    CFRunLoopRunInMode (                           // 6
        kCFRunLoopDefaultMode,                     // 7
        0.25,                                      // 8
        false                                      // 9
    );
} while (aqData.mIsRunning);
//...

关于第6行的文档说: “CFRunLoopRunInMode函数运行包含音频队列线程的运行循环。” 但是,当我的方法返回时,是不是执行了运行循环?上面的代码是在我的应用程序中按下播放按钮时由主线程执行的。

现在我很难理解这些对CFRunLoopRunInMode()的调用有什么好处,因为它们的缺点是我的播放按钮没有正确更新(它看起来整个时间都按下了音频播放)并没有积极的效果,即如果我从代码中删除do-while-loop以及调用CFRunLoopRunInMode()并且直接从此方法返回,则音频也可以很好地播放。 那么这就指出了显而易见的解决方案,只需将这些调用删除,因为这不会产生问题。有人可以解释为什么Apple在使用iOS中的音频队列进行音频播放的官方指南中包含此代码吗?

编辑:

我刚才看到,在Mac OS X中,存在与iOS相同的音频队列API,iOS指南似乎是Mac OS guide的复制粘贴复制。这让我怀疑那些对运行循环的调用仅在Mac OS中需要而在iOS中不再需要,例如因为否则Mac OS应用程序会退出或类似的东西。有人可以验证这个或排除它吗?

3 个答案:

答案 0 :(得分:1)

@bunnyhero是对的,CFRunLoopRunInMode()通常用于命令行示例

https://github.com/abbood/Learning-Core-Audio-Book-Code-Sample/blob/master/CH05_Player/CH05_Player/main.c

只要您的AudioQueueRef未被解除分配,您就不必在IOS中使用CFRunLoopRunInMode() ...

我所做的是为音频队列创建一个单独的类,只要我的类指针和AudioQueueRef被分配,我就可以播放,暂停,恢复,停止等....

答案 1 :(得分:0)

与OP有关AQ阻止UI线程的问题有关,以进一步解放AQ用户免于盲目地复制that CoreAudio AQ example cited

我还要补充一点,该示例将AQ配置为在Listing 3-11 Creating a playback audio queue中的主线程的当前运行循环中运行:

AudioQueueNewOutput (                                // 1
    &aqData.mDataFormat,                             // 2
    HandleOutputBuffer,                              // 3
    &aqData,                                         // 4
    CFRunLoopGetCurrent (),                          // 5
    kCFRunLoopCommonModes,                           // 6
    0,                                               // 7
    &aqData.mQueue                                   // 8
);

,请参见上面的参数值CFRunLoopGetCurrent ()。文字说明

当前运行循环,以及在其上播放音频队列的循环 回调将被调用。

看一下函数原型:

OSStatus AudioQueueNewOutput(
    const AudioStreamBasicDescription *inFormat,   // 2
    AudioQueueOutputCallback inCallbackProc,       // 3
    void *inUserData,                              // 4
    CFRunLoopRef inCallbackRunLoop,                // 5
    CFStringRef inCallbackRunLoopMode,             // 6
    UInt32 inFlags,                                // 7
    AudioQueueRef  _Nullable *outAQ                // 8
);

如果将{5替换为NULL,则AQ将在CoreAudio内部线程中运行,从而对您的应用程序更加有效。

答案 2 :(得分:0)

CFRunLoopRunInMode需要在代码执行结束时(例如,在运行终端应用程序时)使音频队列保持活动状态。 iOS应用程序包含生命周期:要使音频队列保持活动状态,只需声明AudioQueueRef作为成员变量。否则,如果在方法范围内声明它,则在执行该方法后销毁它-因此,它将停止-除非您使用CFRunLoopRunInMode使它保持活动状态。

总而言之,只要您将AudioQueueRef或新的AVAudioEngine的成员变量保存在没有从内存中释放出来的实例化类中,那么CFRunLoopRunInMode就是不需要