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

5
我正在编写一个iOS应用程序,其中一个功能是播放音频指令。
每次应用程序想要播放音频时,它会从非标准文件中读取,并将该音频的PCM数据放入内存缓冲区中。
尽管我有了包含PCM数据的缓冲区,但我在让应用程序实际播放声音方面遇到了麻烦。在搜索iOS文档后,我开始实现AudioUnit。这个AudioUnit的问题是使用渲染回调(据我所知,这是输出声音的唯一方法)。来自Apple开发者文档
“…渲染回调具有严格的性能要求,您必须遵守。渲染回调位于实时优先级线程上,在此线程上,后续渲染调用以异步方式到达。您在渲染回调体中执行的工作都在这个受时间限制的环境中进行。如果您的回调在响应上一个渲染调用产生样本帧时仍在产生样本帧,则声音会出现间隙。因此,您不能在渲染回调函数的主体中锁定、分配内存、访问文件系统或网络连接,或以其他方式执行耗时任务。”
如果我不能在渲染回调方法中使用锁,则无法在读取缓冲区时写入它。由于渲染回调将不断访问它,因此没有机会读取文件并写入缓冲区。
我找到的唯一示例实际上是在渲染方法内生成PCM数据,而我无法这样做。
这是使用AudioUnits(具有异步渲染回调)的唯一方法吗?
有没有从内存中播放PCM数据的替代方案?

问题写得很好。非常感谢您帮助我理解! - JohnK
1个回答

4
使用RemoteIO音频单元可能需要在音频单元回调之外拥有一个独立的数据队列(fifo或循环缓冲区),该队列可以从文件读取中预先缓存足够的音频数据,以满足更差的情况下的延迟。然后,渲染回调只需要对音频数据进行快速复制,然后更新一个仅写标志,指示已消耗音频数据。
另一种内置于iOS中的选择是使用Audio Queue API,它会为您执行预缓冲。它允许您的应用程序提前在主运行循环中填充多个较大的音频缓冲区。您仍然需要预先缓冲足够的数据以允许最大的文件、网络、锁定或其他延迟。
另一种策略是在文件或网络读取无法跟上的情况下提供替代音频数据以供实时渲染回调使用,例如快速创建一个逐渐变静的音频缓冲区(然后在真实数据再次到达时取消变静)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接