Fifteen years ago, NetBSD’s Bluetooth audio stack was
From what I remember using it back then, it worked sufficiently well but its
configuration was cumbersome.
It supported Bluetooth HID keyboards and mice, audio, and serial devices.
Six years ago, however, it was
due to conflicts with how it integrated into our kernel.
While we still have no Bluetooth support today, it is possible to play audio on Bluetooth headphones using a small hardware dongle.
Last year I
USB device, which presents a standard
device on OpenBSD and handles all of the Bluetooth pairing and audio
communication itself with just one shortcoming: it did not expose any volume
OpenBSD’s sound server,
did have software volume control so it was possible to limit the volume through
I’ve been using the BT-W2 frequently since then to send audio from my OpenBSD laptop to my Apple AirPods Pro, but unfortunately Apple released a firmware at some point that limited the volume output when paired with such devices, including Android phones. Presumably this was a safety measure because unless the sending side was doing software volume control (which the AirPods wouldn’t know about), the AirPods would play at maximum volume.
Unfortunately, even at the loudest volume from
sndiod, the volume to the
AirPods was still quite low, sometimes even too low to understand YouTube videos
with poor audio like conference talks.
Otherwise though, the BT-W2 worked well and I didn’t notice any latency or
video sync issues on OpenBSD.
The other day I became aware of the updated
which now has a USB-C interface instead of USB-A and finally exposes hardware
mixer control (note the
uaudio0 at uhub0 port 3 configuration 1 interface 1 "Creative Technology Ltd Creative BT-W3" rev 2.00/1.00 addr 2 uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec, 2 ctls audio1 at uaudio0
Since Tweeting about the BT-W2 last year, OpenBSD’s audio system has changed
quite a bit and now
sndiod controls output volume itself with
the preferred utility, rather than directly changing hardware mixer settings
mixerctl as in years past.
The new hardware volume control (
outputs.dac) can still be seen or modified
mixerctl and passing it the control device for
/dev/audioctl0 is for the built-in audio device of my laptop):
# mixerctl -f /dev/audioctl1 outputs.dac=161 outputs.dac_mute=off record.enable=sysctl
Whatever mechanism the BT-W3 uses to handle this hardware volume control (whether just doing software volume limiting itself, or passing it through to the AirPods through some fancy audio protocol), the benefit is that now the AirPods can be used at full volume from OpenBSD.
Automatically Switching to Bluetooth
My laptop’s Dolby Atmos speaker setup is pretty good, so normally I just listen to music or play YouTube videos through the speakers. When my son is napping and I need to use my AirPods, I want to just plug in the BT-W3 dongle and have it automatically start sending audio to my AirPods, and have the volume controls on my keyboard control the AirPods.
To accomplish this, set an alternate device name with
# rcctl set sndiod flags -f rsnd/0 -F rsnd/1 # rcctl restart sndiod
In this mode,
sndiod will play through
rsnd/1 if it exists, which maps to
the second audio device (
If the device is not present, such as when the BT-W3 is not plugged in, it will
rsnd/0 which maps to
audio0, the laptop’s built-in speakers.
This works fine if the device is present when
sndiod starts, but otherwise it
will need a
SIGHUP to re-scan the audio devices once the BT-W3 is plugged in,
and start sending audio through it.
This can be done automatically with
# cat > /etc/hotplug/attach case $2 in uaudio*) pkill -HUP sndiod ;; esac ^D # chmod +x /etc/hotplug/attach # rcctl enable hotplugd # rcctl start hotplugd
Now when a new
uaudio device is plugged in and detected by the kernel,
hotplugd will send a
sndiod which will see that
available and start sending audio to it.
When the BT-W3 is unplugged,
sndiod will automatically detect that the device
is no longer usable and send audio to its fallback,
Hardware device switching will be seamless and any applications playing audio
won’t have to stop or be restarted.
is configured to respond to the hardware volume keys on my laptop (F4 for mute,
F5 for volume down, and F6 for volume up) by executing
sndioctl, so the
commands will work the same regardless of which device
sndiod is talking to.
definekey top F4 exec sndioctl -q output.mute=!; pkill -USR1 i3status; true definekey top F5 exec sndioctl -q output.mute=0; sndioctl -q output.level=-0.05; pkill -USR1 i3status; true definekey top F6 exec sndioctl -q output.mute=0; sndioctl -q output.level=+0.05; pkill -USR1 i3status; true