Multiple AVAudioPlayerNodes, each playing to different output channels

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?

Replies

Hi! Have you found solution?