Why work at the ALSA level? - A general rant about pulseaudio and friends
(The impatient are invited to skip this section.)
No matter how well-disguised by a GUI, certain aspects of software and hardware setup are necessarily fiddly. We'd like to reduce the fiddle-factor.
I can't speak for everyone. SystemD -- with its RPC protocol dbus, audio routing and soundcard management framework pulseaudio (later replaced by pipewire) -- works for the majority. The majority are using it, and if they are using it, that means it works sufficiently well for them. Except for the edge cases. The SystemD developers are famous for treating bug reports as unwelcome feature requests. Basically, it is a whole new API for managing a Linux system. Also with SystemD came an entire documentation and support ecosystem.
We can say we don't want those millions of lines of code, edge cases and lurking vulnerabilities. So we run devuan. And we can grouse that it was a misrepresentation to say SystemD would bring faster booting (it didn't) and sell it on that basis when in fact the developers had much bigger ambitions. We can't revert history. SystemD is here, a fact, an ecosystem, its binaries running on millions of devices.
So, you've decided to bite the bullet and configure for yourself, not as far as gentoo, but devuan, debian minus some of the above. You can have dbus, pipewire, and every linux desktop environment except gnome. Gnome is being developed hand-in-hand with wayland, the next step in the SystemD path away from legacy linux userland codebase, in this case the X window system. I'll note that means giving up battle tested and well understood software to and migrating to something new. As in the latest version of MacOS or Windows, you are the guinea pig.
Choosing devuan is choosing not to be a guinea pig, choosing to retain a smaller, more stable and better understood software stack.
Getting away from dbus is harder than SystemD because so many GUI programs and others use it for managing system events and notifications, IPC, RPC. I'm not an absolutist: dbus runs on my system. Together with that, a lot of stuff that I don't use runs on my system. We're lucky we can afford it.
Of course, the embedded people can't afford it and won't pay for it. They use software like busybox that requires only a fraction of the lines of code of the unix utilities they replace. They use alternate init systems of which there are a score, many battle tested, providing all the functionality the admin could want, with only the cost of learning the software and understanding the outlines of the problem domain.
So, with a bad taste from pulseaudio taking years to solve bugs and poor design assumptions, I stayed with ALSA, running JACK if necessary, and perhaps programs depending on gstreamer, etc.
Asoundrc, the ALSA configuration file
Having lost you all with this rant, I will now show you an example of solving an ALSA configuration problem yourself.
I got a new HDMI smart TV to use as a monitor, and want to route audio to the TV speakers, for example, from brave, the browser I've been using.
ALSA is configured in $HOME/.asoundrc.
$ cat .asoundrc
defaults.ctl.card 1;
defaults.pcm.card 1;
Now, TBH, I don't even remember this syntax. ALSA syntax is very flexible and I must have found this example somewhere. The two lines set the default audio device to be card index 1.
How soundcards get indexed in linux has historically been a fiddly issue. That's a decent reason to use pulseaudio, you don't need to think about it... except when it doesn't work.
Fortunately, the card indexing usually stays the same absent hardware changes. You can query this information and we'll get to that.
Here is a more common example of asoundrc, in fact, the default configuration.
pcm.!default {
type hw
card 0
}
ctl.!default {
type hw
card 0
}
Probably identical in function to my current asoundrc above except for the soundcard index.
My first try to enable HDMI audio was a utility called 'speaker-test'.
I listed the virtual audio devices using an ALSA utility, aplay.
$ aplay -L
null
Discard all samples (playback) or generate zero samples (capture)
hw:CARD=Generic,DEV=3
HD-Audio Generic, HDMI 0
Direct hardware device without any conversions
hw:CARD=Generic,DEV=7
HD-Audio Generic, VHD32M-0810
Direct hardware device without any conversions
hw:CARD=Generic,DEV=8
HD-Audio Generic, HDMI 2
Direct hardware device without any conversions
plughw:CARD=Generic,DEV=3
HD-Audio Generic, HDMI 0
Hardware device with all software conversions
plughw:CARD=Generic,DEV=7
HD-Audio Generic, VHD32M-0810
Hardware device with all software conversions
plughw:CARD=Generic,DEV=8
HD-Audio Generic, HDMI 2
Hardware device with all software conversions
hdmi:CARD=Generic,DEV=0
HD-Audio Generic, HDMI 0
HDMI Audio Output
hdmi:CARD=Generic,DEV=1
HD-Audio Generic, VHD32M-0810
HDMI Audio Output
hdmi:CARD=Generic,DEV=2
HD-Audio Generic, HDMI 2
HDMI Audio Output
dmix:CARD=Generic,DEV=3
HD-Audio Generic, HDMI 0
Direct sample mixing device
dmix:CARD=Generic,DEV=7
HD-Audio Generic, VHD32M-0810
Direct sample mixing device
dmix:CARD=Generic,DEV=8
HD-Audio Generic, HDMI 2
Direct sample mixing device
hw:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
Direct hardware device without any conversions
plughw:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
Hardware device with all software conversions
sysdefault:CARD=Generic_1
HD-Audio Generic, ALC257 Analog
Default Audio Device
front:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
Front output / input
surround21:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
2.1 Surround output to Front and Subwoofer speakers
surround40:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
4.0 Surround output to Front and Rear speakers
surround41:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
4.1 Surround output to Front, Rear and Subwoofer speakers
surround50:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
5.0 Surround output to Front, Center and Rear speakers
surround51:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
5.1 Surround output to Front, Center, Rear and Subwoofer speakers
surround71:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
dmix:CARD=Generic_1,DEV=0
HD-Audio Generic, ALC257 Analog
Direct sample mixing device
With this multiplicity of choices, you can understand the pulseaudio and later SystemD developer decided that linux audio would be a good domain to get started in.
Here are the lines that concern us:
hdmi:CARD=Generic,DEV=0
HD-Audio Generic, HDMI 0
HDMI Audio Output
hdmi:CARD=Generic,DEV=1
HD-Audio Generic, VHD32M-0810
HDMI Audio Output
hdmi:CARD=Generic,DEV=2
HD-Audio Generic, HDMI 2
HDMI Audio Output
I tried the 'speaker-test' utility to determine which of these devices to set as default. The following made noise out of the TV speaker:
speaker-test -Dhdmi:CARD=Generic,DEV=1 --channels 2
(By trial and error, I found that I needed to specify a channel count of 2. With no channel arguments or setting it to 1 channel of output, it fails with an error.)
Now I have to translate that to asoundrc configuration syntax. Maybe some more information will help.
$ cat /proc/asound/cards
0 [Generic ]: HDA-Intel - HD-Audio Generic
HD-Audio Generic at 0xfd3c8000 irq 102
1 [Generic_1 ]: HDA-Intel - HD-Audio Generic
HD-Audio Generic at 0xfd3c0000 irq 103
2 [acp ]: acp - acp
LENOVO-20UES01R00-ThinkPadT14Gen1
Okay Generic is card 0, and within card 0, speaker-test succeeded when routed to device 1.
But let's test this first. I'll use ecasound.
$ ecasound -i ~/music/tmh.wav -o alsaplugin,0,1
**************************************************************************
* ecasound v2.9.3 (C) 1997-2020 Kai Vehmanen and others
**************************************************************************
(eca-chainsetup) Chainsetup "untitled-chainsetup"
(eca-chainsetup) "rt" buffering mode selected.
(eca-chainsetup) Opened input "/home/me/music/tmh.wav", mode "read". Format: s16_le, channels 2, srate 44100,
... interleaved (locked params).
ERROR: Connecting chainsetup failed: "Enabling chainsetup: AUDIOIO-ALSA: Unable to open ALSA-device for playback; error:
... No such file or directory"
The last line is what matters. This should have worked on the first try!!!
I didn't slam my hand on the table or yell obscenities at my teddy bear.
Calmly, I went through all the subdevices of card 0. Somehow I thought to look at aplay -l.
$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Generic [HD-Audio Generic], device 3: HDMI 0 [HDMI 0]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: Generic [HD-Audio Generic], device 7: HDMI 1 [VHD32M-0810]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: Generic [HD-Audio Generic], device 8: HDMI 2 [HDMI 2]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: Generic_1 [HD-Audio Generic], device 0: ALC257 Analog [ALC257 Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
With this in hand, I soon found I could play audio to device 7:
$ ecasound -i ~/music/tmh.wav -o alsaplugin,0,7
Now I can finally go back to asoundrc.
$ cat .asoundrc
pcm.!default {
type hw
card 0
device 7
}
ctl.!default {
type hw
card 0
device 7
}
So, I'm a happy camper and bob is my dad, not my uncle.
This is an example of the one-time setup needed so that well-behaved programs will know where to route their audio stream.
After restarting, brave browser does correctly route my audio.
I'm not sure about the inconsistency with the speaker-test utility. Worth filing a bug report.