My recently-bought Behringer UMC204HD audio interface, that is advertised as 2 inputs, 4 outputs, presents itself to Linux as one stereo input channel and one 4.0 output channel:

 1pacmd list-sinks |grep -P 'name: \<|channel map' -C 1
 2...
 3    index: 2
 4	name: <alsa_output.pci-0000_00_1b.0.iec958-stereo>
 5	driver: <module-alsa-card.c>
 6--
 7	sample spec: s16le 2ch 44100Hz
 8	channel map: front-left,front-right
 9	             Stereo
10...
11pacmd list-sources |grep -P 'name: \<|channel map' -C 1
12...
13    index: 2
14	name: <alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo>
15	driver: <module-alsa-card.c>
16--
17	sample spec: s32le 2ch 44100Hz
18	channel map: front-left,front-right
19	             Stereo
20
21...

I'm guessing the reason is plain "we just use some generic USB ADC/DAC chip and reference implementation comes in that config".

That poses a problem for most voice communication software, usually putting stereo input into it means it will sum both channels up, and summing a channel with signal to channel with zero signal results in volume drop (-6db usually).

Some software is competent enough to auto-gain out of that problem, but most don't even have VU meter, let alone any indication of sound level you're sending to other participants of the conversation so it's easy to be too quiet in out of the box config.

So we need to split one device into two. We might still occasionally want the stereo input so I won't try to replace it with two mono ones.

Remapping the channels

We will use 2 pulseaudio modules module-remap-source and module-remap-sink

Both work in same manner: you specify the master sink/source, new device name and list names of channels in order of each side to link, so for example device that switches channel order would have front-left,front-right on one side and front-right,front-left on the other.

For example, remapping first(left) input into solo mono input:

