enum : AudioUnitElement {
kOutputElement = 0,
kInputElement = 1
};
const UInt32 disableFlag = 0;
const UInt32 enableFlag = 1;
OSStatus err = noErr;
NSError *error = nil;
// Configure & activate audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
if (![session setCategory:AVAudioSessionCategoryRecord error:&error]) NSLog(@"Error configuring session category: %@", error);
if (![session setMode:AVAudioSessionModeMeasurement error:&error]) NSLog(@"Error configuring session mode: %@", error);
if (![session setActive:YES error:&error]) NSLog(@"Error activating audio session: %@", error);
NSLog(@"Session activated. sample rate %f", session.sampleRate);
NSLog(@"Number of channels %d", session.inputNumberOfChannels);
NSInteger numChannels = session.inputNumberOfChannels;
// Set up Remote I/O audio unit for audio capture
AudioComponent component = AudioComponentFindNext(NULL, &(const AudioComponentDescription){
.componentType = kAudioUnitType_Output,
.componentSubType = kAudioUnitSubType_RemoteIO,
.componentManufacturer = kAudioUnitManufacturer_Apple,
.componentFlags = 0,
.componentFlagsMask = 0
});
AudioComponentInstance unit;
// Create audio component
err = AudioComponentInstanceNew(component, &unit);
if (err != noErr) NSLog(@"Error instantiating audio unit: %@", E2S(err));
// Enable input
err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputElement, &enableFlag, sizeof(enableFlag));
if (err != noErr) NSLog(@"Error enabling input for audio unit: %@", E2S(err));
// Disable output
err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputElement, &disableFlag, sizeof(disableFlag));
if (err != noErr) NSLog(@"Error disabling output for audio unit: %@", E2S(err));
// "The canonical audio sample type for audio units and other audio processing in iPhone OS is noninterleaved linear PCM with 8.24-bit fixed-point samples."
assert(kAudioFormatFlagsAudioUnitCanonical & kAudioFormatFlagIsNonInterleaved);
AudioStreamBasicDescription streamDesc = {
.mSampleRate = session.sampleRate,
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical /*matches AudioUnitSampleType*/,
.mBytesPerPacket = sizeof(AudioUnitSampleType) * numChannels,
.mFramesPerPacket = 1,
.mBytesPerFrame = sizeof(AudioUnitSampleType) * numChannels,
.mChannelsPerFrame = numChannels,
.mBitsPerChannel = 8 * sizeof(AudioUnitSampleType),
.mReserved = 0,
};
err = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputElement, &streamDesc, sizeof(streamDesc));
if (err != noErr) NSLog(@"Error configuring input stream format for audio unit: %@", E2S(err));
AURenderCallbackStruct callbacks = {
.inputProc = myInputCallback,
.inputProcRefCon = unit
};
err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, kOutputElement, &callbacks, sizeof(callbacks));
if (err != noErr) NSLog(@"Error configuring input callbacks for audio unit: %@", E2S(err));
err = AudioUnitInitialize(unit);
if (err != noErr) NSLog(@"Error initializing audio unit: %@", E2S(err));
err = AudioOutputUnitStart(unit);
if (err != noErr) NSLog(@"Error starting audio unit: %@", E2S(err));