如何正确使用 iOS AudioUnit 渲染回调

Posted

技术标签:

【中文标题】如何正确使用 iOS AudioUnit 渲染回调【英文标题】:How to use iOS AudioUnit render callback correctly 【发布时间】:2011-11-24 16:18:46 【问题描述】:

我正在编写一个 ios 应用程序,它将播放音频指令作为其功能之一。

应用程序每次想要播放音频时,它都会从非标准文件中读取,并将生成的音频 PCM 数据放入内存中的缓冲区中。

即使我有 PCM 数据的缓冲区,我也无法让应用程序实际播放声音。在搜索了 iOS 文档之后,我开始实现一个 AudioUnit。这个 AudioUnit 的问题是使用了渲染回调(据我所知,这是输出声音的唯一方法)。来自Apple's developer documentation:

… 渲染回调有严格的性能要求,你必须 坚持。渲染回调位于实时优先级线程上 随后的渲染调用异步到达。你所做的工作 在渲染回调的主体中发生在这个时间受限的 环境。如果您的回调仍在生成示例帧 在下一次渲染调用时响应上一次渲染调用 到达时,您会听到声音的间隙。出于这个原因,你不能采取 锁定、分配内存、访问文件系统或网络 连接,或以其他方式在主体中执行耗时的任务 渲染回调函数

如果我不能在渲染回调方法中使用锁,我就不能在写入缓冲区时读取缓冲区。没有机会读取文件并写入缓冲区,因为渲染回调将不断访问它。

唯一的例子I found实际上在render方法内部生成了PCM数据,我做不到。

这是使用 AudioUnits 的唯一方法(带有异步渲染回调)吗?

是否有替代从内存中播放 PCM 数据的方法?

【问题讨论】:

写得很好的问题。非常感谢您帮助我理解! 【参考方案1】:

使用 RemoteIO 音频单元可能需要在音频单元回调之外有一个单独的数据队列(fifo 或循环缓冲区),它可以在音频单元渲染回调之前从文件读取中预缓冲足够的音频数据,以遇到更糟糕的情况延迟。那么渲染回调只需要快速复制音频数据,然后更新一个表示音频数据被消费的只写标志。

iOS 内置的另一种方法是使用音频队列 API,它会为您进行预缓冲。它允许您的应用提前在主运行循环中填充大量较大的音频缓冲区。您仍然必须预先缓冲足够的数据以允许最大文件、网络、锁或其他延迟。

另一种策略是,如果文件或网络读取跟不上,则使用替代音频数据来提供实时渲染回调,例如快速创建一个逐渐变细的音频缓冲区(然后在真实时取消逐渐变细)数据再次开始到达)。

【讨论】:

以上是关于如何正确使用 iOS AudioUnit 渲染回调的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AudioUnit (iOS) 播放信号?

AudioUnit Render 回调中的 Objective-C/Swift 用法

OSX AudioUnit SMP

AVAudioUnit(渲染)回调

AudioUnit播放PCM问题

将 AudioUnit 回调与 NSOutputStream 同步