Netzwerk-Streaming mit PulseAudio

26. Februar 2022 · Anwendungen · andreas · Kein Kommentar

Manchmal wäre es ganz schön, die Audioausgabe des eigenen PCs auf einem anderen Gerät wie z.B. der heimischen Stereoanlage ausgeben zu können.

Während dem Verlegen von langen Kabeln physikalische (und ggf. auch ästhetische) Grenzen gesetzt sind und Bluetooth je nach Gerätestandort den Weg nicht störunsgfrei überbrücken kann, bietet sich ein Rasperry Pi an, der- entweder über LAN oder WiFi angebunden - die Ausgabe übernimmt.

Ein Raspberry Pi der ersten Generation ist hierfür vollkommen ausreichend, ebenso wie eine SD-Karte mit 4GB Speicherplatz.

Sofern auf dem PC Linux eingesetzt wird, lässt sich das Projekt mit wenig Aufwand und Bordmitteln realisieren. Die meisten aktuellen Linux-Distributionen setzen für die Audioausgabe auf PulseAudio, welches die benötigte Funktionalität bereits mitbringt.

Vorbereitung Raspberry Pi

Als Betriebssystem wird Raspberry Pi OS in der “Lite”-Variante verwendet, welches ein funktionsfähiges Basisbetriebssystem ohne grafische Oberfläche bereitstellt. Das Image wird von der offiziellen Website heruntergeladen und anschließend der “SHA256 file integrity hash” verifiziert:

$ sha256sum 2021-10-30-raspios-bullseye-armhf-lite.zip 008d7377b8c8b853a6663448a3f7688ba98e2805949127a1d9e8859ff96ee1a9 2021-10-30-raspios-bullseye-armhf-lite.zip

Sofern der Hash übereinstimmt, sollte mit dem Download alles geklappt haben und das heruntergeladene Image vollständig und fehlerfrei sein.

Nun wird die zu verwendende SD-Karte eingelegt und das verwendete Gerät ermittelt:

$ sudo fdisk -l ... Disk /dev/sdb: 7,5 GiB, 8053063680 bytes, 15728640 sectors Disk model: SD Transcend

Nachdem das Gerät ermittelt wurde (im Beispiel “/dev/sdb”) kann nun das heruntergeladene Betriebssystemimage auf die SD-Karte geschrieben werden. Im nachfolgenden Befehl ist “/dev/sdb” durch das soeben ermittelte Gerät zu ersetzen.

“dd” (über)schreibt ohne weitere (Rück)fragen - lieber einmal zu oft schauen, ob das Gerät auch tatsächlich die SD-Karte ist, statt sich über Datenverlust zu ärgern.
$ unzip -p 2021-10-30-raspios-bullseye-armhf-lite.zip | sudo dd of=/dev/sdb bs=4M conv=fsync status=progress 1764360192 Bytes (1,8 GB, 1,6 GiB) kopiert, 11 s, 160 MB/s 0+29824 Datensätze ein 0+29824 Datensätze aus 1954545664 Bytes (2,0 GB, 1,8 GiB) kopiert, 247,918 s, 7,9 MB/s $ sync

Bevor die Karte in den Raspberry Pi eingelegt wird, wird noch der SSH-Server aktiviert

For headless setup, SSH can be enabled by placing a file named ssh, without any extension, onto the boot partition of the SD Card. When the Raspberry Pi boots, it looks for the ssh file. If it is found, SSH is enabled and the file is deleted. The content of the file does not matter; it could contain text, or nothing at all. [Quelle]

Dies kann von der Kommandozeile aus erledigt werden, “/dev/sdb” wieder durch das ermittelte Gerät zu ersetzen.

$ mkdir /tmp/raspiboot $ sudo mount /dev/sdb1 /tmp/raspiboot $ sudo touch /tmp/raspiboot/ssh $ sudo umount /tmp/raspiboot

Anschließend kann die Karte entnommen und in den Raspberry Pi eingesetzt werden.

Grundkonfiguration Raspberry Pi

Der erste Start des Systems dauert etwas, da hierbei das Dateisystem an die Größe der SD-Karte angepasst und einige weitere Dinge eingerichtet werden.

The default user is pi, and the password is raspberry. [Quelle]

Anschließend kann eine Anmeldung über SSH am Raspberry Pi erfolgen.

$ ssh pi@raspberrypi ... pi@raspberrypi:~ $ passwd ... passwd: password updated successfully

Nachdem die Anmeldung erfolgreich war, sollte als erstes eine Änderung des Standardkennworts mittels “passwd” erfolgen und anschließend eine Aktualisierung des Systems durchgeführt werden:

$ sudo apt update ... $ sudo apt upgrade ... $ sudo apt autoremove --purge ... $ sudo reboot

Nach dem Neustart des Systems kann es dann an die Installation und Konfiguration von PulseAudio gehen.

Installation und Konfiguration PulseAudio

