AudioConverter неправильное количество пакетов

Я создал класс для преобразования звука из одного формата в другой с учетом ввода и вывода AudioStreamBasicDescription. Когда я конвертирую Linear PCM из микрофона в iLBC, он работает и дает мне 6 пакетов, когда я передаю ему 1024 пакета из функции AudioUnitRender. Затем я отправляю эти 226 байт через UDP в то же приложение, работающее на другом устройстве. Проблема в том, что когда я использую тот же класс для преобразования обратно в Linear PCM для подачи на вход аудиоустройства, функция AudioConverterFillComplexBuffer не дает 1024 пакета, она дает 960... Это означает, что вход аудиоустройства ожидает 4096 байт (2048 x 2 для стерео), но я могу дать только 3190 или около того, поэтому звук действительно хриплый и искаженный...

Если я передам AudioConverter 1024 пакета LinearPCM, конвертирую в iLBC, конвертирую обратно в LinearPCM, я должен снова получить 1024 пакета?

Функция аудио конвертера:

-(void) doConvert {

    // Start converting
    if (converting) return;
    converting = YES;

    while (true) {

        // Get next buffer
        id bfr = [buffers getNextBuffer];
        if (!bfr) {
            converting = NO;
            return;
        }

        // Get info
        NSArray* bfrs = ([bfr isKindOfClass:[NSArray class]] ? bfr : @[bfr]);
        int bfrSize = 0;
        for (NSData* dat in bfrs) bfrSize += dat.length;

        int inputPackets = bfrSize / self.inputFormat.mBytesPerPacket;
        int outputPackets = (inputPackets * self.inputFormat.mFramesPerPacket) / self.outputFormat.mFramesPerPacket;

        // Create output buffer
        AudioBufferList* bufferList = (AudioBufferList*) malloc(sizeof(AudioBufferList) * self.outputFormat.mChannelsPerFrame);
        bufferList -> mNumberBuffers = self.outputFormat.mChannelsPerFrame;
        for (int i = 0 ; i < self.outputFormat.mChannelsPerFrame ; i++) {
            bufferList -> mBuffers[i].mNumberChannels = 1;
            bufferList -> mBuffers[i].mDataByteSize = 4*1024;
            bufferList -> mBuffers[i].mData = malloc(bufferList -> mBuffers[i].mDataByteSize);
        }

        // Create input buffer
        AudioBufferList* inputBufferList = (AudioBufferList*) malloc(sizeof(AudioBufferList) * bfrs.count);
        inputBufferList -> mNumberBuffers = bfrs.count;
        for (int i = 0 ; i < bfrs.count ; i++) {
            inputBufferList -> mBuffers[i].mNumberChannels = 1;
            inputBufferList -> mBuffers[i].mDataByteSize = [[bfrs objectAtIndex:i] length];
            inputBufferList -> mBuffers[i].mData = (void*) [[bfrs objectAtIndex:i] bytes];
        }

        // Create sound data payload
        struct SoundDataPayload payload;
        payload.data = inputBufferList;
        payload.numPackets = inputPackets;
        payload.packetDescriptions = NULL;
        payload.used = NO;

        // Convert data
        UInt32 numPackets = outputPackets;
        OSStatus err = AudioConverterFillComplexBuffer(converter, acvConverterComplexInput, &payload, &numPackets, bufferList, NULL);
        if (err)
            continue;

        // Check how to output
        if (bufferList -> mNumberBuffers > 1) {

            // Output as array
            NSMutableArray* array = [NSMutableArray arrayWithCapacity:bufferList -> mNumberBuffers];
            for (int i = 0 ; i < bufferList -> mNumberBuffers ; i++)
                [array addObject:[NSData dataWithBytes:bufferList -> mBuffers[i].mData length:bufferList -> mBuffers[i].mDataByteSize]];

            // Save
            [convertedBuffers addBuffer:array];

        } else {

            // Output as data
            NSData* newData = [NSData dataWithBytes:bufferList -> mBuffers[0].mData length:bufferList -> mBuffers[0].mDataByteSize];

            // Save
            [convertedBuffers addBuffer:newData];

        }

        // Free memory
        for (int i = 0 ; i < bufferList -> mNumberBuffers ; i++)
            free(bufferList -> mBuffers[i].mData);

        free(inputBufferList);
        free(bufferList);

        // Tell delegate
        if (self.convertHandler)
            //dispatch_async(dispatch_get_main_queue(), self.convertHandler);
            self.convertHandler();

    }

}

Форматы при преобразовании в iLBC:

// Get input format from mic
UInt32 size = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription inputDesc;
AudioUnitGetProperty(self.ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &inputDesc, &size);

// Set output stream description
size = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription outputDescription;
memset(&outputDescription, 0, size);
outputDescription.mFormatID         = kAudioFormatiLBC;
OSStatus err = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputDescription);

Форматы при конвертации из iLBC:

// Set input stream description
size = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription inputDescription;
memset(&inputDescription, 0, size);
inputDescription.mFormatID        = kAudioFormatiLBC;
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &inputDescription);

// Set output stream description
UInt32 size = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription outputDesc;
AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outputDesc, &size);

person jjv360    schedule 05.12.2012    source источник
comment
Кстати, этот код работает в собственной очереди отправки...   -  person jjv360    schedule 05.12.2012


Ответы (1)


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

AudioConverter может буферизовать сэмплы и изменять размеры пакетов в зависимости от формата сжатия.

person hotpaw2    schedule 05.12.2012
comment
Хорошо... И как мне это сделать? Я получаю кучу NSDatas (или NSArrays, если 2 канала) от своего преобразователя, как мне сделать промежуточный буфер? - person jjv360; 06.12.2012
comment
K Я добавил поле preferredOutputBufferSize в свой конвертер, который теперь отправляет буферы любого заданного размера, и теперь он работает, спасибо... - person jjv360; 06.12.2012