A deep dive into Audio processing on Linux

6–10 minutes

As I am sure you know, I love music – It is my absolute favourite thing on this earth and nothing else makes me feel the way music does. I also love computers (again, if you couldn’t tell). Combining music and computers gives you quite a few cool things;

  • Electronic Music
  • Sampling
  • Sharing music over the internet
  • Streaming music

I want to focus on that last point in this project. Like many other people, I use Spotify Premium. It’s convinient as I can stream music and podcasts in my car, create playlists, find new artists through their DJ and look back at my year with Spotify Wrapped. For the artists and albums I really love however, I often buy them on CD or purchase them digitally on Bandcamp so that I have them in the highest quality format for streaming and archiving.

For the past few years, I have been using Volumio – a custom operating system you can load onto a Raspberry Pi to stream music from a NAS to a DAC or other Hi-Fi system component. This works really well and supports plenty of plugis.

I even paired this up with an official Raspberry Pi 7″ touch screen to create a simple tablet interface for music streaming. This worked great but to be honest, after a while, it was much easier using the software on the Web UI. And, as I like to do from time to time, I wanted to use the Pi for something else.

The question then becomes ‘How can I repalce the existing functionality?’. A few months ago, I switched to using Navidrome – an app that can be run in Docker with all of the same functionality as Volumio but the key difference? Navidrome streams to any device, any where. Volumio only streams to one output device.

This makes Navidrome the best choice for streaming as I can use it on my laptop when I am at home working on my website, stream it in the car on my drive to work but, there is one setback. Navidrome cannot natively output raw data to a USB DAC.

What do we do now?

After doing some digging online, it turns out that getting an audio device to work with Navidrome is quite tricky. This is because;

  • Navidrome does not natively support DAC’s
  • Navidrome is running within a Docker container

This means that we both have to enable Navidrome to output to audio devices over USB and we also have to find a way to pass through an audio device to Linux and then allow it to access the data within a container.

Turns out, Navidrome does have a new mode called ‘Jukebox’ which allows it to connect to system audio devices via the ones exposed by the operating system. And so, with a new tab of ChatGPT open, I navigated the world of audio on Linux.

Finding out if OMV has audio

The first thing to do was to unplug one end of my USB from my old Raspberry Pi into the front of my server, Mayflower. This USB connects my Panasonic PMX82M Hi-Fi system that my brother got me for christmas.

For reference, in order to get this to work on a Windows PC or a Mac, you first need to download Panasonic Audio Driver 2 before the DAC will let you play audio through the digital USB connection. I plugged it in, and ran the following command

Straight away the system detected it and knew that it was a Panasonic audio device. Now that I knew the system could see the DAC, I needed to configure a few things before we could make use of it.

I needed to download the libasound2 audio library.

ChatGPT then advised that before I went any further, I performed a basic test to check that audio was working, even at a very low level. Running this test played a female voice in each speaker – it was working! audio directly being output from my server!

Getting it working in Navidrome

Now as I previously mentioned, one of the hardest things to do is to pass real hardware devices from the host operating system, in this case Open Media Vault, through to a container which runs in a virtualisation engine such as Docker.

Turns out, this requires two simple steps. The first one was to pass the hardware device through to the container. This was done by simply adding a few lines into the Docker compose file.

I also had to enable Jukebox mode and allow the container to access group 29 which in my case is the _audio group on my system.

The second step, again with the help of AI was to create a custom config file for Navidrome, telling it about the new audio device it has access to and how to access it.

With that, I saved it to the navidrome directory, started the container (which for some reason pulled an update? perhaps I changed branches to navidrome:latest) and it was back up and running.

Confusion and Betrayal

Now, at this point, there were two things I had hoped to happen.

  • Audio streams right from the server to my DAC and I get to hear my music.
  • I am given a choice of output devices

Ladies and gentlemen – this was not the case. Turns out, Navidrome does not explicitly show the user a list of output devices nor does it give you the option to manually specify where you want the audio stream to go. Another issue was that whilst Jukebox is supported in Navidrome, not even Navidromes own app or Web UI supports this!

I am now on the hunt for an app that can do this functionality whilst also having the core features and feel of Navidrome. Although it won’t be my main music streaming app, I still want it to feel nice. I tried various apps, substreamer, yuzic but the one that worked best was Narjo.

The app looks stunning, the UI perfectly fits the theme of a high end audio streaming app, includes support for hi-res bit perfect streaming and a bunch of other really nice features.

The thing I wanted though was Jukebox mode so I could play directly from the server to my audio hardware. Finding this was a little bit tricky. I had to dig around in the settings to find Jukebox mode and even then, this would just tell you if it was available or not.

At first, it said that Jukebox was not available, it also said that the Jukebox role was missing from my local Navidrome account. This was conflicting as my Navidrome account was an admin account, meaning I had access to all groups, including Jukebox. This was confirmed by looking at the Navidrome configuration file variables.

The trick to this was to first turn my DAC on (lol should have thought of that) and then restart the app. Once this was done, I was met with the following screen in the Jukebox Debug menu.

Now that both Navidrome and Narjo were happy, it was time to actually play something from the server directly to the DAC over USB.

More betrayal

For some reason, I just could not get the option to stream to the DAC to appear on my app. I had already verified everything else such as that Jukebox was on in the Navidrome.TOML file, my user account had the Jukebox role and that OMV and the container had access to the DAC – I was stumped. Searching online for similar issues did not yeild many results and so I was forced to turn to their discord for support.

I managed to speak with one of the developers and moderators of the server. They asked for the logs from Narjo and once sending them over, they confirmed that everything was working in regards to Narjo being able to talk to Navidrome – the issue was Navidrome could not talk to the DAC.

Despite what ChatGPT would tell me, I had a feeling that something was misconfigured. The device would connect to my server but refuse to play anything. I decided to install the sound drivers directly onto the host machine, rather than relying on the ones provided by Navidrome’s Docker container.

After installing it, it seemed like the DAC would connect and disconnect, making it impossible to play audio through. Testing the device by unplugging it, plugging it back in and spamming

dmesg

In the terminal, it seemed that the device would be identified as being a high speed USB 2 device, an audio device and the device would be connected at a kernel level, but ALSA, Linux’s audio suite, would not assign it an identifier.

In the end, I managed to assign it a unique name that could then be passed from the host OS into the Docker container for Navidrome and then controlled via Narjo.

Victory

After a long and confusing battle with just trying to play music directly from my server, I am pleased to say I now know slightly more about how audio works on Linux. When I hit play on a random album and heard the opening synth to ‘Two Bad’ by 2hollis, I was so happy.

Thanks for reading