I'm trying to grab audio input from the iPhone's microphone by using this code:
@property (nonatomic) AudioUnit rioUnit;
@property (nonatomic) CAStreamBasicDescription outputCASBD;
(...)
// set our required format - LPCM non-interleaved 32 bit floating point
CAStreamBasicDescription outFormat = CAStreamBasicDescription(44100, // sample rate
kAudioFormatLinearPCM, // format id
4, // bytes per packet
1, // frames per packet
4, // bytes per frame
1, // channels per frame
32, // bits per channel
kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved);
try {
// Open the output unit
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
AudioComponentInstanceNew(comp, &_rioUnit);
UInt32 one = 1;
XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one)), "couldn't enable input on the remote I/O unit");
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = renderInput;
callbackStruct.inputProcRefCon = (__bridge void*)self;
XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct)), "couldn't set remote i/o render callback");
XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, sizeof(outFormat)), "couldn't set the remote I/O unit's output client format");
XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, sizeof(outFormat)), "couldn't set the remote I/O unit's input client format");
XThrowIfError(AudioUnitInitialize(_rioUnit), "couldn't initialize the remote I/O unit");
XThrowIfError(AudioOutputUnitStart(_rioUnit), "couldn't start the remote I/O unit");
}
catch (CAXException &e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
catch (...) {
fprintf(stderr, "An unknown error occurred\n");
}
// Allocate our own buffers (1 channel, 16 bits per sample, thus 16 bits per frame, thus 2 bytes per frame).
// Practice learns the buffers used contain 512 frames, if this changes it will be fixed in processAudio.
// will need float for accellerate fft (input is 16 bit signed integer) so make space...
_tempBuffer.mNumberChannels = outFormat.mChannelsPerFrame;
_tempBuffer.mDataByteSize = 512 * outFormat.mBytesPerFrame * 2;
_tempBuffer.mData = malloc( self.tempBuffer.mDataByteSize );
All is good, up to the point where I want to stop listening to the Mic input.
I'm doing this:
AudioOutputUnitStop(_rioUnit);
AudioUnitUninitialize(_rioUnit);
AudioComponentInstanceDispose(_rioUnit);
_rioUnit = nil;
But I get an error from inside the callback function defined for kAudioOutputUnitProperty_SetInputCallback
.
The error is: AURemoteIO::IOThread (14): EXC_BAD_ACCESS (code=1, address=0x8000000c)
It appears to me that AudioUnit's InputCallback is still being called, even though I am Stopping it, Unitializing and Disposing of its instance.
Why is this happening and how can I prevent the InputCallback from being called after I Stop, Unitialize and Dispose of its instance?
First, make sure that _rioUnit really has the same value in the stop as in the start.
The audio input callback is being called in another asynchronous thread. So you may need to wait until that thread also stops (which usually happens in less than 2 audio buffer duration times, so that may be a reasonable amount to time to wait) before uninitializing or disposing of the audio unit or any other needed data structures.
The problem was this line:
_rioUnit = nil; // causes EXC_BAD_ACCESS error
Changing nil
to NULL
solved the issue:
_rioUnit = NULL; // works smoothly
I got the idea from this article: http://teragonaudio.com/article/How-to-do-realtime-recording-with-effect-processing-on-iOS.html
Also, this answer outlines the difference between nil
and NULL
in Objective-C
.
User contributions licensed under CC BY-SA 3.0