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.
pavucontrol to do realtime graphical config changes, including volume adjustments. It takes more config via files in
alsamixer to do realtime volume adjustment and a bit of config, but mostly it depends on a config file which is called
~/.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
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.