objective-c - 使用 NSData 解决生产者-消费者问题(用于音频流)

标签 objective-c audio buffer nsoperation producer-consumer

我正在使用 AVAssetReader 将 PCM 数据从 iPod 轨道复制到缓冲区,然后使用 RemoteIO 音频单元播放。我正在尝试创建一个单独的线程来加载声音数据,这样我就可以在加载缓冲区时访问和播放缓冲区中的数据。

我目前有一个大型 NSMutableData 对象,它最终保存了整首歌曲的数据。目前,我使用 NSOperation 在单独的线程中加载音频数据,如下所示:

  • AVAssetReaderOutput 一次最多复制 8192 个字节到 CMBlockBuffer
  • 将这些字节复制到 NSData 对象
  • 将此 NSData 对象附加到更大的 NSMutableData 对象(最终保存整首歌曲)
  • 完成后,通过访问 NSMutableData 对象
  • 中的每个数据包来播放歌曲

    我试图在复制这些字节的同时播放歌曲。我不确定同时写入和读取文件的好方法是什么。

    我有一个简短的想法:
  • 创建并填充 3 个 NSData 对象,每个对象的长度为 8192 字节,作为缓冲区。
  • 开始播放。当我播放完第一个缓冲区后,将新数据加载到第一个缓冲区中。
  • 当我播放完第二个缓冲区后,将新数据加载到第二个缓冲区中。第三个
  • 相同
  • 再次从第一个缓冲区开始播放,填充第三个。等等。

  • 或者,创建一个包含 3 * 8192 个 PCM 单元的 NSData 对象,并以某种方式使用两个不同的线程同时对其进行写入和读取。

    我的代码现在在两个不同的线程上工作。我将数据附加到数组,直到我按下播放,此时它停止(可能是因为线程被阻塞,但我现在不知道)并播放直到它到达我加载的任何内容的末尾并导致 EXC_BAD_ACCESS 异常。

    简而言之,我想找到正确的方式在 PCM 数据被复制时播放,比如一次复制 8192 个字节。我可能不得不使用另一个线程(我现在正在使用 NSOperation)这样做,但不清楚如何同时写入和读取缓冲区,最好使用一些更高级别的 Objective-C 方法。

    最佳答案

    我正在做这件事。您肯定需要在不同的线程上播放音频(我正在使用 RemoteIO 执行此操作)。您还需要使用循环缓冲区。如果您不熟悉此数据结构,您可能需要查找它,因为您将在此类操作中大量使用它。我的一般设置如下:

  • LoadTrackThread 启动并开始从 AVAssetReader 加载数据并将其作为 PCM 存储在文件中。
  • 一旦有足够的数据加载到我的 PCM 文件中,LoadPCMThread 就会启动,并且本质上将该文件加载到本地内存中以供我的 RemoteIO 线程按需使用。每当我的 RemoteIO 线程甚至远程接近用完样本时,它都会将此数据输入循环缓冲区来实现这一点。
  • RemoteIO 播放回调线程消耗循环缓冲区帧并将它们提供给 RemoteIO 接口(interface)。它还通知 LoadPCMThread 在需要开始加载更多样本时唤醒。

  • 就线程而言,这应该是您所需要的一切。您将需要在两个线程之间使用某种互斥锁或信号量,以确保在同时写入文件时不会尝试读取文件(这是错误的形式,会导致您崩溃)。我只是让我的两个线程都设置一个 bool 值并休眠一段时间,直到它被取消设置。可能有一种更复杂的方法可以做到这一点,但它适用于我的目的。

    希望有帮助!

    关于objective-c - 使用 NSData 解决生产者-消费者问题(用于音频流),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4646442/

    相关文章:

    ios - iOS7 和 iOS8 返回的 UIScreen 边界不同

    audio - 可以使用Tensorflow学习和处理音频吗?

    java - 手动更改扬声器位置

    c++ - OpenGL:我可以将 glBindBuffer 与 glBindBufferARB 混合使用吗?

    c++ uint8 缓冲区数组

    php - 为什么这个 header 位置重定向在内容已经被回显后起作用?

    ios - 如何使用自动布局获取 iOS tableview 最后正确的内容大小

    ios - 使用 if 语句的结果作为变量

    ios - iOS检测短信发送失败

    c++ - 在 C++ 中处理音频缓冲区时,如何执行从 float -> double -> float 的转换