1pacmd load-module module-remap-source source_name=UMC204HD_in1 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-left remix=no source_properties="device.description='UMC204HD\ input\ 1'"`

Used options:

  • source_name - name of newly created source
  • channel_map - map of the new channel, mono if you just want single channel, front-left,front-right if you want stereo etc. For sanity you should probably stick to the "normal" order of left->right
  • master - name of source you're taking channels from
  • master_channel_map - which channels to use, one entry per entry from channel map. For our mono example it would be front-left for first channel, front-right for second.
  • source_properties - any extra properties of our created sources. We only set description here (as shown, spaces must be escaped) but there is few other options like setting the icon of device
  • remix=no - disable any funky processing pulseaudio would want to do if it finds some extra channels in master

So, for our example of one stereo into mono we came to this:

1pacmd load-module module-remap-source source_name=UMC204HD_in1 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-left remix=no source_properties="device.description='UMC204HD\ input\ 1'"
2pacmd load-module module-remap-source source_name=UMC204HD_in2 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-right remix=no source_properties="device.description='UMC204HD\ input\ 2'"

and we can switch one we deem worthy to be our default

1pacmd set-default-source UMC204HD_in1

Making remap stick

You could at this point just stick

1.include /etc/pulse/default.pa
2.nofail
3load-module module-remap-source source_name=UMC204HD_in1 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-left remix=no source_properties="device.description='UMC204HD\ input\ 1'"
4load-module module-remap-source source_name=UMC204HD_in2 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-right remix=no source_properties="device.description='UMC204HD\ input\ 2'"
5set-default-source UMC204HD_in1
6.fail 

into ~/.config/pulse/default.pa and call it a day but that has noticeable disadvantage of not working after USB gets reconnected (PA only parses that on start and will not get a clue if the device shows up later while daemon is still working).

For that we need to run those when the card is detected. It is generally the UDEV job to do it but the problem here is that UDEV is running scripts as root while pulseaudio is running as user.

we can get "what udev knows about the card" via

udevadm info --attribute-walk --path=/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/sound/card3

and make required rule to run script setting the setup.

We can also reload udev config via udevadm control --reload-rules and trigger rerun of them via udevadm trigger (WARNING it will not generate "add" action, only "change")

But there are few problems we need to solve there:

  • udev runs stuff on root, pulseaudio runs as user
  • udev will call it multiple times in parallel per each device. So we either need to make super-specific rule or put a lock around it
  • there is delay between running script in udev and device showing up in pulseaudio. Which means we need to wait for device to show up in pulseaudio but we can't do that directly in script ran from udev because that would stall device creation

That means we need to split the job. First, create udev rule

1☠ cat /etc/udev/rules.d/99-behringer-umc204hd.rules 
2ACTION=="add",ATTRS{idVendor}=="1397", ATTRS{idProduct}=="0508",DRIVER=="snd-usb-audio", RUN+="/home/xani/bin/pa-split-streams"

with vendor/product IDs extracted from lsusb

then we have script running our stuff as user:

1# cat /home/xani/bin/pa-split-streams
2#!/bin/bash
3systemd-run --unit=pa-split-streams --on-active=5 su xani -c /home/xani/bin/pa-split-streams2 || exit 0

and script that it is calling

1# cat  /home/xani/bin/pa-split-streams2
2#!/bin/bash
3export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
4PAUSER=$(whoami)
5PAUSER_UID=$(id -u $PAUSER)
6export PULSE_RUNTIME_PATH=/run/user/$PAUSER_UID/pulse/
7pacmd load-module module-remap-source source_name=UMC204HD_in1 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-left remix=no source_properties="device.description='UMC204HD\ input\ 1'"
8pacmd load-module module-remap-source source_name=UMC204HD_in2 master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo channel_map=mono master_channel_map=front-right remix=no source_properties="device.description='UMC204HD\ input\ 2'"
9pacmd set-default-source UMC204HD_in1

WARNING This script WILL be ran as root. Take care to limit vulnerable surface on it. Putting it in root-only accessible place (especially the first one) is recommended

How it works:

  • udev calls it when device is added (i.e on reconnect)
  • script schedules a systemd timer (or fails to if it is already running, that's our "lock" and reason for || exit 0) to run it as your user via su
  • second script sets up pulseaudio environmental vars to point to right directory and runs remapping.

Reliance on timer is a bit ugly but alternative would be asking PA whether it seen the source yet in a loop and so far I didn't find the effort neccesary for better result.

Bonus: splitting the outputs

In analogous way, the 4.0 output can be split:

1pacmd load-module module-remap-sink sink_name=UMC204HD_out_a master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=front-left,front-right channel_map=front-left,front-right remix=no sink_properties="device.description='UMC204HD\ stereo\ A'"
2pacmd load-module module-remap-sink sink_name=UMC204HD_out_b master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=rear-left,rear-right channel_map=front-left,front-right remix=no sink_properties="device.description='UMC204HD\ stereo\ B'"
3pacmd load-module module-remap-sink sink_name=UMC204HD_out_1 master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=front-left channel_map=mono remix=no sink_properties="device.description='UMC204HD\ output\ 1'"
4pacmd load-module module-remap-sink sink_name=UMC204HD_out_2 master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=front-right channel_map=mono remix=no sink_properties="device.description='UMC204HD\ output\ 2'"
5pacmd load-module module-remap-sink sink_name=UMC204HD_out_3 master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=rear-left channel_map=mono remix=no sink_properties="device.description='UMC204HD\ output\ 3'"
6pacmd load-module module-remap-sink sink_name=UMC204HD_out_4 master=alsa_output.usb-BEHRINGER_UMC204HD_192k-00.analog-surround-40 master_channel_map=rear-right channel_map=mono remix=no sink_properties="device.description='UMC204HD\ output\ 4'"

here we're splitting it into 2 stereo pairs and into 4 separate mono channels as well..

As for the audio interface itself it works entirely fine. There is a soft click when it first gets audio data from USB (weirdly enough, none at power on) but it has been nice and quiet.

I haven't had a chance or reason (I have separate preamp) to test the mic preamp on the input.