Audio Backends - librespot-org/librespot GitHub Wiki

librespot supports various audio backends. Multiple backends can be enabled at compile time by enabling the corresponding cargo feature. By default, only Rodio is enabled.

See the Compiling page for information on building specific backends into librespot.

Usage

--backend Is used to select the audio playback engine.

The following backends are currently available:

  • Rodio (Default)
    • Uses Alsa on Linux, so development packages are required to build
    • MacOS and Windows should work out of the box
  • Alsa --backend alsa
    • Linux build dependencies: libasound2-dev on Debian and alsa-lib-devel on Fedora
  • PortAudio --backend portaudio
  • PulseAudio --backend pulseaudio
  • JACK Audio --backend jackaudio
  • JACK Audio over Rodio --backend rodiojack
  • SDL --backend sdl
  • pipe --backend pipe and subprocess --backend subprocess
    • Always included during compilation, require something to read stdout or an external executable to playback the audio.
  • GStreamer --backend gstreamer

--device Is used to select a specific audio device. Some backends will list available audio devices when passing --device ?.

Most backends don't require specific setup and try to have sane defaults.

Alsa

The right device needs to be passed to librespot via the --device flag. The alsa terminology of hw:X,Y is used, where X is the card number, and Y is the device number. This can be determined by:

~/librespot$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC3234 Analog [ALC3234 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 9: HDMI 3 [HDMI 3]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 10: HDMI 4 [HDMI 4]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

# To determine the right mixer name for your card, try
~/librespot$  amixer --device "hw:0" --card "0" # Results truncated here 
Simple mixer control 'Master',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 87
  Mono: Playback 64 [74%] [-17.25dB] [on]
Simple mixer control 'Headphone',0
  Capabilities: pswitch
  Playback channels: Front Left - Front Right
  Mono:
  Front Left: Playback [off]
  Front Right: Playback [off]
Simple mixer control 'PCM',0
  Capabilities: pvolume
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 255
  Mono:
  Front Left: Playback 2 [1%] [-50.60dB]
  Front Right: Playback 2 [1%] [-50.60dB]

Thus, in this example the settings would be:

./target/release/librespot [] --backend alsa  \
        --device="hw:0,0" \
        --mixer="alsa" --alsa-mixer-device="hw:0" --alsa-mixer-control="Master" \

NOTE: You might want to turn on the linear volume mapping --volume-ctrl linear when utilising a hardware mixer with Librespot

pipe

The pipe backend requires very minimal setup provided you have an audio player which can accept and process the output correctly.

By default, the pipe outputs the data as raw stereo 16-bit 44.1 kHz as bytes. The bit depth can be increased with the --format option. If the option --passthrough is set, then pipe outputs the raw Ogg data. This is true for any bitrate (quality) setting.

The passthrough decoder copies the entire encoded audio to stdout, untouched. Multiple tracks are chained and will be recognized as independent 'streams' (per Ogg format). Seeking within one track will extend or shorten it, but it will remain the same Ogg 'stream'. Skipping will shorten the current track and start a new Ogg 'stream' but the 'end of stream' flag for the skipped track will be missing. It is a slight non-conformity to Ogg format although all tested players accept it.

GStreamer

The GStreamer backend sends raw PCM audio to any arbitrary GStreamer pipeline. You can define the pipeline using the device option to librespot.

If you specify the GStreamer backend but omit the device option, the default device will be ! audioconvert ! autoaudiosink. This basically tells GStreamer to determine what your "default" audio device is for your platform, and play the sound back normally using that. As of this writing, that usually means:

  • The default DirectSound playback device on Windows;
  • The default playback device on macOS;
  • PulseAudio on Linux if it's available, otherwise Alsa, otherwise it'll keep trying audio backends based on which plugins you have installed and eventually give up if it can't figure out what to use.

This behavior is subject to change as GStreamer makes changes to the behavior of their "autoaudiosink" code.

Specifying the GStreamer device option

To customize the back end of the GStreamer pipeline, you need to learn a bit about pipeline syntax. Here are some great examples. This behavior is not unique to librespot; we are using the same pipeline parsing engine as gst-launch-1.0.

Very important: The first characters of your device parameter should be either whitespace, or an exclamation mark !. So prepending any amount of whitespace is fine, because GStreamer ignores whitespace in pipeline syntax, but the first non-whitespace character must be !.

After that first !, the first element you declare will be receiving some type of audio samples (by default 16-bit signed integer, can be changed using the --format option), interleaved PCM audio samples with a sample rate of 44100 Hz and two channels. In most cases, just sticking an ! audioconvert or -- at worst -- ! audioconvert ! audioresample in the start of your pipeline should cause GStreamer to perform any necessary format conversion so that your downstream pipeline elements can use the data being passed in.

You can test your custom pipeline code independent of librespot using gst-launch (usually gst-launch-1.0 on most systems) as follows:

gst-launch-1.0 audiotestsrc ! <your pipeline backend>

Your pipeline backend can contain any arbitrary number of elements that do processing, as well as any sink supported by GStreamer.

The pipeline "preamble" that is hard-coded into librespot is the following:

appsrc caps="audio/x-raw,format={}LE,layout=interleaved,channels=2,rate=44100" block=true max-bytes=4096 name=appsrc0, where {} is substituted with the output format (S16 by default).

Basically, you're going to get audio in the format listed in the caps parameter above to the "left-most" element in your custom device pipeline.

Here are some full examples of invoking librespot with GStreamer.

  1. Send audio out to DirectSound on Windows

From a cmd shell: librespot.exe -u 12345 -p password -n kitchen --backend gstreamer --device "! audioconvert ! directsoundsink"

  1. Change the pitch of the audio to 90% of its original pitch and send audio out to PulseAudio on Linux

From a bash/zsh shell: ./librespot -u 12345 -p password -n kitchen --backend gstreamer --device '! audioconvert ! pitch pitch=0.9 ! audioconvert ! pulsesink'

You should note that in both Bash and Windows CMD, I put quotes around the pipeline content. The reason is that librespot expects the entire device to be read in as a single argument to librespot, so if you have any spaces in the pipeline that get interpreted by the shell as argument separators, it won't work.

Here is an INCORRECT example that does not properly quote the device argument:

  1. INCORRECT: ./librespot -u 12345 -p password -n kitchen --backend gstreamer --device ! audioconvert ! alsasink

Why GStreamer?

If you just want to play audio out to a sound backend that is already supported by the existing librespot backends, there is no reason to use GStreamer. In fact, GStreamer might introduce additional latency that is absent from some of the more "direct" audio backends like the Alsa backend.

The librespot GStreamer backend exists for those who want to do processing on the audio that comes out of librespot, or who want to pipe it to sound backends that are not supported natively by other librespot backends.

A few obvious examples of processing include:

  • Changing the pitch, tempo or speed of the audio.
  • Equalizers.
  • Visualization (yes, GStreamer supports visualization plugins).
  • AGC, adding audio watermarks, mixing in audio from other sources, etc.

A few obvious examples of sinks include:

  • Piping the audio to a novel audio backend that isn't supported well or at all otherwise; example, PipeWire.
  • Customizing the audio device or the properties (like sample rate, etc.) for the audio backend of your choice. This could be really useful if you want to change the sample rate to the "native" sample rate of your hardware; some Alsa devices either don't support resampling, or don't support the sample rate you're trying to play back, for instance.

To truly understand the capabilities of audio processing and sinks in GStreamer, you need to look at the GStreamer plugins list here.

This is just a start, though. There are many proprietary, as well as system-specific GStreamer plugins that have been written over the years. A lot of smartphones and embedded chipsets have GStreamer elements for processing and/or output, and some of these are "non-standard" and wouldn't work with other librespot plugins.

A caveat about GStreamer Plugin Availability

Not every build/installation of GStreamer is created equal. Depending on your platform, and the elements that your GStreamer installation has available, you may not be able to run some or any of the pipeline examples here.

You should be aware that upstream GStreamer maintains the following major plugin "bundles":

  • gst-plugins-base: These are the true "core" plugins of GStreamer; without these, the librespot GStreamer backend won't work.
  • gst-plugins-good: A bundle of well-supported and tested plugins that are fully compatible with the core GStreamer license.
  • gst-plugins-bad: A bundle of less well-supported plugins that are fully compatible with the core GStreamer license. Some of these might be very stable and well-tested, but they may end up staying in -bad for legacy reasons (it would break a lot of code if they move a -bad plugin to -good). Some of these may coincidentally work, but lack a maintainer.
  • gst-plugins-ugly: A bundle of plugins with licensing issues. Basically, it might violate some law somewhere if you distribute certain ones of these plugins with the rest of GStreamer due to license compatibility and/or patent issues. Some of the -ugly plugins no longer have licensing issues, but remain here again for compatibility reasons. Consult a lawyer if you are in doubt; this Wiki does not provide legal advice.

These three plugin bundles do not consist of all GStreamer plugins that have ever been written, but they do contain the majority. For the other system-specific ones that may or may not exist for your operating system or hardware, consult your hardware or OS vendor.

If you are running a modifiable system and can rebuild GStreamer itself or some of these plugin libraries from source code, or install them from your package manager, you may be able to "add on" more GStreamer plugins by installing one or more of these plugin bundles.

For example, on Ubuntu or Debian, you can use apt to search for gst-plugins or gstreamer and install the requisite plugin packages to get many more plugins than may be installed by default.