Als erstes müssen die benötigten Pakete heruntergeladen und installiert werden

$ sudo apt install pulseaudio pulseaudio-module-zeroconf pulseaudio-utils

Nach der Installation werden einige Konfigurationsdateien angelegt bzw. angepasst.

Zuerst die Datei “/etc/default/pulseaudio”,

/etc/default/pulseaudio
PULSEAUDIO_SYSTEM_START=1 DISALLOW_MODULE_LOADING=0

dann die Datei “/etc/asound.conf”

/etc/asound.conf
pcm.pulse { type pulse } ctl.pulse { type pulse } pcm.!default { type pulse } ctl.!default { type pulse }

sowie die Datei “/etc/pulse/default.pa”, wobei “aaa.bbb.ccc.0/24” durch das eigene Netz zu ersetzen ist:

/etc/pulse/default.pa
# folgende Zeile auskommentieren # load-module module-suspend-on-idle # folgende Zeilen am Ende der Datei hinzufügen load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;aaa.bbb.ccc.0/24 auth-anonymous=1 load-module module-zeroconf-publish

Standardmäßig legt PulseAudio zwei verschiedene Konfigurationsdateien ("/etc/pulse/default.pa" und “"/etc/pulse/system.pa”) an, die je nach Startkontext verwendet werden. Um vor allem während der Testphase etwas copy & paste zu sparen, wird die eine Datei als Link zur anderen definiert:

$ sudo mv /etc/pulse/system.pa /etc/pulse/system.pa.dist $ sudo ln -s /etc/pulse/default.pa /etc/pulse/system.pa

Die Empfehlung ist, PulseAudio im Benutzerkontext auszuführen, was unter “What is wrong with system mode?” genauer erläutert wird. Trotzdem wird der System-Modus konfiguriert, da der Raspberry Pi ja nach Systemstart ohne angemeldeten Benutzer als Ausgabegerät zur Verfügung stehen soll.

In einem ersten Schritt wird PulseAudio für die Ausführung (bei Bedarf) als normaler Benutzer deaktiert. Nachdem die Abschaltung mittels “disable” nicht zuverlässig funktionierte und PulseAudio sporadisch doch wieder nach Anmeldung im Benutzermodus gestartet wurde, half ein zusätzliches “mask” zur dauerhaften Deaktivierung.

$ systemctl --user stop pulseaudio $ systemctl --user disable pulseaudio $ systemctl --user mask pulseaudio

Als Ersatz wird ein Systemdienst konfiguriert, welcher den Start übernimmt. Hierzu wird eine Datei “/etc/systemd/system/pulseaudio.service” mit folgendem Inhalt angelegt:

/etc/systemd/system/pulseaudio.service
[Unit] Description=PulseAudio System Service After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/bin/pulseaudio --daemonize=no --exit-idle-time=-1 --disallow-exit=true --system Restart=always [Install] WantedBy=default.target

Die Parameter “After=” und “Wants=” sorgen dafür, daß der Dienst erst dann gestartet wird, wenn das Netzwerk online ist, wobei im Zweifelsfall “up” nicht gleich “up” ist.

network-online.target is a target that actively waits until the nework is “up”, where the definition of “up” is defined by the network management software. [Quelle]

Damit das Warten funktioniert, muß sichergestellt sein, daß auch der entsprechende Wartedienst aktiviert wurde:

The right “wait” service must be enabled too (NetworkManager-wait-online.service if NetworkManager is used to configure the network, systemd-networkd-wait-online.service if systemd-networkd is used, etc.). [Quelle]

Ohne grafische Oberfläche sollte dies “systemd-networkd-wait-online.service” sein, der zum Installationszeitpunkt deaktivert ausgeliefert wurde:

$ systemctl is-enabled NetworkManager-wait-online.service Failed to get unit file state for NetworkManager-wait-online.service: No such file or directory $ systemctl is-enabled systemd-networkd-wait-online.service disabled $ sudo systemctl enable systemd-networkd-wait-online.service Created symlink /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service → /lib/systemd/system/systemd-networkd-wait-online.service.

Anschließend wird der soeben definierte Dienst aktiviert und gestartet.

$ sudo systemctl enable pulseaudio ... $ sudo systemctl start pulseaudio

Damit alles wie gewünscht eingelesen und aktiviert wird, wird der Raspberry Pi neu gestartet, anschließend sollte der Raspberry Pi zur Ausgabe bereitstehen.

Da PulseAudio als Systemdienst mit dem Benutzer “pulse” läuft, muss ein Aufruf von “pacmd” mit Angabe des Benutzers und Pfades erfolgen:

sudo PULSE_RUNTIME_PATH=/var/run/pulse -u pulse pacmd

Damit ist dann die Konfiguration des Dienstes weiterhin über die Kommandozeile möglich.

Installation lokaler Arbeitsplatz

Auf dem lokalen Arbeitsplatz gestaltet sich die Installation und Konfiguration deutlich einfacher und schneller.

Es muß lediglich (sofern noch nicht geschehen) das Programm “paprefs” installiert

$ sudo apt install paprefs

und anschließend in der Konfiguration der Haken bei “PulseAudio Netzwerk-Audio-Geräte im lokalen Netzwerk auffindbar machen” gesetzt werden:

Sofern alles richtig konfiguriert wurde, sollte unter “Einstellungen” / “Audio” nun der Raspberry Pi als Ausgabegerät “Build in Analog Stereo on …” auswählbar sein.

Optionaler Schritt: Dateisysteme nur lesend einbinden

Standardmäßig sind die Dateisysteme für Lese- und Schreibzugriff eingebunden. Im Einsatz als Streamingclient kann dies den ein- oder anderen Systemcrash nach sich ziehen, wenn der Raspberry Pi im laufenden Betrieb ausgeschaltet und nicht sauber heruntergefahren wird.

Die schon mehr als sieben Jahre alte Anleitung aus dem Blog-Beitrag “Raspberry Pi als Streamingclient für die Synology Audio Station” kann zwar noch als Grundlage dienen, damit der Player reibungslos läuft, sind allerdings noch ein paar zusätzliche Einträge in der Datei “/etc/fstab” notwendig.

Zuerst wird eine Datei “resolv.conf” an einen Ort verschoben, an dem sie auch weiterhin noch bearbeitet werden kann

$ sudo mv /etc/resolv.conf /tmp/resolv.conf $ sudo ln -s /tmp/resolv.conf /etc/resolv.conf

dann wird die Datei “/etc/fstab” bearbeitet.

Während “proc” unverändert bleiben kann, wird bei den beiden Einhängepunkten “/” und “/boot” jeweils die Option “ro” vor “defaults” eingefügt. Ein paar weiter Verzeichnisse werden als temporäres Dateisystem eingehängt, Grundlage für die erweiterte Liste war der Beitrag “Raspberry Pi mit schreibgeschütztem Linux betreiben” aus der Zeitschrift c’t (Ausgabe 16/2021). Beim Parameter “PARTUUID=” ist “***” durch die korrekte UUID zu ersetzen.

/etc/fstab
proc /proc proc defaults 0 0 PARTUUID=***-01 /boot vfat ro,defaults 0 2 PARTUUID=***-02 / ext4 ro,defaults,noatime 0 1 tmpfs /var/lib/systemd tmpfs mode=0755 0 0 tmpfs /var/lib/pulse tmpfs mode=0700 0 0 tmpfs /var/lib/private tmpfs mode=0700 0 0 tmpfs /var/log tmpfs nodev,nosuid 0 0 tmpfs /var/tmp tmpfs nodev,nosuid 0 0 tmpfs /var/cache tmpfs nodev,nosuid 0 0 tmpfs /tmp tmpfs nodev,nosuid,mode=1777 0 0

Als letztes muß noch der Parameter “ro” in der Datei “/boot/cmdline.txt” zwischen “root=” und “rootfstype=” hinzugefügt werden.

/boot/cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=***-02 ro rootfstype=ext4 fsck.repair=yes rootwait ipv6.disable=1

Nach einem Neustart sollte spontaner Stromentzug dem Dateisystem des Raspberry Pi nichts mehr ausmachen.

Optionaler Schritt: HifiBerry aktivieren

Die Treiber für den HiFiBerry sind bereits im Raspbian-Kernel enthalten, müssen aber bei Systemstart noch aktiviert werden. Dies ist auf der Seite “Configuring Linux 4.x or higher” des HiFiBerry-Blogs beschrieben.

Für einen Raspberry Pi 3 mit Dac+ sehen die Änderungen wie folgt aus:

/boot/config.txt
# folgende Zeile auskommentieren # dtparam=audio=on # folgende Zeile hinzufügen dtoverlay=hifiberry-dacplus

Daß alles richtig geladen wurde, kann mittels “aplay” verifiziert werden:

$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 [HifiBerry DAC HiFi pcm5102a-hifi-0] ...

Optionaler Schritt: ipv6 deaktivieren

Sofern nicht benötigt, kann das standardmäßig aktivierte Protokoll ipv6 durch hinzufügen von “ipv6.disable=1” in der Datei “/boot/cmdline.txt” deaktiviert werden.

/boot/cmdline.txt
# am Zeilenende hinzufügen ipv6.disable=1

Viel Spaß beim Musik hören …

Aktualisierungen:
2022-06-28: Aufruf für “pacmd” hinzugefügt
2022-03-18: Anpassung der Berechtigungen in der Datei fstab für Ordner “/var/lib/pulse”
2022-03-08 : Abschnitt “Installation und Konfiguration PulseAudio” erweitert, Abschnitt “Dateisysteme nur lesend einbinden” erweitert, Abschnitt “ipv6 deaktivieren” hinzugefügt.