External USB Speakerphone on OpenBSD
2021-12-15This article describes some tests I did with a speakerphone under OpenBSD. I got it working with some restrictions.
Introduction
Within the winter term of 2021/22 I had the chance to get my hands on
a portable, wireless speakerphone (EPOS 30T BT)
. A great
opportunity to tinker with such kind of device under OpenBSD. Similar to
jcs experience with
bt audio, I used the include USB Bluetooth sound card to connect the
speakerphone with my PC.
In case of success, I would use the device to replace my current USB
audio interface/headset combination (yamaha AG 03
and
Superlux HDC
660X
). In general, I'm using this setup for video conferencing
with my students. But first things first, I need to allow to record
audio on my machine.
doas echo sysctl.kern.audio.record=1 >> /etc/sysctl.conf
Basic Setup
I don't want to reproduce the information from sndiod(8) and aucat(1). What follows, therefore, is a summary of commands I used often during my tests.
Basically, all physical (the real hardware) audio devices get
numbered like audio0, audio1 and corresponding (raw)
sound devices rsnd0, rsnd1. On my system,
rsnd0 refers to my internal audio device (e.g. speaker). To
test an external audio device I first tried to play and record audio
directly on the raw device rsnd/1
using
aucat
.
doas aucat -f rsnd/1 -o test.wav
doas aucat -f rsnd/1 -i test.wav
What I don't like about this approach is to execute these commands
with higher privileges (i.e. root
). For that reason, I
configured sndiod
in a way that it uses the internal audio
device rsnd/0
but switches to rsnd/1
when
available.
sndiod -dd -f rsnd/0 -F rsnd/1
Again, recording and playing of a .wav file but this time by using
snd
devices as regular user. But the speakerphone produces
no sound (i.e. empty .wav file).
aucat -f snd/1 -o test.wav
aucat -f snd/1 -i test.wav
Side Node: On my system, I always suffered from
"shuttering" audio on my speakers, my current workaround is to disable
the rec
mode on default
:
sndiod -f rsnd/0 -m play -s default -F rsnd/1 -m play,rec
Anyhow, the speakerphone keeps silent. So let's tinker with this thing a little bit more.
Testing
For testing, I attached my working yamaha AG 03
interface and start to invest. Here rsnd/1
is the
EPOS
and rsnd/2
the AG03. As you can see I
disabled my internal sound system (damn is sndiod
flexible!).
sndiod -dd -f rsnd/1 -f rsnd/2
At that point I came up with a test table as follows:
Device | Mode | Command |
---|---|---|
EPOS | Record | aucat -f snd/1 -o test.wav |
EPOS | Play | aucat -f snd/1 -i test.wav |
AG03 | Play | aucat -f snd/2 -i test.wav |
AG03 | Record | aucat -f snd/2 -o test.wav |
Resulting in the following combinations. (BTW. sndiod
is
really nice in doing such things in the mix)
Record | Play | Result |
---|---|---|
EPOS | EPOS | no audio |
EPOS | AG03 | no audio |
AG03 | EPOS | yes |
AG03 | AG03 | yes |
So it seems, that the speakerphone is not recording.
As a next step I compared the monitor
and
control
information of both devices to get a hint. After
shutting down of sndiod
to get access to the raw
devices.
Control Information for
the AG03 (rsnd/2
):
In both cases, I've checked the following points:
- all levels muted
off
- all level are high at 1.
Audio
audioctl -f /dev/audio2
name=uaudio1
mode=play
pause=0
active=0
nblks=16
blksz=480
rate=48000
encoding=s24le4msb
play.channels=2
play.bytes=0
play.errors=0
record.channels=2
record.bytes=0
record.errors=0
Mixer
mixerctl -f /dev/audio2
record.enable=sysctl
Control information for the
EPOS
Audio
audioctl -f /dev/audio1
name=uaudio0
mode=play
pause=0
active=0
nblks=16
blksz=480
rate=48000
encoding=s16le
play.channels=2
play.bytes=0
play.errors=0
record.channels=1
record.bytes=0
record.errors=0
Mixer settings
mixerctl -f /dev/audioctl1
outputs.dac=128
inputs.record=255
inputs.record_mute=off
record.enable=sysctl
Sessions with sndiod
Maybe session output of sndiod
brings more light into
that. A regular session with sndiod
looks
like:
snd0.default: rec=0:1 play=0:1 vol=32768 dup
snd0.0: rec=0:1 play=0:1 vol=32768 dup
snd1.1: rec=0:1 play=0:1 vol=32768 dup
default/server.device=0:1 at 1 -> opt_dev:default/0: added
default/server.device=1:0 at 2 -> opt_dev:default/1: added
app/firefox0.level=127 at 3 -> slot_level:firefox0: added
warning, device opened in play-only mode
0/output0.level=128 at 4 -> hw:0/0: added
0/input0.level=255 at 5 -> hw:0/64: added
0/input0.mute=0 at 6 -> hw:0/96: added
snd0: 48000Hz, s16le, play 0:1, 16 blocks of 480 frames
firefox0: 48000Hz, s16le, play 0:1, 4 blocks of 480 frames
snd0: device started
firefox0: attached at -7680 + 0/480
Screening the logs, warning, device opened in play-only mode
is
interesting because even if I configured this device in
play,rec
mode it merely gets opened in
play-only
mode.
I'm not certain about the reason but had some ideas in mind:
- the device cannot support play,rec (full-duplex)
- the app (i.e. Firefox) just requested a play mode; which is unlikely
at least in case for
aucat
where it was explicitly states as record operation
The last mile with
aucat
So back to start, I start recording with aucat
like
aucat -f snd/0 -o test.wav
Corresponding sndiod
configuration that
excludes all other audio devices and just uses the speakerphone.
sndiod -dd -f rsnd/1
And the corresponding log:
snd0.default: rec=0:1 play=0:1 vol=32768 dup
snd0.0: rec=0:1 play=0:1 vol=32768 dup
warning, device opened in play-only mode
0/output0.level=128 at 1 -> hw:0/0: added
0/input0.level=255 at 2 -> hw:0/64: added
0/input0.mute=0 at 3 -> hw:0/96: added
snd0: 48000Hz, s16le, play 0:1, 16 blocks of 480 frames
default/server.device=0:1 at 4 -> opt_dev:default/0: added
app/firefox0.level=127 at 5 -> slot_level:firefox0: added
firefox0: 48000Hz, s16le, play 0:1, 4 blocks of 480 frames
snd0: device started
firefox0: attached at -7680 + 0/480
app/aucat0.level=127 at 6 -> slot_level:aucat0: added
aucat0: attached at -7680 + 0/480
aucat0: 48000Hz, s16le, rec 0:1, 20 blocks of 480 frames
aucat0: detached at 0 + 0/480
aucat0: 48000Hz, s16le, play 0:1, 20 blocks of 480 frames
aucat0: attached at -7680 + 0/480
app/firefox1.level=127 at 7 -> slot_level:firefox1: added
firefox1: 44100Hz, s16le, play 0:1, 10 blocks of 441 frames
firefox1: attached at -7056 + 0/441
aucat0: attached at -7680 + 0/480
aucat0: 48000Hz, s16le, rec 0:1, 20 blocks of 480 frames
Recording works if the mode of the default
sub-device is set to rec
rather then play,rec
sndiod -dd -f rsnd/1 -m rec -s default
Bringing the speakerphone in rec-only
mode. But, you
guess it, no audio playing (kind of walky talky)
The warning about play-only
mode is
also gone (also kind of expected).
snd0.default: rec=0:1 dup
snd0.0: rec=0:1 dup
default/server.device=0:1 at 1 -> opt_dev:default/0: added
app/firefox0.level=127 at 2 -> slot_level:firefox0: added
0/output0.level=128 at 3 -> hw:0/0: added
0/input0.level=255 at 4 -> hw:0/64: added
0/input0.mute=0 at 5 -> hw:0/96: added
snd0: 16000Hz, s16le, rec 0:0, 16 blocks of 160 frames
firefox0: 48000Hz, s16le, play 0:1, 4 blocks of 480 frames
firefox0 at default: mode not allowed on this sub-device
snd0: device started
firefox0: attached at -7680 + 0/480
app/aucat0.level=127 at 6 -> slot_level:aucat0: added
aucat0: 48000Hz, s16le, play 0:1, 20 blocks of 480 frames
aucat0 at default: mode not allowed on this sub-device
aucat0: attached at -7680 + 0/480
^Cfirefox0: detached at 0 + 0/160
default/server.device=0:1 at 1 -> opt_dev:default/0: removed
snd0: device stopped
snd0: software master level control enabled
0/output.level=127 at 7 -> dev_master:0: added
0/output.level=127 at 7 -> dev_master:0: removed
Changing back to play-only
mode, the
warning is also gone. Seems that it can be used either in play
mode or rec
mode but not in play,rec
mode
(full-duplex).
sndiod -dd -f rsnd/1 -m play -s default
The last test I made was to mix the rec-only
mode of the speakerphone and play-only
mode with the internal speaker or the
AG03 (which kind of worked).
sndiod -dd -f rsnd/1 -m rec -s default -f rsnd/0 -m play -s out
aucat -f snd/0 -o file.wav
aucat -f snd/1.out -i file.wav
Lessons Learned
Shortly after my tests I need to bring the speakerphone back. This closes that case to some degree. Nevertheless I would take the following three key elements from that journey.
sndiod
is flexible like hell despite its simplicity- no need for external tools to start with audio processing (everything you need is in the base system)
- it highly depends on the device what is working (e.g. a
Yamaha AG03
works like a charm on my system)