How can i resample audio(PCM data) using Audio Unit at runtime/live ?
I have an Audio Unit setup as follows.
- (void) setUpAudioUnit {
OSStatus status;
AudioComponentInstance audioUnit;
AudioComponent inputComponent;
AudioComponentDescription audioComponentDescription;
AudioStreamBasicDescription audioStreamBasicDescription;
// Describe audio component
audioComponentDescription.componentType = kAudioUnitType_Output;
audioComponentDescription.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
audioComponentDescription.componentFlags = 0;
audioComponentDescription.componentFlagsMask = 0;
audioComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
// Get component
inputComponent = AudioComponentFindNext(NULL, &audioComponentDescription);
// Get audio units
status = AudioComponentInstanceNew(inputComponent, &audioUnit);
checkStatus(status);
// Enable IO for recording
UInt32 flag = 1;
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
checkStatus(status);
// Enable IO for playback
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flag,
sizeof(flag));
checkStatus(status);
// Describe format
audioStreamBasicDescription.mSampleRate = AUDIO_SAMPLE_RATE;
audioStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
audioStreamBasicDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioStreamBasicDescription.mFramesPerPacket = AUDIO_FRAMES_PER_PACKET;
audioStreamBasicDescription.mChannelsPerFrame = AUDIO_CHANNELS_PER_FRAME;
audioStreamBasicDescription.mBitsPerChannel = AUDIO_BITS_PER_CHANNEL;
audioStreamBasicDescription.mBytesPerPacket = AUDIO_BYTES_PER_PACKET;
audioStreamBasicDescription.mBytesPerFrame = AUDIO_BYTES_PER_FRAME;
// Apply format
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus,
&audioStreamBasicDescription,
sizeof(audioStreamBasicDescription));
checkStatus(status);
/* Make sure we set the correct audio category before restarting */
UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(audioCategory),
&audioCategory);
checkStatus(status);
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&audioStreamBasicDescription,
sizeof(audioStreamBasicDescription));
checkStatus(status);
// Set input callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
kInputBus,
&callbackStruct,
sizeof(callbackStruct));
checkStatus(status);
// Set output callback
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
kOutputBus,
&callbackStruct,
sizeof(callbackStruct));
checkStatus(status);
// Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
flag = 0;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_ShouldAllocateBuffer,
kAudioUnitScope_Output,
kInputBus,
&flag,
sizeof(flag));
}
And the Audio settings is as follows.
kOutputBus 0
kInputBus 1
AUDIO_SAMPLE_RATE 44100
AUDIO_FRAMES_PER_PACKET 1
AUDIO_CHANNELS_PER_FRAME 1
AUDIO_BITS_PER_CHANNEL 16
AUDIO_BYTES_PER_PACKET 2
AUDIO_BYTES_PER_FRAME 2
I am receiving the PCM data from recording callback as
audioBufferList->mBuffers[0].mData
SO, how can i resample this PCM data from 44.1KHz to 8KHz and vice versa ? I have googled a lot but didn't find any code sample or straight instruction for this.
Found these thread but none of these provides clear instruction.
Any code sample or information is highly appreciated.
A converter audio unit will handle your sample rate conversions. I find the best way to deal with this is to adapt your chain to what the hardware is doing natively. This means that you should get the system AudioStreamBasicDescription (sysASBD) then put converter units between the system and the parts of your chain that need something different. So for audio play through with 8K sampleRate you would do this: ReomoteIO(mic) -> converter -> your8Kprocessing -> converter -> RemoteIO(out).
Here is the description for the converter.
AudioComponentDescription convDesc;
convDesc.componentType = kAudioUnitType_FormatConverter;
convDesc.componentSubType = kAudioUnitSubType_AUConverter;
convDesc.componentFlags = 0;
convDesc.componentFlagsMask = 0;
convDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
Here is how you get the system ASBDin and ASBDout
UInt32 sizeASBD = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription ioASBDin;
AudioStreamBasicDescription ioASBDout;
AudioUnitGetProperty(remoteIO, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &ioASBDin, &sizeASBD);
AudioUnitGetProperty(remoteIO, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &ioASBDout, &sizeASBD);
All you have to do to use a converter is set it's input ASBD and output ASBD to the desired formats and it does all the work. The make your connections and you have your 8K play through.
AudioStreamBasicDescription asbd8K;
AudioComponentInstance converter44To8;
AudioUnitSetProperty(converter44To8,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,0,& ioASBDin,sizeof(AudioStreamBasicDescription));
AudioUnitSetProperty(converter44To8,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,0,&asbd8K,sizeof(AudioStreamBasicDescription));
AudioComponentInstance converter8To44;
AudioUnitSetProperty(converter8To44,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,0,&asbd8K,sizeof(AudioStreamBasicDescription));
AudioUnitSetProperty(converter8To44,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,0,& ioASBDout,sizeof(AudioStreamBasicDescription));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With