Imagine you have a USB audio interface with 20 output channels attached to your iMac, and you want to have multiple stereo files playing to multiple stereo speakers. Each file to one speaker. I'm hoping to accomplish this with AVAudioEngine + a bit of low level Core Audio kung-fu.
So far, I've successfully managed to play audio to my USB audio interface, by configuring AVAudioEngine's output node:
AudioUnit audioUnit = [[self.avAudioEngine outputNode] audioUnit];
OSStatus error = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&deviceID,
sizeof(deviceID));
if (error) {
NSLog(@"Failed to set desired output audio device: %d", (int)error);
}
I've also successfully managed to set up a channel map which lets one player play to channels 4+5 of my USB audio interface:
// Get the output's channel count
UInt32 outputNumChannels = [engineOutputNode outputFormatForBus:0].channelCount; /
// Create channel map array
SInt32 outputChannelMap[outputNumChannels];
// Set all channels to -1 (unmapped)
memset(outputChannelMap, -1, sizeof(outputChannelMap));
// Set desired channels
outputChannelMap[4] = 0; // channel 0 of the player to channel 4 of the USB audio interface
outputChannelMap[5] = 1; // channel 1 of the player to channel 5 of the USB audio interface
// Apply channel map
UInt32 propSize = (UInt32)sizeof(outputChannelMap);
OSStatus err = AudioUnitSetProperty(engineOutputNode.audioUnit,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Global,
0,
outputChannelMap,
propSize);
theanalogkid gave a great example for how to do the above, here: https://forums.developer.apple.com/thread/15416
However, I am stuck figuring out how to apply such a channel map on a per-player basis, as opposed to applying it to the entire AVAudioEngine.
My hunch was to create a mixer node for each player, and then apply a channel map to that mixer node instead. High Sierra exposed the AVAudioMixerNode's AUAudioUnit. Though when trying this, I'm getting an error -2147450879:
AudioUnit au = CFBridgingRetain(speakerMixer.AUAudioUnit);
// Set channel map
UInt32 propSize = (UInt32)sizeof(outputChannelMap);
OSStatus err = AudioUnitSetProperty(au,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Global,
0,
outputChannelMap,
propSize);
if (noErr != err) {
NSLog(@"Error setting channel map! %d", (int)err); // -2147450879
}
Any idea what I'm missing?