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

时间:2011-01-10 11:43:18

标签: objective-c audio buffer nsoperation producer-consumer

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

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

  1. AVAssetReaderOutput一次最多复制8192个字节到CMBlockBuffer
  2. 将这些字节复制到NSData对象
  3. 将此NSData对象附加到更大的NSMutableData对象(最终保存整首歌曲)
  4. 完成后,通过访问NSMutableData对象中的每个数据包来播放歌曲
  5. 我正试图在复制这些字节时播放这首歌。我不确定从同一时间写入和读取文件的好方法是什么。

    我有一个简短的想法:

    1. 创建并填充3个NSData对象,每个长度为8192个字节,作为缓冲区。
    2. 开始玩。当我完成第一个缓冲区的播放后,将新数据加载到第一个缓冲区中。
    3. 当我完成第二个缓冲区的播放后,将新数据加载到第二个缓冲区中。对于第三个
    4. 也是如此
    5. 再次从第一个缓冲区开始播放,填写第三个缓冲区。等等。
    6. 或者,创建一个包含3 * 8192 PCM单元的NSData对象,并以两种不同的线程同时写入和读取它。

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

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

1 个答案:

答案 0 :(得分:1)

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

  • LoadTrackThread启动并开始从AVAssetReader加载数据并将其作为PCM存储在文件中。
  • 一旦有足够的数据加载到我的PCM文件中,LoadPCMThread就会启动,并且实际上会根据需要将该文件加载到我的RemoteIO线程的本地内存中。它是通过将我的RemoteIO线程远程接近样本用完时将这些数据提供给循环缓冲区来实现的。
  • RemoteIO回放回调线程使用循环缓冲帧并将它们提供给RemoteIO接口。当需要开始加载更多样本时,它还会通知LoadPCMThread唤醒。

这应该是关于线程所需的全部内容。您需要在两个线程之间使用某种互斥或信号量,以确保您在同时写入文件时不会尝试读取文件(这是一种糟糕的形式,会导致您崩溃)。我只是让我的两个线程都设置了一个布尔值并暂停一段时间,直到它被取消设置。可能有更复杂的方法,但它适用于我的目的。

希望有所帮助!