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

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

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

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

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

-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {

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

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

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

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

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

-(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, я сбросил его в журнал, и он заполняется и пополняется по кругу, поэтому я знаю, что, по крайней мере, этот бит работает.


person DoctorDbx    schedule 14.05.2012    source источник
comment
Опубликуйте свой код управления буфером, поскольку, похоже, это ваша проблема.   -  person hotpaw2    schedule 15.05.2012


Ответы (1)


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

person hotpaw2    schedule 04.06.2012