AudioUnitInitialize throws error while initializing AudioComponentInstance

audio-recording, core-audio, ios, iphone

Solution

I found the solution. If we call below functions back to back, it creates problem.

extern OSStatus AudioUnitUninitialize(AudioUnit inUnit)                     
extern OSStatus AudioComponentInstanceDispose(AudioComponentInstance inInstance)

So, I called dispose method on main thread by below way.

[self performSelectorOnMainThread:@selector(disposeCoreAudio) withObject:nil waitUntilDone:NO];

-(void) disposeCoreAudio
{
     OSStatus status = AudioComponentInstanceDispose(kAudioUnit);
     kAudioUnit = nil;
}

It solved the problem. So, the correct sequence is Stop recording, uninitialize recorder and dispose recorder on main thread.

Problem

I am using below code to init my audio components. ``` -(void) startListeningWithCoreAudio { NSError *error = nil; [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:&error]; if (error) NSLog(@"error setting up audio session: %@", [error localizedDescription]); [[AVAudioSession sharedInstance] setDelegate:self]; OSStatus status = AudioSessionSetActive(YES); checkStatus(status); // Find the apple mic AudioComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO; desc.componentFlags = 0; desc.componentFlagsMask = 0; desc.componentManufacturer = kAudioUnitManufacturer_Apple; AudioComponent inputComponent = AudioComponentFindNext( NULL, &desc ); status = AudioComponentInstanceNew( inputComponent, &kAudioUnit ); checkStatus( status ); // enable mic output as our input UInt32 flag = 1; status = AudioUnitSetProperty( kAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag) ); checkStatus(status); // Define mic output audio format AudioStreamBasicDescription audioFormat; audioFormat.mSampleRate = 16000.0; audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioFormat.mFramesPerPacket = 1; audioFormat.mChannelsPerFrame = 1; audioFormat.mBitsPerChannel = 16; audioFormat.mBytesPerPacket = 2; audioFormat.mBytesPerFrame = 2; status = AudioUnitSetProperty( kAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &audioFormat, sizeof(audioFormat) ); checkStatus(status); // Define our callback methods AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = recordingCallback; callbackStruct.inputProcRefCon = self; status = AudioUnitSetProperty( kAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct) ); checkStatus(status); // By pass voice processing UInt32 audiobypassProcessing = [[NSUserDefaults standardUserDefaults] boolForKey:VOICE_BY_PASS_PROCESSING]; status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_BypassVoiceProcessing, kAudioUnitScope_Global, kInputBus, &audiobypassProcessing, sizeof(audiobypassProcessing)); checkStatus(status); // Automatic Gain Control UInt32 audioAGC = [[NSUserDefaults standardUserDefaults]boolForKey:VOICE_AGC]; status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, kInputBus, &audioAGC, sizeof(audioAGC)); checkStatus(status); //Non Audio Voice Ducking UInt32 audioDucking = [[NSUserDefaults standardUserDefaults]boolForKey:VOICE_DUCKING]; status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_DuckNonVoiceAudio, kAudioUnitScope_Global, kInputBus, &audioDucking, sizeof(audioDucking)); checkStatus(status); //Audio Quality UInt32 quality = [[NSUserDefaults standardUserDefaults]integerForKey:VOICE_QUALITY]; status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_VoiceProcessingQuality, kAudioUnitScope_Global, kInputBus, &quality, sizeof(quality)); checkStatus(status); status = AudioUnitInitialize(kAudioUnit); checkStatus(status); status = AudioOutputUnitStart( kAudioUnit ); checkStatus(status); UInt32 audioRoute = (UInt32)kAudioSessionOverrideAudioRoute_Speaker; status = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof (audioRoute), &audioRoute); checkStatus(status); } -(void) stopListeningWithCoreAudio { OSStatus status = AudioUnitUninitialize( kAudioUnit ); checkStatus(status); status = AudioOutputUnitStop( kAudioUnit ); checkStatus( status ); // if(kAudioUnit) // { // status = AudioComponentInstanceDispose(kAudioUnit); // checkStatus(status); // kAudioUnit = nil; // } status = AudioSessionSetActive(NO); checkStatus(status); NSError *error = nil; [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategorySoloAmbient error:&error]; if (error) NSLog(@"error setting up audio session: %@", [error localizedDescription]); } ``` It works fine for first time. I mean `startListeningWithCoreAudio` is called by a button pressed event. It could record/process audio well. On other event I am calling `stopListeningWithCoreAudio` to stop record/process audio. The problem is coming when I am again trying to call the function `startListeningWithCoreAudio`. It throws error for two functions. `AudioUnitInitialize` and `AudioOutputUnitStart` which are called from `startListeningWithCoreAudio`. Can anyone please help me what is the problem?

Original source