AVAssetReader для AudioQueueBuffer

В настоящее время я делаю небольшой тестовый проект, чтобы посмотреть, смогу ли я получить образцы из AVAssetReader для воспроизведения с помощью AudioQueue на iOS.

Я прочитал это: ( Воспроизвести сырой несжатый звук с AudioQueue, без звука) и это: ( Как правильно читать декодированные сэмплы PCM на iOS с помощью AVAssetReader - в настоящее время некорректное декодирование),

Которые оба действительно помогли. Перед чтением у меня вообще не было звука. Теперь я получаю звук, но звук воспроизводится супер быстро. Это мой первый опыт в звуковом программировании, поэтому любая помощь очень ценится.

Я инициализирую читателя таким образом:

NSDictionary * outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                         [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                         [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                         [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                         [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,

                                         nil];

        output = [[AVAssetReaderAudioMixOutput alloc] initWithAudioTracks:uasset.tracks audioSettings:outputSettings];
        [reader addOutput:output];
...

И я получаю данные таким образом:

CMSampleBufferRef ref= [output copyNextSampleBuffer];
    // NSLog(@"%@",ref);
    if(ref==NULL)
        return;
    //copy data to file
    //read next one
    AudioBufferList audioBufferList;
    NSMutableData *data = [NSMutableData data];
    CMBlockBufferRef blockBuffer;
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(ref, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
    // NSLog(@"%@",blockBuffer);

    if(blockBuffer==NULL)
    {
        [data release];
        return;
    }
    if(&audioBufferList==NULL)
    {
        [data release];
        return;
    }

    //stash data in same object
    for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
    {
//        NSData* throwData;
        AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
        [self.delegate streamer:self didGetAudioBuffer:audioBuffer];
        /*
        Float32 *frame = (Float32*)audioBuffer.mData;
        throwData = [NSData dataWithBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
        [self.delegate streamer:self didGetAudioBuffer:throwData];
        [data appendBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
         */
    }

что в итоге приводит нас к аудио-очереди, настроенной таким образом:

//Apple's own code for canonical PCM
    audioDesc.mSampleRate       = 44100.0;
    audioDesc.mFormatID         = kAudioFormatLinearPCM;
    audioDesc.mFormatFlags      = kAudioFormatFlagsAudioUnitCanonical;
    audioDesc.mBytesPerPacket   = 2 * sizeof (AudioUnitSampleType);    // 8
    audioDesc.mFramesPerPacket  = 1;
    audioDesc.mBytesPerFrame    = 1 * sizeof (AudioUnitSampleType);    // 8
    audioDesc.mChannelsPerFrame = 2;
    audioDesc.mBitsPerChannel   = 8 * sizeof (AudioUnitSampleType);    // 32


err = AudioQueueNewOutput(&audioDesc, handler_OSStreamingAudio_queueOutput, self, NULL, NULL, 0, &audioQueue);
    if(err){
#pragma warning  handle error
//never errs, am using breakpoint to check
        return;
    }

и мы ставим в очередь таким образом

while (inNumberBytes)
        {
            size_t bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
            if (bufSpaceRemaining < inNumberBytes)
            {
                AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
        fillBuf->mAudioDataByteSize = bytesFilled;
        err = AudioQueueEnqueueBuffer(audioQueue, fillBuf, 0, NULL);
            }


                bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
                size_t copySize;
                if (bufSpaceRemaining < inNumberBytes)
                {
                    copySize = bufSpaceRemaining;
                }
                else
                {
                    copySize = inNumberBytes;
                }

                if (bytesFilled > packetBufferSize)
                {
                    return;
                }

                AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
                memcpy((char*)fillBuf->mAudioData + bytesFilled, (const char*)(inInputData + offset), copySize);


                bytesFilled += copySize;
                packetsFilled = 0;
                inNumberBytes -= copySize;
                offset += copySize;
            }
        }

Я старался быть максимально включенным в код, чтобы всем было легко указать, где я идиот. При этом у меня возникает ощущение, что моя проблема возникает либо в объявлении настроек вывода программы чтения треков, либо в фактическом объявлении AudioQueue (где я описываю очереди, какой тип звука я собираюсь отправить). В том-то и дело, что я не знаю математически, как на самом деле генерировать эти числа (байты на пакет, кадры на пакет, что у вас). Объяснение этого будет с благодарностью, и спасибо за помощь заранее.

2 ответа

Решение

По какой-то причине, хотя каждый пример аудио-очереди с использованием LPCM имел

ASBD.mBitsPerChannel = 8* sizeof (AudioUnitSampleType);

Для меня оказывается, что мне нужно

ASBD.mBitsPerChannel    = 2*bytesPerSample;

для описания:

ASBD.mFormatID          = kAudioFormatLinearPCM;
ASBD.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
ASBD.mBytesPerPacket    = bytesPerSample;
ASBD.mBytesPerFrame     = bytesPerSample;
ASBD.mFramesPerPacket   = 1;
ASBD.mBitsPerChannel    = 2*bytesPerSample;
ASBD.mChannelsPerFrame  = 2;           
ASBD.mSampleRate        = 48000;

Я понятия не имею, почему это работает, что очень беспокоит меня... но, надеюсь, я смогу со временем все это понять.

Если кто-нибудь может объяснить мне, почему это работает, я был бы очень благодарен.

Не знаю, какой это будет ответ, но текста и ссылок для комментария будет слишком много, и, надеюсь, это поможет (возможно, поможет вам найти ответ).

Во-первых, я знаю, что в моем текущем проекте настройка частоты дискретизации повлияет на скорость звука, поэтому вы можете попробовать поиграть с этими настройками. Но 44k - это то, что я вижу в большинстве реализаций по умолчанию, включая пример Apple SpeakHere. Однако я бы потратил некоторое время на сравнение вашего кода с этим примером, потому что есть довольно много различий. как проверка перед постановкой в ​​очередь.

Сначала ознакомьтесь с этой публикацией /questions/39744181/opredelite-kolichestvo-kadrov-v-bazovom-audiobufere-audio/39744202#39744202 ней рассказывается о том, как вам нужно знать формат аудио, в частности, сколько байтов в кадре, и о правильном преобразовании.

тоже удачи. У меня было довольно много вопросов, размещенных здесь, на форумах Apple и на форуме ios (не на официальном). С очень небольшими ответами / помощью. Чтобы добраться туда, где я сейчас нахожусь (аудиозапись и потоковая передача в формате ulaw), мне пришлось открыть билет поддержки Apple Dev. Который до того, как заняться аудио, я никогда не знал, что существует (поддержка разработчиков). Хорошо, что если у вас есть действующий аккаунт разработчика, вы получаете 2 случая бесплатно! CoreAudio это не весело. Документация скудна, и кроме SpeakHere примеров не так много. Одна вещь, которую я обнаружил, заключается в том, что заголовки фреймворка действительно содержат хорошую информацию и эту книгу. К сожалению, я только начал книгу, в противном случае я смогу помочь вам в дальнейшем.

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

использование AQRecorder (пример устройства записи аудио очереди) в целевом классе c

пытаясь использовать AVAssetWriter для аудио ulaw ( 2)

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