Обратный вызов AVCaptureOutput в Audio Unit через TPCircularBuffer

Я создаю AUGraph и пытаюсь получить звук с устройства ввода с помощью метода делегата AVCaptureAudioDataOutput.

Использование AVCaptureSession является следствием проблемы, описанной здесь< /а>. Мне удалось создать воспроизведение звука с помощью этого метода через CARingbuffer, как описано в книге Learning Core Audio. Но получение данных из CARingbuffer подразумевает предоставление допустимого шага расчета, и когда я останавливаю AVCaptureSession, времена расчета из AVCaptureOutput и обратного вызова ввода устройства больше не синхронизируются. Итак, сейчас я пытаюсь использовать TPCircularBuffer, который, судя по тому, что я читал, кажется превосходным. Но даже с некоторыми примерами, которые я нашел, я не могу получить от него звук (или только трещины).

Мой график выглядит так:

AVCaptureSession -> callback -> AUConverter -> ... -> HALOutput

А вот код моего метода AVCaptureOutput

- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{

CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
const AudioStreamBasicDescription *sampleBufferASBD = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription);

if (kAudioFormatLinearPCM != sampleBufferASBD->mFormatID) {

    NSLog(@"Bad format or bogus ASBD!");
    return;

}

if ((sampleBufferASBD->mChannelsPerFrame != _audioStreamDescription.mChannelsPerFrame) || (sampleBufferASBD->mSampleRate != _audioStreamDescription.mSampleRate)) {

    _audioStreamDescription = *sampleBufferASBD;
    NSLog(@"sample input format changed");

}




CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
                                                        NULL,
                                                        _currentInputAudioBufferList,
                                                        CAAudioBufferList::CalculateByteSize(_audioStreamDescription.mChannelsPerFrame),
                                                        kCFAllocatorSystemDefault,
                                                        kCFAllocatorSystemDefault,
                                                        kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
                                                        &_blockBufferOut);


TPCircularBufferProduceBytes(&_circularBuffer, _currentInputAudioBufferList->mBuffers[0].mData, _currentInputAudioBufferList->mBuffers[0].mDataByteSize);

И обратный вызов рендера:

OSStatus PushCurrentInputBufferIntoAudioUnit(void inRefCon,
                                             AudioUnitRenderActionFlags *   ioActionFlags,
                                             const AudioTimeStamp *         inTimeStamp,
                                             UInt32                         inBusNumber,
                                             UInt32                         inNumberFrames,
                                             AudioBufferList *              ioData)
{

ozAVHardwareInput *hardWareInput = (ozAVHardwareInput *)inRefCon;
TPCircularBuffer circularBuffer = [hardWareInput circularBuffer];

Float32 *targetBuffer = (Float32 *)ioData->mBuffers[0].mData;

int32_t availableBytes;
TPCircularBufferTail(&circularBuffer, &availableBytes);
UInt32 dataSize = ioData->mBuffers[0].mDataByteSize;

if (availableBytes > ozAudioDataSizeForSeconds(3.)) {

    // There is too much audio data to play -> clear buffer & mute output
    TPCircularBufferClear(&circularBuffer);

    for(UInt32 i = 0; i < ioData->mNumberBuffers; i++)
        memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);

} else if (availableBytes > ozAudioDataSizeForSeconds(0.5)) {

    // SHOULD PLAY
    Float32 *cbuffer = (Float32 *)TPCircularBufferTail(&circularBuffer, &availableBytes);
    int32_t min = MIN(dataSize, availableBytes);

    memcpy(targetBuffer, cbuffer, min);
    TPCircularBufferConsume(&circularBuffer, min);
    ioData->mBuffers[0].mDataByteSize = min;

} else {

    // No data to play -> mute output
    for(UInt32 i = 0; i < ioData->mNumberBuffers; i++)
        memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
}

return noErr;

}

В TPCIrcularBuffer передается AudioBufferList, но ничего не выводится, а иногда только трещины.

Что я делаю неправильно ?


person Benoît Lahoz    schedule 01.06.2014    source источник
comment
Если вы не женаты на TPCircularBuffer, другой альтернативой является мой RingBuffer класс: github.com /sbooth/SFBAudioEngine/blob/master/RingBuffer.h   -  person sbooth    schedule 02.06.2014
comment
Спасибо. Я попробую!   -  person Benoît Lahoz    schedule 02.06.2014
comment
Большое спасибо @sbooth, он работает как шарм и так прост в использовании!   -  person Benoît Lahoz    schedule 03.06.2014


Ответы (1)


Обратный вызов визуализации аудиоустройства должен всегда возвращать inNumberFrames образцов. Проверьте, сколько данных возвращает ваш обратный вызов.

person hotpaw2    schedule 08.06.2014
comment
Я, наконец, использовал кольцевой буфер @sbooth, и он работает хорошо, но я попытаюсь изменить значение, которое я передаю в качестве числовых кадров, в TPCircularBuffer для тестирования. - person Benoît Lahoz; 11.06.2014