2016-01-20 8 views
2

Я пишу приложение voip, которое использует библиотеку «новокаин» для записи и воспроизведения звука. Я установил частоту дискретизации 8 кГц. Эта частота выборки установлена ​​в новокаине в AudioStreamBasicDescription аудиоустройства и в качестве свойства аудиосообщения kAudioSessionProperty_PreferredHardwareSampleRate. Я понимаю, что установка предпочтительной частоты дискретизации аппаратного обеспечения не гарантирует, что фактическая частота дискретизации будет изменена, но она работает для всех устройств, кроме iPhone6 ​​и iPhone6s + (когда маршрут изменен на динамик). С iPhone6s (+) и динамиком я получаю звук 48 кГц от микрофона. Поэтому мне нужно каким-то образом преобразовать этот звук 48 кГц в 8 кГц. В документации я обнаружил, что AudioConverterRef можно использовать в этом случае, но у меня есть проблемы с его использованием.Преобразование частоты дискретизации AudioConverterRef (iOS)

Я использую AudioConverterFillComplexBuffer для преобразования частоты дискретизации, но он всегда возвращает -50 OSStatus (один или несколько параметров, переданных функции, недействительны). Вот как я использую аудиоконвертер:

// Setup AudioStreamBasicDescription for input 
inputFormat.mSampleRate = 48000.0; 
inputFormat.mFormatID = kAudioFormatLinearPCM; 
inputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; 
inputFormat.mChannelsPerFrame = 1; 
inputFormat.mBitsPerChannel = 8 * sizeof(float); 
inputFormat.mFramesPerPacket = 1; 
inputFormat.mBytesPerFrame = sizeof(float) * inputFormat.mChannelsPerFrame; 
inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame * inputFormat.mFramesPerPacket; 

// Setup AudioStreamBasicDescription for output 
outputFormat.mSampleRate = 8000.0; 
outputFormat.mFormatID = kAudioFormatLinearPCM; 
outputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; 
outputFormat.mChannelsPerFrame = 1; 
outputFormat.mBitsPerChannel = 8 * sizeof(float); 
outputFormat.mFramesPerPacket = 1; 
outputFormat.mBytesPerFrame = sizeof(float) * outputFormat.mChannelsPerFrame; 
outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame * outputFormat.mFramesPerPacket; 


// Create new instance of audio converter 
AudioConverterNew(&inputFormat, &outputFormat, &converter); 

// Set conversion quality 
UInt32 tmp = kAudioConverterQuality_Medium; 
AudioConverterSetProperty(converter, kAudioConverterCodecQuality, 
          sizeof(tmp), &tmp); 
AudioConverterSetProperty(converter, kAudioConverterSampleRateConverterQuality, sizeof(tmp), &tmp); 

// Get the size of the IO buffer(s) 
UInt32 bufferSizeFrames = 0; 
size = sizeof(UInt32); 
AudioUnitGetProperty(self.inputUnit, 
           kAudioDevicePropertyBufferFrameSize, 
           kAudioUnitScope_Global, 
           0, 
           &bufferSizeFrames, 
           &size); 
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32); 

// Allocate an AudioBufferList plus enough space for array of AudioBuffers 
UInt32 propsize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * outputFormat.mChannelsPerFrame); 

// Malloc buffer lists 
convertedInputBuffer = (AudioBufferList *)malloc(propsize); 
convertedInputBuffer->mNumberBuffers = 1; 

// Pre-malloc buffers for AudioBufferLists 
convertedInputBuffer->mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame; 
convertedInputBuffer->mBuffers[0].mDataByteSize = bufferSizeBytes; 
convertedInputBuffer->mBuffers[0].mData = malloc(bufferSizeBytes); 
memset(convertedInputBuffer->mBuffers[0].mData, 0, bufferSizeBytes); 

// Setup callback for converter 
static OSStatus inputProcPtr(AudioConverterRef    inAudioConverter, 
           UInt32*       ioNumberDataPackets, 
           AudioBufferList*    ioData, 
           AudioStreamPacketDescription* __nullable* __nullable outDataPacketDescription, 
           void* __nullable    inUserData) 
{ 
    // Read data from buffer 
} 

// Perform actual sample rate conversion 
AudioConverterFillComplexBuffer(converter, inputProcPtr, NULL, &numberOfFrames, convertedInputBuffer, NULL) 

inputProcPtr callback никогда не вызывается. Я пытался установить различное количество кадров, но все равно получаю OSStatus -50.

1) Использует AudioConverterRef - правильный способ конверсии частоты дискретизации, или это можно сделать по-другому?

2) Что случилось с моей реализацией преобразования?

Спасибо всем заранее

ответ

0

Одна из проблем заключается в следующем:

AudioUnitGetProperty(self.inputUnit, 
          kAudioDevicePropertyBufferFrameSize, 
          kAudioUnitScope_Global, 
          0, 
          &bufferSizeFrames, 
          &size); 

kAudioDevicePropertyBufferFrameSize является собственностью OSX, и не существует на прошивкой. Как этот код даже компилируется?

Если вы каким-то образом скомпилировали его, проверьте код возврата из этой функции! У меня такое ощущение, что он терпит неудачу, и bufferSizeFrames равен нулю. Это сделало бы AudioConverterFillComplexBuffer return -50 (kAudio_ParamError).

Так на iOS либо выберете bufferSizeFrames самостоятельно, либо положите его на AVAudioSessionIOBufferDuration, если вам нужно.

Другая проблема: проверьте коды возврата. Все они!

например.

UInt32 tmp = kAudioConverterQuality_Medium; 
AudioConverterSetProperty(converter, kAudioConverterCodecQuality, 
         sizeof(tmp), &tmp); 

Я уверен, что нет кодека говорить в LPCM-> преобразования LPCM, и что kAudioConverterQuality_Medium не является правильным значением для использования с kAudioConverterCodecQuality в любом случае. Я не вижу, как этот вызов может быть успешным.