2016-01-20 231 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使用权价值。我不明白这个电话会如何成功。