Posted on Sat 22 February 2020
Since this class of bug just bit me, I figured I would write it up in the nearly futile hope that it might prevent me from making it again.
This bug is most often evident when we have a software stack that has varying levels of configuration available in each layer, ranging from simple components that are either installed or not to complex components with configuration stored in files.
Today’s example is my home theater computer, which has these relevant layers:
- a television with an HDMI connection to
- a smart receiver (a computer with a set of AV switches, ADCs, DACs, and amplifiers)
- a Linux server connected via HDMI to the receiver
- on the server: A/V output hardware via HDMI
- either ALSA or PulseAudio to manage the sound
- a choice of playback programs that can use ALSA or PulseAudio or either
- and the media that we want to play back
Today’s problem is that PulseAudio is an erratic piece of crap that frequently forgets its own configuration, exits without warning, and chews up CPU time. Oh, sorry, that’s not the problem as such, that’s a sub-problem. The problem is that we would like to play the 5.1-encoded audio tracks from our media in as faithful a manner as we can possibly arrange, with a minimum of extraneous processing. The observed error is that, beyond PulseAudio’s cantankerous obstreperousness, all the available playback programs occasionally-through-frequently end up sending stereo signals instead of 5.1 signals to the smart receiver.
A confounding issue is that the smart receiver has a lot of modes in which it will take a stereo signal and try to decode it into the 7 channels of speakers, and one mode in which it will take either a stereo signal or a 5.1 signal and decode it into 7.
There’s actually a lot of information available at most layers of this stack, so it was not difficult to set the TV to not doing anything weird and get the receiver to display what it was actually receiving in realtime. (Thanks, Yamaha.) That made it clear that the Linux box was sending stereo instead of 5.1. Now all my debugging could go to that set of layers.
My initial assumption was that PulseAudio didn’t recognize the
capabilities of the output and downgraded to stereo as a
most-reasonable-fallback. pavucontrol
told various stories,
including stories about how it knew the full capabilities of the HDMI
outputs, and how audio was being played back via PulseAudio emulating
ALSA. Obviously the first thing to try was to set the software to use
PulseAudio directly. Unfortunately, it said that it was already doing
that.
This is where the bug comes in.
PulseAudio has pavucontrol
to do realtime graphical
config changes, including volume adjustments. It takes more config via
files in /etc/pulse/
or ~/.pulse/
.
ALSA has alsamixer
to do realtime volume adjustment and
a bit of config, but mostly it depends on a config file which is called
/etc/asound.conf
or ~/.asoundrc
. Yes, that is
a stupid difference. VLC offers built-in configuration, in both an easy
mode and a complete mode, and also a config file located at
~/.config/vlc/vlcrc
.
PulseAudio and ALSA do not change any of their config files when a
human adjusts things through the realtime config interfaces. VLC does,
but the displayed information does not use the same nomenclature that
the config files do. Where the realtime config might show you an output
device named “HDMI-1, Intel PCH, 5.1”, that is not a string you can
write into alsa-output-device:
in the config file. In
addition, there are things that can be changed in the config file which
are not obviously changeable in the realtime config.
So, the bug: you can get a working config that is not written to a file and will not work some period of time later – after a program restart, or after a system reboot, or after PulseAudio crashes because it hates you.
Part two of the bug: you can write a config value that consistently takes effect after one of those events, but does not show up in the realtime config.
The solution for this particular problem has been to disable
PulseAudio entirely, use /etc/asound.conf
to pick the HDMI
output as the default output device, and remove several lines in
vlcrc
of unknown origin which reassigned channels
badly.