SlimStreamer: Multiroom Streamer That Does Not Resample

Hi,

The step that puzzles me most is the loopback devices, I simply don’t understand why they are necessary:

# add loopback devices, two are needed because only one subdevice is allowed > check with aplay -l | grep Loopback echo "options snd-aloop enable=1,1 index=1,2 pcm_substreams=8,8 id=Loopback1,Loopback2" | sudo tee /etc/modprobe.d/alsa-loopback.conf

Two loopback devices are created, but I don’t get how they are used. Are they referred to in code? I mean the command names them “Loopback1” and “Loopback2”. Does it still work if I call them “LB1” and “LB2”?

What I think it does is send all PCM streams to both loopback devices automatically, but I know too little about ALSA to actually know for sure.

I think I understand the asound.conf; that just makes the slimplexor the default output ‘device’.

The good part is I have successfully installed SlimStreamer, I find that it logs quite much (which is good for testing :slight_smile: ), but it runs and I can hear sound from squeezelite. Playing an mp3 file gave me static using aplay, I had to set the format… Maybe I made a mistake, a wav-file gave me no trouble at all.

So the next step is to actually make sure that mpd/airplay/spotify etc. output to ALSA.

Update: some quick testing gave me the following results when configuring MPD to use the default device instead of hw.

AIF(F) 44.1kHz 16 bit: no problem
MP3 any bitrate: volume very low
DSD64 2.82MHz: no sound
FLAC 192kHz 24 bit: no sound

The HD formats seem to throw buffer overflow errors and then crash:

2018/02/19 19:56:31.242310 DEBUG [1925375056] (Streamer.hpp:177) {proto} - Delivered chunk all the clients (size=153600, clinets=1) 2018/02/19 19:56:31.343031 DEBUG [1925375056] (Streamer.hpp:177) {proto} - Delivered chunk all the clients (size=153600, clinets=1) 2018/02/19 19:56:44.101120 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.205260 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.301131 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.401478 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.509047 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.609747 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.704076 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.801184 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:44.901184 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.001168 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.103833 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.201158 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.301227 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.401175 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.501254 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.601094 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.701128 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.801147 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:45.901222 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.001128 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.101088 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.201220 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.301187 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.401159 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.501201 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.601108 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.701191 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.801528 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:46.901191 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.001177 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.101163 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.201315 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.301274 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.401249 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.501237 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.601295 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.701215 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.801729 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:47.901367 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:48.008182 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:48.111207 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:48.201581 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:48.310670 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped 2018/02/19 19:56:48.410275 ERROR [1802499152] (Pipeline.hpp:98) {slim} - Buffer overflow error: a chunk was skipped Killed

MPD config:

[code]resampler {
plugin “soxr”
quality “high”
threads “1”
}

audio_output {
type “alsa”
enabled “yes”
name “alsa”

device “hw:1,0”

            dop                     "no"

}
[/code]

Hello Saiyato

Great stuff, you made it work, congrats! Thank you for so much valuable feedback. I need to digest it and provide you the answers. For now, let me explain about Loopback devices used by SlimStreamer.

When an app (like aplay) sends PCM audio to a default ALSA device, ALSA uses SlimPlexor to send the actual PCM audio (because you tell ALSA to do so in asound.conf file). Think of SlimPlexor as a DLL that runs within a context of original app (say aplay).

SlimStreamer is a separate independent process that has its own context, somehow it needs to receive PCM audio from SlimPlexor. This is what Loopback devices are used for: they are used to transfer PCM data between different LINUX processes (like pipe or sockets). Loopback devices allow one process to write data to one end and other process will get the same data from other end (just like pipe). One essential difference from pipes or sockets is that Loopback devices will do throttling: they will transfer PCM data based on sampling rate defined (in case of pipe data will flow as fast as OS allows). This is essential feature to ensure near-Real-Time playback.

Let me know if it is still unclear for you :wink:

Thanks for the explanation, I will try to draw what my mind understands and see if I can upload it. I do have more understanding of the matter now. :slight_smile:

A little bit of extra information, I’m testing on a Raspberry Pi 3B with an Audiophonics Sabre V3 HAT + OLED LCD (which can influence performance I guess) + sufficient power (iFi).

After some reading I think I understand what is happening.

PART 1
Any application generating sound and using default ALSA as output will be pushing sound into one of the 32 subdevices of the two loopback cards (4 loopback devices). This is managed by SlimPlexor, an ALSA plugin, which requires the snd_aloop module of ALSA.

At this point no sound will be sent to the hardware device, since ALSA’s default PCM output device is the SlimPlexor plugin.

PART 2
All sound sent to either one of the 32 subdevices of the four loopback devices is detected by SlimStreamer, which then will send it to all connected clients.

Is or will meta data be supported? E.g. for jivelite? :slight_smile:

Hi, just wondering if there’s been any developments on this? I think I speak for many users that having Volumio with good multiroom capabilities would be incredible.

Br

In case anyone is still interested, I recently (26 Apr 2024) downloaded the code and after a bit of a hack (some of the dependacies were out of whack with the baseline code) I managed to compile SlimStreamer and the ALSA plugin SlimPlexor as well as give it a basic test against squeezelite.

This was done on a recent Ubuntu image and will also do this on a Fedora image so this has most common Linux platforms covered (Debian/Ubuntu/RedHat) [sure suse is common but not something you see at the consumer level]

Worked ok for the limted testing I did.

I will do some extended testing over the next few days including playing around with the command line switches to see if they work as advertised.

Note the last changes to the baseline code was mid Jan 2020.

For my own purposes, I reduced support for the “never seen in real life” sample rates (8000;11025;12000;16000;22500;24000;32000;) which meant I only needed to configure one ALSA loopback set.

Thus in my version the supported rates are: 44100;48000;88200;96000;176400;192000;

The instructions on the git website related to ALSA setup are messy and duplicitous but I have a good handle now on what really is needed.

The main issue with the code is that the ALSA loopback devices it uses are hard coded which suggests that the best strategy currently is to load the ALSA loopbacks at boot time so they will always be the first devices created so the hard coded ALSA config in the source code can match.

Upshot is I can provide whomever wants it a tarball of an install image that has all the dependancies installed so a compile is very simple. As noted above, I removed the never seen sample rates from my version to simplify the ALSA loopbacks but can provide the tarball with the original supported rates.

Will also supply my suggested ALSA config steps and the compile notes including changing the ALSA device numbers to suit your own purposes (In case you dont want to load the loopbacks at boot time)

One other change I need to make is to add a startup switch to SlimStreamer to reduce the log output… its way to chatty as supplied.

I see you can upload into a thread so once I have a new stable version I will upload the tarball (its small)

Peter

PS1: I am not voluntering to support this long term… just providing an install image that easily compiles and fix up any obvious issues and add the debug startup switch to reduce logging output

PS2: It might be possible to remove the hardcoded ALSA device requirement by using an ENV variable to point to the loopback device card(s). For example, we could do “export SLIMCARD=1” at startup (given the rest of the tree is linear from that point) so it could be seen by both components if our loopbacks were say:

card 1: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
card 1: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM

PS3: The data stream is your playback software addresses the ALSA default device which is the ALSA I/O plugin SlimPlexor. This then routes the data stream down one loopback input device from a set of ALSA input loopback devices (one for each supported sample rate) which is then read on the corresponding output loopback device by the SlimStreamer program which then sends a valid SlimProto stream to the Squeezebox player

just a test post to see if tracking is set

well… it works at the most basic level (i.e. aplay -D slimplexor test.wav) BUT (I assume due to the way it buffers data) it has lots of latency when used with playback software.

So when you start playing an album it takes a few seconds before the 1st track starts (maybe you could live with that) but if you then move to another track while the current track is playing then it takes ~20 seconds to switch (again I assume cause its draining its buffer of the previous track).

Its strange that such a basic requirement as speedy reaction to track switches isnt supported.

So my enthusiasm has diminished. Will see if I can resolve this but I imagine given the buffer design that it wont be a quick fix.

Peter