OpenBSD sndio and multiple devices

Automatic audio device switch

OpenBSD automatically detects the system audio device. But often this is not enough. I want to plug in a USB headset and audio should automatically switch to it.

You can start sndiod with additional -F flags to define additional devices, which are switched to when they appear.

# sndiod -f rsnd/0 -F rsnd/1 -F rsnd/2 -F rsnd/3

You can set these flags permanently with:

# rcctl set sndiod flags -f rsnd/0 -F rsnd/1 -F rsnd/2 -F rsnd/3

This configuration allows up to 3 additional USB devices to be connected and sndiod will switch to the last one connected.

If you have multiple devices connected and want to switch to a specific one, you can do so with:

$ sndioctl server.device=0
$ sndioctl server.device=1
$ sndioctl server.device=2
...

Record from one device, but play back on another…

Let’s say I want to connect USB microphone, but I want to play back sound on another device.

This works by setting the environment variables AUDIORECDEVICE and AUDIOPLAYDEVICE accordingly.

Example:

export AUDIOPLAYDEVICE=snd/0
export AUDIORECDEVICE=snd/1

By default sndiod opens each device for full-duplex (both input and output). A USB microphone that only supports recording will fail to open this way. The -m flag restricts a device to a specific direction, which is what makes the split setup work.

If the devices are more limited, the sndio flags need to be more specific, like this:

# rcctl set sndiod flags -f rsnd/0 -m play -s play -f rsnd/1 -m rec -s rec
# rcctl restart sndiod
$ export AUDIOPLAYDEVICE=snd/0.play
$ export AUDIORECDEVICE=snd/1.rec

This creates a “play” sub device on the first audio device (system audio). And a sub device “rec” on the first USB device. The default is “play,rec”, which would not work on my USB microphone. The -m switch describes what the device can do. The -s switch defines the sub device name.

And now… everything works as expected.

$ aucat -o test.wav # record from microphone
$ aucat -i test.wav # play on system speaker