2016-01-20 93 views
2

我寫了一個使用「novocaine」庫來錄製和播放聲音的voip應用程序。我將採樣率設置爲8kHz。此採樣率在音頻單元的AudioStreamBasicDescription中設置爲novocaine,並設置爲音頻會話屬性kAudioSessionProperty_PreferredHardwareSampleRate。據我所知,設置首選硬件採樣率並不能保證實際的硬件採樣率會發生變化,但它適用於除iPhone6s和iPhone6s +之外的所有設備(當路由更改爲揚聲器時)。通過iPhone6s(+)和揚聲器路線,我可以收到來自麥克風的48kHz聲音。所以我需要以某種方式將這個48kHz的聲音轉換成8kHz。在文檔中,我發現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回調永遠不會被調用。我試圖設置不同數量的幀,但仍然收到OSStatus -50。

1)使用AudioConverterRef是否是正確的方式來進行採樣率轉換或可以以不同的方式完成?

2)我的轉換實現有什麼問題?

謝謝大家提前

回答

0

的一個問題是這樣的:

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

kAudioDevicePropertyBufferFrameSize是OSX的財產,設備和iOS不存在。這段代碼如何編譯?

如果你以某種方式編譯它,請檢查這個函數的返回代碼!我有一種失敗的感覺,並且bufferSizeFrames爲零。這將使AudioConverterFillComplexBuffer返回-50(kAudio_ParamError)。

因此,在iOS上,您可以自己挑選bufferSizeFrames或根據AVAudioSessionIOBufferDuration(如果必須)。

另一個問題:檢查您的返回碼。他們全部!

例如

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

我敢肯定,沒有編解碼器LPCM-> LPCM轉換可言,那kAudioConverterQuality_Medium不是在任何情況下與kAudioConverterCodecQuality使用權價值。我不明白這個電話會如何成功。