Решение проблемы производителя-потребителя с NSData (для потокового аудио) - PullRequest
1 голос
/ 10 января 2011

Я использую AVAssetReader для копирования данных PCM с дорожки iPod в буфер, который затем воспроизводится с помощью аудиоустройства RemoteIO.Я пытаюсь создать отдельный поток для загрузки звуковых данных, чтобы я мог получить доступ и воспроизводить данные из буфера во время его загрузки.

В настоящее время у меня есть большой объект NSMutableData, который в конечном итоге содержит всю песнюданные.В настоящее время я загружаю аудиоданные в отдельном потоке, используя NSOperation следующим образом:

  1. AVAssetReaderOutput копирует, самое большее, 8192 байта за раз в CMBlockBuffer
  2. Скопируйте эти байты в NSDataobject
  3. Добавить этот объект NSData к большему объекту NSMutableData (который в конечном итоге содержит всю песню)
  4. Когда закончите, воспроизведите песню, получив доступ к каждому пакету в объекте NSMutableData

Я пытаюсь воспроизвести песню, копируя эти байты.Я не уверен, что хороший способ записи и чтения из файла того же времени.

Короткая идея, которая у меня была:

  1. Создание и заполнение 3 объектов NSData, каждыйДлина 8192 байта в качестве буферов.
  2. Начните играть.Когда я закончу воспроизведение первого буфера, загрузите новые данные в первый буфер.
  3. Когда я закончу воспроизведение второго буфера, загрузите новые данные во второй.То же самое для третьего
  4. Начните воспроизведение с первого буфера снова, заполните третий.И т. Д.

Или создайте один объект NSData, содержащий 3 * 8192 единицы PCM, и каким-либо образом выполняйте запись и чтение из него одновременно с двумя различными потоками.

Мой код работает на двух разных потоках прямо сейчас.Я добавляю данные в массив до тех пор, пока не нажму кнопку воспроизведения, после чего он останавливается (возможно, потому что поток заблокирован, но я не знаю прямо сейчас) и воспроизводится, пока не достигнет конца того, что я загрузил, и не вызовет исключение EXC_BAD_ACCESS.

Короче говоря, я хочу найти правильный способ воспроизведения данных PCM, когда они копируются, скажем, 8192 байта за раз.Вероятно, мне придется сделать это с другим потоком (я сейчас использую NSOperation), но неясно, как писать и читать из буфера одновременно, предпочтительно с использованием методов Objective-C более высокого уровня.

1 Ответ

1 голос
/ 07 июня 2011

Я делаю именно эту вещь.Вам определенно нужно будет воспроизводить звук в другом потоке (я делаю это с RemoteIO).Вам также нужно будет использовать кольцевой буфер.Возможно, вы захотите посмотреть на эту структуру данных, если вы не знакомы с ней, поскольку вы будете часто использовать ее для операций такого типа.Моя общая настройка выглядит следующим образом:

  • LoadTrackThread запускается и начинает загрузку данных из AVAssetReader и сохраняет их в файле в формате PCM.
  • LoadPCMThread запускается, как только в мой файл загружается достаточно данныхФайл PCM и по существу загружает этот файл в локальную память для моего потока RemoteIO по требованию.Это делается путем подачи этих данных в кольцевой буфер, когда мой поток RemoteIO даже удаленно приближается к завершению выборок.
  • Поток обратного вызова воспроизведения RemoteIO потребляет циклические буферные кадры и передает их в интерфейс RemoteIO.Он также информирует LoadPCMThread о том, что он должен проснуться, когда ему нужно начать загрузку большего количества сэмплов.

Это должно быть примерно все, что вам нужно, что касается потоков.Вам нужно будет иметь какой-то мьютекс или семафор между двумя потоками, чтобы гарантировать, что вы не пытаетесь прочитать ваш файл, когда вы записываете в него в одно и то же время (это дурной тон и приведет к сбою).Я просто установил в обоих потоках логическое значение и поспал некоторое время, пока он не отключился.Вероятно, есть более изощренный способ сделать это, но он работает для моих целей.

Надеюсь, это поможет!

...