Objective-C - передача потоковых данных в аудио-очередь

В настоящее время я разрабатываю приложение для iOS, которое считывает аудиоданные IMA-ADPCM через TCP-сокет, преобразует их в PCM и затем воспроизводит поток. На этом этапе я закончил класс, который извлекает (или я должен сказать реагирует на нажатия) данные из потока и декодирует их в PCM. Я также настроил класс Audio Queue, чтобы он воспроизводил тестовый сигнал. Где мне нужна помощь, это лучший способ передать данные в аудио-очередь.

Аудиоданные поступают из декодера ADPCM в виде 16-битного LPCM с тактовой частотой 8 кГц и частотой 640 байт. (он создается как 160 байтов данных ADPCM, но распаковывается до 640). Он входит в функцию как массив uint_8t и передает объект NSData. Поток является потоком "push", поэтому каждый раз при отправке аудио он создает / очищает объект.

-(NSData*)convertADPCM:(uint8_t[]) adpcmdata {

Конечно, обратный вызов Audio Queue - это функция извлечения, которая ищет данные на каждом проходе цикла выполнения, на каждом проходе:

-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {

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

Я установил круговой буфер, равный 0,5 секунды, в uint16_t[] ~, но я думаю, что измотал свой мозг и не смог придумать аккуратный способ толкать и извлекать из буфера, так что в итоге я получил треск с треском,

Я завершил проект в основном на Android, но обнаружил, что AudioTrack - это совсем не то, что Core-Audio Queues.

На этом этапе я также скажу, что я взял копию Learning Core Audio от Adamson и Avila и нашел это отличным ресурсом для тех, кто хочет демистифицировать ядро ​​аудио.

ОБНОВЛЕНИЕ: Вот код управления буфером:

-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {

    int frame = 0;
    double frameCount = bufferSize / self.streamFormat.mBytesPerFrame; 
    // buffersize = framecount = 8000 / 2 = 4000
    //    

    // incoming buffer uint16_t[] convAudio holds 64400 bytes (big I know - 100 x 644 bytes)
    // playedHead is set by the function to say where in the buffer the
    // next starting point should be

    if (playHead > 99) {
        playHead = 0;
    }

    // Playstep factors playhead to get starting position   
    int playStep = playHead * 644;

    // filling the buffer
    for (frame = 0; frame < frameCount; ++frame) 
        // framecount = 4000
       {
        // pointer to buffer
        SInt16 *data = (SInt16*)buffer->mAudioData;
        // load data from uint16_t[] convAudio array into frame
        (data)[frame] = convAudio[(frame + playStep)];
    }

    // set buffersize
    buffer->mAudioDataByteSize = bufferSize;

    // return no Error - Osstatus will return an error otherwise if there is one. (I think)
    return noErr;
}

Как я уже сказал, мой мозг был нечетким, когда я написал это, и, возможно, есть что-то явно очевидное, что мне не хватает.

Выше код вызывается обратным вызовом:

static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) 
{
    soundHandler *sHandler = (__bridge soundHandler*)inUserData;

    CheckError([sHandler fillBuffer: inCompleteAQBuffer],
               "can't refill buffer",
               "buffer refilled");
    CheckError(AudioQueueEnqueueBuffer(inAQ,
                                       inCompleteAQBuffer,
                                       0,
                                       NULL),
               "Couldn't enqueue buffer (refill)",
               "buffer enqued (refill)");

}

Что касается массива convAudio, я поместил его в журнал, и он заполняется и пополняется по кругу, поэтому я знаю, что по крайней мере этот бит работает.

1 ответ

Трудная часть в управлении ставками, и что делать, если они не совпадают. Сначала попробуйте использовать огромный круговой буфер (много-много секунд) и в основном заполнить его, прежде чем запускать аудио-очередь, чтобы извлечь из нее. Затем следите за уровнем буфера, чтобы увидеть его большую проблему соответствия скорости.

Другие вопросы по тегам