Pactl combined-sink outputs not mapping independently

I’m setting up a four channel sound lab for young coders to practice Python on, and I must be close to success but the output channel mapping is resisting :roll_eyes:.

Our rig:
Raspberry Pi 4B / 4M
Manjaro ARM Linux Release: 23.02
pipewire using libpipewire 0.3.65 + ALSA module
pactl says libpulse 16.1.0
wireplumber
2 x USB audio adapters
Audio is checked out, each adapter functioning fine as a stereo device.

Our plan is:
Python + sounddevice (portaudio) module
→ pulse ‘default’ device based on module-combine-sink
→ 2 x USB audio adapters

[1] The loaded module does some weird mapping. Method:

pactl load-module module-combine-sink sink_name="fourplay" slaves=alsa_output.usb-Plugable_Plugable_USB_Audio_Device_000000000000-00.2.analog-stereo,
  alsa_output.usb-Plugable_Plugable_USB_Audio_Device_000000000000-00.analog-stereo channel_map=left,right,rear-left,rear-right channels=4 remix=no
  • generates a pipewire ID. Then we:
pactl set-default-sink fourplay

… successful

wpctl status

shows (a bit odd):

└─ Streams:
...
       81. output.fourplay_alsa_output.usb-Plugable_Plugable_USB_Audio_Device_000000000000-00.analog-stereo
            93. output_1        > Plugable USB Audio Device:playback_FL	[paused]
            94. output_2        > Plugable USB Audio Device:playback_FR	[paused]
            95. output_RL
            96. output_RR
       83. output.fourplay_alsa_output.usb-Plugable_Plugable_USB_Audio_Device_000000000000-00.2.analog-stereo
            79. output_1        > Plugable USB Audio Device:playback_FL	[paused]
            97. output_2        > Plugable USB Audio Device:playback_FR	[paused]
            98. output_RL
            99. output_RR

            Settings
 └─ Default Configured Node Names:
         0. Audio/Sink    fourplay

Then, with Python:

>>> import sounddevice as sd
>>> print(sd.query_devices())
  0 bcm2835 Headphones: - (hw:1,0), ALSA (0 in, 8 out)
  1 Plugable USB Audio Device: - (hw:3,0), ALSA (2 in, 2 out)
  2 Plugable USB Audio Device: - (hw:4,0), ALSA (2 in, 2 out)
  3 pipewire, ALSA (64 in, 64 out)
* 4 default, ALSA (64 in, 64 out)

>>> import soundfile as sf
>>> data,fs = sf.read("noise.wav")
>>> sd.play(data,mapping=[1])   # appears in FL and RL outputs (left channel on both cards, should only be FL)
>>> sd.play(data,mapping=[2])   # right ditto
>>> sd.play(data,mapping=[3])   # silence
>>> sd.play(data,mapping=[4])   # right ditto

The best guesses I have are:

  • ‘remix=no’ is being ignored?
  • my channel maps are rubbish?

The Pulse Wiki FAQ shows a technique of specifying the channel names when loading the original device modules, but …

pactl load-module module-alsa-sink device="hw:3,0"   sink_name=output0 channel_map=front-left,front-right channels=2
Failure: No such entity

Gripe: there being six different ways to name/identify a device, none of which work universally.

Any advice?

inxi --audio
Audio:
  Device-1: bcm2711-hdmi0 driver: vc4_hdmi
  Device-2: bcm2711-hdmi1 driver: vc4_hdmi
  Device-3: bcm2835-audio driver: bcm2835_audio
  Device-4: JMTek LLC. Plugable USB Audio Device type: USB
    driver: hid-generic,snd-usb-audio,usbhid
  Device-5: JMTek LLC. Plugable USB Audio Device type: USB
    driver: hid-generic,snd-usb-audio,usbhid
  Sound API: ALSA v: k5.15.92-1-MANJARO-ARM-RPI running: yes
  Sound Server-1: PipeWire v: 0.3.65 running: yes