Introducing aloopd - the ALSA Loop Sound Server

Aka, who needs the stinking pulseaudio?




Motivation

All over many years, I only had one soundcard in my machines. I configured it once, and there it went. No further tweaking was ever needed. If I needed alternate sound output - just plug in a headphone to the headphone jack. Nothing else was needed, ALSA takes care of everything.

When laptops started to support HDMI output, a problem arose. The HDMI output in effect was a second soundcard; so all these new-fangled laptops now had two soundcards. It was not a problem in itself, except that the kernel had no idea which was was to be the "default". Often times, the HDMI output was chosen as the default soundcard (over the "more correct" analog output jack), and since the laptop HDMI's port was not connected to anything, the result is an absolute silence when the user tried to play some audio apps.

To address this problem, Kirk invented Multiple-Sound-Card-Wizard (MSWC) to allow the user to choose which soundcard he/she wanted to use as the default. This settings was persisted over reboots, so the user only had to configure it once. MSCW was quickly adopted by Puppy Linux world, and its derivatives still lives on until today.

In Fatdog, MSCW was replaced with "fatdog-default-soundcard.sh" (FDS) - which worked exactly like the original MSCW except that it had more options and more features (e.g. equaliser, pre-amp, stereoswap, etc).

And then came bluetooth speakers. The FDS was updated to support these as well, so audio apps could route the audio to these speakers too. Now, unlike the analog out/HDMI selection, which was usually set only once and then never touched again, with bluetooth speakers one might want to connect to it one day, and disconnect and use the internal speaker the other day.

FDS supported this - but, after each changes, the audio app had to be restarted. If you're watching a video you had to quit the video player, make the change using FDS, and re-started. A bit annoying, but not too bad you only had to do it once a day.

And then came USB soundcards. That's okay, we could still ignore that. And then come USB headphones. These are headphones whose cables are permanently soldered to USB soundcards, the only way to make them make sound, is to connect their USB connections to USB ports and then run FDS to set the configuration.

This now means that over the course of the day, one might want/need to change the "default" soundcard many times - perhaps to route over the internal soundcard, then to bluetooth speakers/headset, then to USB headphones, etc ... FDS still works, but if one has to restart the audio app everything this happens, it starts to get more and more annoying.

The solution to avoid re-starting the audio apps is to use a "audio router", a middleman that takes the output from an audio app, and then send it to the correct destination (internal soundcard, bluetooth speakers, USB devices, etc). These "audio routing" function is done by a "sound server", of which pulseaudio is the most well know notorious example, but there are others too (JACK for real-time audio, older/defunct ones like EsoundD/ESD, aRts, etc).

All these sound servers suffer from the same problem: the applications must be explicitly programmed to use them. Apps that uses PulseAudio have to use PulseAudio API and link with PulseAudio libraries, same for JACK, and all the others too. And therein lies the problem.
1) If you don't have these libraries at run-time, the app goes kaput.
2) Even if you do, in case the "sound server" cannot run properly at run-time, you won't hear any sound.

And PulseAudio, while being the most popular soundserver in this decade (due to it being pushed down the throat on many distributions, just like systemd is), isn't exactly the most stable or the easiest one to configure. If you need proof, just use your favourite search engine and see how many questions there are about "PulseAudio not working" ...

Anyway, as I said, in days past, I only had one soundcard, so the need to do all these was non-existent - if one only has one soundcard, what's really the need of having a middleman? So, I was never bothered about this for long while ...

Until now. Recently got a USB headphone. With a regular headphone, you plug in the jack to the hole, and it all works (the sound on the laptop was turned off and redirected to the headphone). This was by the way done by the __hardware__ (the audio codec chip), there is no "sound server" in the kernel that does this.

However, things aren't the same with USB audio. As I said above, it is effectively a different soundcard, so FDS needs to be called to configure the app to use it, and then the audio app has to be restarted ...

And thus is born the ALSA Loop Sound Server.




The ALSA Loop Sound Server

As it turns out, ALSA has already come with a sound server of sorts.
It's primitive compared to others, but for me, it does the job fine enough.

My objective is only one: I want to be able to switch sound output without having to shutdown and restart the audio apps. I can live with the interruption during the switching, I can live with the fact that different soundcards have different mixer (volume) control etc (although this apparently can be automated as well - I haven't tried it).

The ALSA Sound Server consist of two components: the kernel module component called snd-aloop (ALSA Loopback module), and the user-space program called "alsaloop". ALSA Loopback module basically acts are virtual soundcard and acts are a "pipe" - audio data goes from one part, and out into another. "alsaloop" acts like a pump - it read data from one card, and output it to another.

The entire setup is conceptually simple:
- use snd-aloop to create a virtual soundcard and make it as the default output.
- run alsaloop, which reads audio from this virtual soundcard, and push it out the actual soundcard.

So the audio routing becomes like this:
app --> loopback virtual soundcard --> alsaloop --> actual soundcard.

But what have we achieve with this middle-man setup? Well, the magic of this setup is that even if "alsaloop" is not running, the audio app will continue to blissfully send its output - except that of course you hear no sound.

To hear any sound, run the "alsaloop" pump, and if you want to switch output, just kill alsaloop and re-start it with different output. Presto!

This implementation is available on Fatdog64 812.

It is capable of switching audio seamlessly between internal soundcards and bluetooth speakers, without restarting the sound apps.




Beyond Fatdog64 812

After the release of Fatdog64 812, I worked a little bit more on the ALSA Sound Server and it is now capable of delivering __network__ audio, using a neat package called "trx" (available in the Fatdog repository).

It is now possible to send audio over the network, and receive audio from the network. Using multicast, it possible to send a single stream to multiple listeners at once.

All using only ALSA (and trx).

This implementation will be available on next release of Fatdog, whenever that will be. If you are keen to test, you can always get the "tip" version of Fatdog, which gets updated whenever there is an interesting feature (or update).



Posted on 9 Dec 2021, 16:15 - Categories: Fatdog64 Linux
Edit - Delete


No comments posted yet.

Add Comment

Title
Author
 
Content
Show Smilies
Security Code 8671680
Mascot of Fatdog64
Password (to protect your identity)