Full Metal ALSA

Full Metal ALSA - The Most Minimal Linux Sound Setup

In this post, I am going to tell you how I got "pure ALSA"* working on Artix Linux (I know this will also work on Arch Linux, and assumedly other Arch based distros, for as long as "apulse" and "lib32-apulse" are in the AUR).

*: ALSA is the only operational sound server on the system; however, as some applications require Pulseaudio, the command 'apulse' is used as a translation layer, so the applications think they are using pulseaudio, and ALSA behaves in a more friendly way, but it is still just ALSA.

0x0: Remove competing sound servers

Competing sound servers can and will ruin your day, if you intend to just use ALSA. Pipewire simply being installed prevents ALSA from loading properly, Pulseaudio continually reloads, and JACK siezes the audio device and won't let any other audio system use it. So, if you want to use just ALSA, you have to remove all of the others.

0x0.1: Fix your audio default device

Most of my laptops (intel and AMD) have loaded the HDMI audio driver before the actual onboard soundcard, and as a result, ALSA selects the HDMI device as the default output. If you have this issue, it can be fixed by changing the default ALSA card in your ~/.asoundrc, HOWEVER, I believe that a more proper fix would be to change the order the drivers are loaded, by adding a file at "/etc/modprobe.d/alsa.conf", with the line "options snd_hda_intel index=1,0" (replace snd_hda_intel with the driver in question, for me, this has been the issue every time). This solves the problem at the source.

0x01: Build apulse

As apulse is in the AUR, you can either use an AUR helper (yay, paru, trizen), or git clone the repo (apulse). During this step, if applicable, your AUR helper should install the dependencies for you; if you are using "makepkg", use the "-s" flag to install the dependencies before hand (and the -i flag to install the package after compilation is finished).

0x02: Install apulse package

If using an AUR helper, it should do this step for you when apulse is done compiling. If using makepkg, using the "-i" flag should also call pacman to do this as well. However, if neither of these is the case, you can simply use "sudo pacman -U <location of .pkg.tar.zst>" to install it.

0x03: Build lib32-apulse (if necessary)

Note: This step (and the next one) are only necessary if you need 32 bit apulse support, i.e. if you intend to use multilib applications, like Steam or WINE. If you only use x64 applications, you don't need to do this. As this is the only use case, this guide will assume you already have the 32 bit repos enabled.

This step is the same as before, but with "lib32-apulse" instead of "apulse" (the repo is here).

0x04: Install lib32-apulse (if necessary)

At the time of writing this, there is an additional step to finish this, because both "apulse" and "lib32-apulse" own the file /usr/share/man/man1/apulse.1.gz. This step would be best fixed by removing the file from one or the other repos; however, as I am not a maintainer for either, I can fix this on my end by manually giving the command "pacman -U <location of .pkg.tar.zst> --overwrite /usr/share/man/man1/apulse.1.gz", HOWEVER this is not a great solution, as the file has to be overwritten every time either package upgrades. The best fix would be for one of the maintainers to remove the unnecessary man page.

0x05: Copy the generic config file

The package provides a standard ALSA config file at /usr/share/apulse/asoundrc.sample, which should be copied to your "~/.asoundrc" if you don't already have one.

0x06: Profit! Ish

Now, you have apulse properly installed! However, you still have to manually run it before every application you want to use pulse emulation with. Not exactly ideal. However, if you use .desktop files to launch your apps, you can edit them and add "apulse" between the "Exec=" and name of the binary (so, for example, "Exec=firefox" turns into "Exec=apulse firefox"), or you can re-link the binary to use apulse instead of libpulse, which I may demonstrate how to do at a later date, or you can write a script and place it earlier in your PATH than the actual binary, and make it run apulse followed by the actual binary (so, if your PATH includes $HOME/.local/bin:/usr/local/bin:/usr/bin, and you want to call firefox, which is at /usr/bin/firefox, you could write a script called "firefox", which contains the lines:

#!/bin/sh

exec apulse /usr/bin/firefox

in $HOME/.local/bin/firefox, then whenever you type the command "firefox" it will automatically run "apulse firefox" for you.


2021-08-06