Multi Channel Audio With AVAudioEngine, Flipping Audio Channels

Hi,

I have multiple audio files I want to decide which channel goes to which output. For example, how to route four 2-channel audio files to an 8-channel output.

Also If I have an AVAudioPlayerNode playing a 2-channel track through headphones, can I flip the channels on the output for playback, i.e flip left and right?

I have read the following thread which seeks to do something similar, but it is from 2012 and I do not quite understand how it would work in modern day.

Many thanks, I am a bit stumped.

Post not yet marked as solved Up vote post of jaolan Down vote post of jaolan
1.6k views

Replies

Hey ! I stumbled across your post while searching myself, since I found a solution, let me post it here.

Goal

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.

Setup formats

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.

Mixer -> Output

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.

Source -> Mixer

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)

Source channels mapping

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.