Perfect Linux Audio

by Richard Kolkovich

As a dabbling audiophile, I’ve never been able to get my audio setup completely perfect. I need to balance my everyday - music while coding, Skype calls, browser audio (TED, Youtube, Hangouts) - with the ability to listen to audio without software mixing when desired.

With the buildout of marle, I believe I have my setup as close to perfect as can be.

Hardware

I use my laptop’s microphones all the time. The wrench in the works, however, is the desire to use my USB DAC while at my desk and my laptop’s soundcard when I’m mobile.

High Quality

The world of high-quality audio is an unmitigated rabbit hole. Without restraint, you will quickly acquire a collection of headphones, DACs, amps, and a heaping pile of debt to go with it.

The long and short of it, however, is that you want the highest quality audio (uncompressed files, higher bitrates) you can find presented to the highest-quality DAC you have access to. This is where computers make it tricky. To be able to listen to the meowing of that cute cat on Youtube while chatting with your sister on Skype requires your operating system to mix audio streams on your behalf. Once this happens, you have already lost the quality battle.

For software to mix disparate audio streams, they must be resampled to the same frequency and bitrate. This mixed stream is then sent to your DAC (be it onboard sound or an external device). If your source material (music) is at a different bitrate than the remixed rate, the source has to be resampled in software before being sent to your DAC. This added step has the potential to drop the final analog quality substantially.

To ensure that software only transmits the source material, one bit at a time, to your DAC, your music player must directly and exclusively access the hardware. By doing this, you can no longer mix cat videos and your sister’s Skype call.

Without using two sets of speakers/headphones, you must have the ability to give your music player exclusive access to your DAC, preferably without too much hassle.

Switching

To be able to switch between desktop mode and audiophile mode, I wrote a script to tell MPD to use either the mixed output or access my DAC directly. Running a script when I want to listen to my music in all its glory is fine by me, as this is typcially a once-per-day affair at the most.

ALSA

Previously, I had a close-but-not-perfect ALSA-only setup. I followed the Two Cards as One guide with much success. Some applications, however, ignored ALSA and grabbed the hardware anyway (VirtualBox, WINE). Chrome also had a tendency to have an open channel on some tab preventing my mpc switching script from working.

Additionally, this setup no longer works on marle when I disconnect the DAC (i.e. when I’m mobile). I’m not sure if this is due to an ALSA update or the fact that it never should have worked.

PulseAudio

Ugh. I have avoided PulseAudio like the plague throughout my entire life running Linux and FreeBSD on my desktop. It had some serious growing pains, and it always seemed to break more than it fixed. Alas, it is, in theory, the best solution for this application.

Combined audio

Open up /etc/pulse/default.pa and add:

load-module module-combine-sink sink_name=combined
set-default-sink combined

Now, restart pulse:

killall pulseaudio

And bask in the glory of PulseAudio actually doing something useful.

Switching

If nothing is using Pulse, my mpc_switch script works a treat. If not, there is luckily a handy utility to suspend Pulse:

pasuspender -- sleep 365d

You’re supposed to provide an app to pasuspender, so I just leave it hanging in a terminal with sleep (for now) and kill it when I’m done with my listening session.

Speakers

By default, this setup is outputting to my DAC + headphones as well as my laptop speakers. This is slightly annoying, but I already have a “docking script” which runs when I connect/disconnect my external monitor. It’s a simple matter to mute/unmute the onboard sound as appropriate with:

pacmd set-sink-mute alsa_output.pci-0000_00_1b.0.analog-stereo 1

You can find your sink name via:

pacmd list-sinks | grep name:

mpd

I was running mpd as a system daemon, and this obviously doesn’t work with the PulseAudio model. The mpd user fired up its own Pulse, and nothing worked. To remedy this, I simply start mpd from my user account.

cp /etc/mpd.conf ~/.mpd.conf
<edit user and group>
mpd ~/.mpd.conf

Cheers!

Edit: Shortly after publishing this post, I discovered that I can easily suspend PulseAudio using pactl. I have updated my mpc_switch script to eliminate the pasuspender step. w00t!