ios - 与核心音频线程同步

标签 ios multithreading performance audio core-audio

我正在使用 ioUnit 的渲染回调将音频数据存储到循环缓冲区中:

OSStatus ioUnitRenderCallback(
                          void *inRefCon,
                          AudioUnitRenderActionFlags *ioActionFlags,
                          const AudioTimeStamp *inTimeStamp,
                          UInt32 inBusNumber,
                          UInt32 inNumberFrames,
                          AudioBufferList *ioData)
{
    OSStatus err = noErr;

    AMNAudioController *This = (__bridge AMNAudioController*)inRefCon;

    err = AudioUnitRender(This.encoderMixerNode->unit,
                          ioActionFlags,
                          inTimeStamp,
                          inBusNumber,
                          inNumberFrames,
                          ioData);

    // Copy the audio to the encoder buffer
    TPCircularBufferCopyAudioBufferList(&(This->encoderBuffer), ioData, inTimeStamp, kTPCircularBufferCopyAll, NULL);

    return err;
}

然后我想从循环缓冲区中读取字节,将它们提供给 libLame,然后提供给 libShout。 我已经尝试启动一个线程并使用 NSCondition 使其等待数据可用,但这会导致由于在 Core Audio 回调上使用锁而导致的各种问题。

推荐的方法是什么?

提前致谢。


关于我如何实现 Adam 的回答的更多细节

我最终采纳了 Adam 的建议并像这样实现了它。

制作人

我在 Core Audio Render 回调中使用 TPCircularBufferProduceBytes 将字节添加到循环缓冲区。在我的例子中,我有非交错的音频数据,所以我最终使用了两个循环缓冲区。

消费者

  1. 我使用 pthread_create 产生了一个新线程
  2. 在新线程中创建一个新的 CFTimer 并将其添加到当前 CFRunLoop(0.005 秒的间隔似乎效果很好)
  3. 我告诉当前的 CFRunLoop 运行
  4. 在我的计时器回调中,我对音频进行编码并将其发送到服务器(如果没有缓冲数据则快速返回)
  5. 我还有一个 5MB 的缓冲区大小,这似乎工作正常(2MB 使我超限)。这似乎有点高:/

最佳答案

使用重复计时器(NSTimer 或 CADisplayLink)轮询无锁循环缓冲区或 FIFO。如果缓冲区中没有足够的数据,则跳过工作,然后返回(到运行循环)。这是有效的,因为你知道高精度的采样率,以及你喜欢或需要一次处理多少数据,所以可以将轮询率设置得稍微快一点,为了安全起见,但仍然非常接近与使用条件锁的效率相同。

不建议在实时音频线程回调中使用信号量或锁(或任何其他具有不可预测延迟的东西)。

关于ios - 与核心音频线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21978305/

相关文章:

iphone - 更改 IOS 应用程序上 TabBar 应用程序中的当前屏幕

ios - 使用 MKNetworkKit 时一个 MKNetworkEngine 对象

c# - List<Object> 上的 Parallel.ForEach 线程安全

javascript - jQuery 执行缓慢的常见原因以及如何优化代码?

javascript - 为什么使用 window.variable 访问变量速度较慢?

ios - 更新 UIWebView Cookie 的到期日期

android - 杀死线程

C# 线程任务 - 无法从任务数组中获取返回值

C++:在表达式和函数调用上使用 '.' 运算符

ios - 如何在 Swift 中以编程方式使用主扬声器