Hey ! I stumbled across your post while searching myself, since I found a solution, let me post it here.
To recap, I am trying to read several audio files and output them in different channels. In my setup, I have 2 devices that both have two channels so I have 4 channels in the end. I use an aggregate device and run the iOS app with Catalyst (I couldn't make aggregate device work with AVAudioEngine
on macOS 🤷♂️).
I use AVAudioSourceNode
as input but it should also work with AVAudioPlayerNode
since both have an auAudioUnit
property.
When the engine is being setup, I make sure that the channels count of the output node is 4:
let outputFormat = audioEngine.outputNode.outputFormat(forBus: 0)
print("Channels count:", outputFormat.channelCount) // 4
If not, this might be because the AVAudioSession
is not configured with the multiRoute
category.
Then, I had to connect the engine main mixer node to the output node using the output node format.
audioEngine.connect(audioEngine.mainMixerNode, to: audioEngine.outputNode, format: format)
I don't know why it's necessary. When I read the doc, it seems that it's already done by default.
If the client never sets the connection format between the mainMixerNode and the outputNode, the engine always updates the format to track the format of the outputNode on startup or restart, even after an AVAudioEngineConfigurationChange.
I also had to connect each source node to the main mixer node using the output format. Otherwise the channel mapping will not be effective.
engine.connect(sourceNode, to: engine.mainMixerNode, format: outputFormat)
In the end, I could set the auAudioUnit.channelMap
of each source node to output to the desired channels. For instance
sourceNode.auAudioUnit.channelMap = [0, 1, -1, -1]
to output in the first pair of speakers (default) and
sourceNode.auAudioUnit.channelMap = [-1, -1, 0, 1]
to output to the second pair of speakers.