I'm trying to create a very basic inter-app audio setup with AVAudioEngine. The app will crash when I try to connect the inter-app audio unit to the main mixer. I've checked to make sure the audio unit is created and not nil. Here is what I have:
- (void)viewDidLoad {
[super viewDidLoad];
//create session with category play and record and options mix with others.
AVAudioSession* session = [AVAudioSession sharedInstance];
NSError* err;
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&err];
[session setPreferredSampleRate:44100.0 error:&err];
[session setActive:YES error:&err];
AVAudioEngine* audioEngine = [[AVAudioEngine alloc] init];
//Find the first available remote instrument for testing.
//This requires you have a remote instrument installed. I've been using a free one called DRC.
//I tested DRC with GarageBand so I know it works as a remote instrument.
//Make sure componentArray is filled with at least 1 object.
AudioComponentDescription description = { kAudioUnitType_RemoteInstrument, 0, 0, 0, 0 };
NSArray* componentArray = [[AVAudioUnitComponentManager sharedAudioUnitComponentManager] componentsMatchingDescription:description];
AVAudioUnitComponent* comp = [componentArray objectAtIndex:0];
AVAudioUnitMIDIInstrument* instUnit = [[AVAudioUnitMIDIInstrument alloc] initWithAudioComponentDescription:comp.audioComponentDescription];
//
//Just checking stream formats
//Oddly enough, none of these crash. The internal AudioUnit wrapped in the AVAudioUnit is clearly working fine.
//Commenting these lines out changes nothing
//
AVAudioFormat* outputFormat = [[audioEngine outputNode] inputFormatForBus:0];
AudioStreamBasicDescription outDesc;
UInt32 outSize = sizeof(outDesc);
AudioUnitSetProperty(instUnit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, 0, outputFormat.streamDescription, sizeof(outputFormat.streamDescription));
AudioUnitSetProperty(instUnit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, 1, outputFormat.streamDescription, sizeof(outputFormat.streamDescription));
AudioUnitGetProperty(instUnit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, 0, &outDesc, &outSize);
AudioUnitGetProperty(instUnit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Global, 1, &outDesc, &outSize);
//
//Any of these will crash with error: *** Terminating app due to uncaught exception 'NSRangeException'
//, reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array'
//
// [instUnit_ outputFormatForBus:0];
// [instUnit_ inputFormatForBus:0];
// instUnit_.name;
//!!!!!!!!!!!!!!!!!!!
//HERE IS THE TROUBLE
//!!!!!!!!!!!!!!!!!!!
//this will crash during the connect with a mysterious index out of bounds error for an NSArray with 0 elements
//in it.
//attach AudioUnit
[audioEngine attachNode:instUnit];
//connect audio unit
//Crash happens here
[audioEngine connect:instUnit to:[audioEngine mainMixerNode] format:nil];
[audioEngine startAndReturnError:&err];
if(err) {
NSLog(@"error: %@", err.localizedDescription);
}
}