OpenMultiroom: Unterschied zwischen den Versionen

Aus FHEMWiki
(Snapcast und Mopdy hinzugefügt)
(Maintainer update, Hinweis auf akutelleres Modul)
 
(13 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt)
Zeile 13: Zeile 13:
|ModForumArea=Multimedia
|ModForumArea=Multimedia
|ModTechName=96_Snapcast.pm
|ModTechName=96_Snapcast.pm
|ModOwner=unimatrix
|ModOwner=Beta-User ({{Link2FU|9229|Forum}}/[[Benutzer Diskussion:Beta-User|Wiki]])
}}
}}
[[Datei:OpenMultiroomOverview.png|mini|400px|Schaubild des Zusammenspiels der einzelnen Komponenten eines Multiroomsystems mit den Backends [https://forum.fhem.de/index.php/topic,18517.msg MPD] und [https://forum.fhem.de/index.php/topic,62389.0.html Snapcast] sowie der Nutzung von Text2Speech]]
[[Datei:OpenMultiroomOverview.png|mini|400px|Schaubild des Zusammenspiels der einzelnen Komponenten eines Multiroomsystems mit den Backends {{Link2Forum|Topic=18517|LinkText=MPD}} und {{Link2Forum|Topic=62389|LinkText=Snapcast}} sowie der Nutzung von Text2Speech]]
</div>
</div>


Achtung: Dieser Wiki-Artikel und auch das beschriebene Modul sind noch in der Implemntierung und noch nicht verfügbar.
Achtung: Das Modul ist noch in der Entwicklung und bisher nur im {{Link2Forum|Topic=65785|LinkText=Forum}} bzw. auf dem [https://github.com/unimatrix27/fhemmodules/blob/master/98_OpenMultiroom.pm Github des ursprünglichen Autors] (beide veraltet) oder aktualisiert im {{Link2Forum|Topic=128206|LinkText=Forum}} verfügbar.  


'''OpenMultiroom''' ist ein Steuerungsmodul sowie auch ein Gesamtkonzept zur Realisierung eines Multiroom-Audio-Systems unter Nutzung von ausschließlich frei verfügbarer Software und ohne Bezug auf die Hardware eines bestimmten Herstellers. Es ist so ausgelegt, dass es prinzipiell flexibel bezüglich der Auswahl der Backendsysteme ist. Zurzeit ist es für die Nutzung mit [https://www.musicpd.org/ MPD] bzw. [https://www.mopidy.com/ Mopidy] und [https://github.com/badaix/snapcast Snapcast] implementiert. Daher wird in diesem WIKI-Eintrag immer von diesen Systemen gesprochen. Einen grundsätzlichen Überblick über das Konzept bietet das Schaubild.
'''OpenMultiroom''' ist ein Steuerungsmodul sowie auch ein Gesamtkonzept zur Realisierung eines Multiroom-Audio-Systems unter Nutzung von ausschließlich frei verfügbarer Software und ohne Bezug auf die Hardware eines bestimmten Herstellers. Es ist so ausgelegt, dass es prinzipiell flexibel bezüglich der Auswahl der Backendsysteme ist. Zurzeit ist es für die Nutzung mit [https://www.musicpd.org/ MPD] bzw. [https://www.mopidy.com/ Mopidy] und [https://github.com/badaix/snapcast Snapcast] implementiert. Daher wird in diesem WIKI-Eintrag immer von diesen Systemen gesprochen. Einen grundsätzlichen Überblick über das Konzept bietet das Schaubild.
Zeile 24: Zeile 24:
== Grobe Übersicht des Funktionsumfangs der Gesamtlösung==
== Grobe Übersicht des Funktionsumfangs der Gesamtlösung==
=== Features ===
=== Features ===
* Integrierte Steuerung des Musikplayers über das [https://forum.fhem.de/index.php/topic,18517.msg MPD]-Modul sowie des Multiroom-System [https://forum.fhem.de/index.php/topic,62389.0.html Snapcast] in einem einzigen Modul
* Integrierte Steuerung des Musikplayers über das [[MPD]]-Modul sowie des Multiroom-System {{Link2Forum|Topic=62389|LinkText=Snapcast}} in einem einzigen Modul
* Implementierung einer Schnittstelle gemäß [[DevelopmentGuidelinesAV]] als Basis für eine Visualisierung mit z.B. [[SmartVisu]] oder [[FHEM_Tablet_UI]]
* Implementierung einer Schnittstelle gemäß [[DevelopmentGuidelinesAV]] als Basis für eine Visualisierung mit z.B. [[SmartVISU]] oder [[FHEM Tablet UI]]
* Synchrones Playback auf z.B. Raspberry Pi oder Android-Geräten (Snapcast-Feature)
* Synchrones Playback auf z.B. Raspberry Pi oder Android-Geräten (Snapcast-Feature)
* optionale Komprimierung der Soundübertragung als OGG oder FLAC (Snapcast-Feature)
* optionale Komprimierung der Soundübertragung als OGG oder FLAC (Snapcast-Feature)
* Möglichkeit der Bedienung völlig ohne Display über eine Fernbedienung und entsprechender Text2Speech Rückmeldung, insbesondere
* Möglichkeit der Bedienung völlig ohne Display über eine Fernbedienung und entsprechender Text2Speech Rückmeldung, insbesondere
** Durschalten von Playlisten mit entsprechenden Channel - Tasten unter Nutzung von raumspezifischen Filtern
** Durschalten von Playlisten mit entsprechenden Channel - Tasten unter Nutzung von raumspezifischen Filtern
** Forward und Rewind mit definierbaren Sprungweiten (implementiert direkt im [https://forum.fhem.de/index.php/topic,18517.msg MPD]-Modul)
** Forward und Rewind mit definierbaren Sprungweiten (implementiert direkt im [[MPD]]-Modul)
** Direktanwahl von Playlisten, Tracks oder Trackpositionen durch Zifferneingabe und anschließende Funktionstaste
** Direktanwahl von Playlisten, Tracks oder Trackpositionen durch Zifferneingabe und anschließende Funktionstaste
** Abfrage von Statusinformationen durch Funktionstasten und Text2Speech Rückmeldungen
** Abfrage von Statusinformationen durch Funktionstasten und Text2Speech Rückmeldungen
** Mithören in anderen Räumen und Übernahme des Playerzustandes anderer Räume durch Nutzung von Funktionstasten
** Mithören in anderen Räumen und Übernahme des Playerzustandes anderer Räume durch Nutzung von Funktionstasten
** Einschlaftimer per Zifferneingabe oder per vordefinierten Zeitabständen, hierbei wird auch die Restlaufzeit des aktuellen Tracks angeboten.
** Einschlaftimer per Zifferneingabe oder per vordefinierten Zeitabständen, hierbei wird auch die Restlaufzeit des aktuellen Tracks angeboten.
* manuelles oder automatisches Speichern und Laden von Playlistbookmarks (implementiert direkt im [https://forum.fhem.de/index.php/topic,18517.msg MPD]-Modul)
* manuelles oder automatisches Speichern und Laden von Playlistbookmarks (implementiert direkt im [[MPD]]-Modul)
* Möglichkeit der Festlegung von tageszeit- und tagestypabhängigen Lautstärkebegrenzungen bis auf 0% z.B. für Kinderzimmer
* Möglichkeit der Festlegung von tageszeit- und tagestypabhängigen Lautstärkebegrenzungen bis auf 0% z.B. für Kinderzimmer
* individuelles Verwalten von Playlisten für verschiedene Familienmitglieder
* individuelles Verwalten von Playlisten für verschiedene Familienmitglieder
Zeile 51: Zeile 51:
Durch das Modul '''OpenMultiroom''' steuert der Nutzer sowohl MPD als auch Snapcast. Für jeden Raum wird eine Instanz des Moduls definiert.  
Durch das Modul '''OpenMultiroom''' steuert der Nutzer sowohl MPD als auch Snapcast. Für jeden Raum wird eine Instanz des Moduls definiert.  


=== verwendete komponenten ===
=== Verwendete Komponenten ===
Folgende Komponenten kommen zum Einsatz:
Folgende Komponenten kommen zum Einsatz:


Zeile 62: Zeile 62:
* FHEM: Modul 98_OpenMultiroom.pm
* FHEM: Modul 98_OpenMultiroom.pm
* FHEM: Modul 96_Snapcast.pm
* FHEM: Modul 96_Snapcast.pm
* FHEM: Modul 73_MPD.pm
* FHEM: Modul [[MPD|73_MPD.pm]]
* FHEM: Optional Modul 98_Text2Speech.pm
* FHEM: Optional Modul 98_Text2Speech.pm


Zeile 71: Zeile 71:
* Webbrowser zur Steuerung per Visualisierung
* Webbrowser zur Steuerung per Visualisierung
* ggf. Infrarot oder Funkfernbedienung. In diesem Artikel wird das Beispiel anhand der Nutzung von X10-Funkfernbedienungen gezeigt, diese gibt es sehr günstig in der Bucht o.ä.
* ggf. Infrarot oder Funkfernbedienung. In diesem Artikel wird das Beispiel anhand der Nutzung von X10-Funkfernbedienungen gezeigt, diese gibt es sehr günstig in der Bucht o.ä.
* Vision: Nutzung von Tastern und Display am PI oder Nutzung eine Steuergerätes mit Tastern und Display auf Basis eines Arduino mit WLAN, z.B. im alten Gehäuse eines Küchenradios usw.  
* Vision: Nutzung von Tastern und Display am PI oder Nutzung eines Steuergerätes mit Tastern und Display auf Basis eines Arduino mit WLAN, z.B. im alten Gehäuse eines Küchenradios usw.  




Zeile 87: Zeile 87:


=== Pulseaudio Konfiguration ===
=== Pulseaudio Konfiguration ===
Will man Pulseaudio verwenden, z.B. um Text2Speech Nachrichten in laufende Musik einzublenden, sollte dieses am besten zuerst konfiguriert werden. Pulseaudio muss hierzu im System-Mode laufen. Dies ist auf einem Headless-Server kein Problem. Bei Ubuntu 16.10 wird dies durch folgenden Inhalt in <em>/etc/systemd/system/pulseaudio.server</em> erreicht:
Will man Pulseaudio verwenden, z.B. um Text2Speech Nachrichten in laufende Musik einzublenden, sollte dieses am besten zuerst konfiguriert werden. Pulseaudio muss hierzu im System-Mode laufen. Dies ist auf einem Headless-Server kein Problem. Bei Ubuntu 16.10 wird dies durch folgenden Inhalt in ''/etc/systemd/system/pulseaudio.service'' erreicht:
<source lang="bash">
<syntaxhighlight lang="bash">
[Unit]
[Unit]
Description=PA
Description=PA
Zeile 105: Zeile 105:
[Install]
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
</source>
</syntaxhighlight>
Weiterhin ist der Befehl
Weiterhin ist der Befehl
<source lang="bash">sudo systemctl enable pulseaudio</source>
<syntaxhighlight lang="bash">sudo systemctl enable pulseaudio</syntaxhighlight>
einzugeben, um Pulseaudio beim Systemstart automatisch zu starten.
einzugeben, um Pulseaudio beim Systemstart automatisch zu starten.


Ausgehend von der Standardkonfiguration werden nun in  <em>/etc/pulse/system.pa</em> die benötigten Module eingetragen
Ausgehend von der Standardkonfiguration werden nun in  ''/etc/pulse/system.pa'' die benötigten Module eingetragen
<source lang="bash">
<syntaxhighlight lang="bash">
load-module module-pipe-sink file=/tmp/wohn.fifo  sink_name=wohn
load-module module-pipe-sink file=/tmp/wohn.fifo  sink_name=wohn
load-module module-pipe-sink file=/tmp/kind1.fifo  sink_name=kind1
load-module module-pipe-sink file=/tmp/kind1.fifo  sink_name=kind1
Zeile 120: Zeile 120:
load-module module-combine-sink slaves=wohn,kueche sink_name=unten
load-module module-combine-sink slaves=wohn,kueche sink_name=unten
load-module module-combine-sink slaves=wohn,kueche,kind1,kind2 sink_name=alle
load-module module-combine-sink slaves=wohn,kueche,kind1,kind2 sink_name=alle
</source>
 
Snapcast benötigt die Audioquelle in Form von FIFOs. Daher wird hier in den erstem 4 Zeilen je ein FIFO von Pulseaudio erzeugt. Der sink_name wird später bei der Konfiguration von MPD als Ausgang verwendet. In den 3 letzten Zeilen werden noch 3 weitere Sinks als Combine-Sinks erstellt. Diese erzeugen keine neuen FIFOs, sondern machen under entsprechenden Sink-Namen eine vorgegebene Kombination von Räumen nach außen hin verfügbar. Der Sink "alle" kann also genutzt werden, um Audio auf allen 4 FIFOs gleichzeitig abzuspielen (und somit später potentiall in allen Räumen gleichzeitig). Dies kann für Announcements sinnvoll sein. Die Nutzung dieser Combine-Sinks ist optional.
pactl load-module module-role-ducking trigger_roles=announcement ducking_roles=music
</syntaxhighlight>
Snapcast benötigt die Audioquelle in Form von FIFOs. Daher wird hier in den erstem 4 Zeilen je ein FIFO von Pulseaudio erzeugt. Der sink_name wird später bei der Konfiguration von MPD als Ausgang verwendet. In den 3 weiteren Zeilen werden noch 3 Sinks als Combine-Sinks erstellt. Diese erzeugen keine neuen FIFOs, sondern machen unter entsprechenden Sink-Namen eine vorgegebene Kombination von Räumen nach außen hin verfügbar. Der Sink "alle" kann also genutzt werden, um Audio auf allen 4 FIFOs gleichzeitig abzuspielen (und somit später potentiell in allen Räumen gleichzeitig). Dies kann für Announcements sinnvoll sein. Die Nutzung dieser Combine-Sinks ist optional. Ebenso optional ist das Laden des Ducking-Moduls am Ende. Das Ducking Modul führt dazu, dass Pulseaudio automatisch die Lautstärke der durch MPD abgespielten Tracks absenkt, wenn etwas über die Text2Speech-Module abgespielt wird. Ohne dies sind die Ausgaben speziell über die Google API unter Umständen nur schwer hörbar.


=== Snapcast Konfiguration ===
=== Snapcast Konfiguration ===
[https://github.com/badaix/snapcast Snapcast] muss entsprechend der Angaben auf der Webseite installiert werden. Auf dem Server muss logischerweise die Serverkomponente und auf den Clients die Clientkomponente installiert werden. Bei Android-Clients wird die auf der Webseite zur Verfügung gestellt APK installiert. Snapcast befindet sich selbst noch in fortlaufender Entwicklung. Die hier vorgestellte Lösung ist mit [https://github.com/badaix/snapcast/tree/98be8a58d945f84af50e40ebcf8a774592dd6e7b dieser Version] kompatibel und getestet.  
[https://github.com/badaix/snapcast Snapcast] muss entsprechend der Angaben auf der Webseite installiert werden. Auf dem Server muss logischerweise die Serverkomponente und auf den Clients die Clientkomponente installiert werden. Bei Android-Clients wird die auf der Webseite zur Verfügung gestellt APK installiert. Snapcast befindet sich selbst noch in fortlaufender Entwicklung. Die hier vorgestellte Lösung ist mit [https://github.com/badaix/snapcast/tree/98be8a58d945f84af50e40ebcf8a774592dd6e7b dieser Version] kompatibel und getestet.  


Die Konfiguration des Servers beschränkt sich auf die Definition der Streams in <em>/etc/default/snapserver</em>
Die Konfiguration des Servers beschränkt sich auf die Definition der Streams in ''/etc/default/snapserver''
<source lang="bash">
<syntaxhighlight lang="bash">
START_SNAPSERVER=true
START_SNAPSERVER=true
SNAPSERVER_OPTS="-d -s pipe:///tmp/kind1.fifo?name=kind1&mode=read -s pipe:///tmp/kind2.fifo?name=kind2&mode=read -s pipe:///tmp/wohn.fifo?name=wohn&mode=read -s pipe:///tmp/kueche.fifo?name=kueche&mode=read"
SNAPSERVER_OPTS="-d -s pipe:///tmp/kind1.fifo?name=kind1&mode=read -s pipe:///tmp/kind2.fifo?name=kind2&mode=read -s pipe:///tmp/wohn.fifo?name=wohn&mode=read -s pipe:///tmp/kueche.fifo?name=kueche&mode=read"
</source>
</syntaxhighlight>
Hier werden die 4 Streams erstellt, diese entsprechen vom Dateinamen her der Pulseaudiokonfiguration. Der hier verwendete Name kann später in FHEM oder auch im Android-Client angezeigt werden. Die Option <pre>mode=read</pre> ist wichtig, weil Pulseaudio meckert, wenn es die FIFO-Dateien nicht selbst anlegen darf.  
Hier werden die 4 Streams erstellt, diese entsprechen vom Dateinamen her der Pulseaudiokonfiguration. Der hier verwendete Name kann später in FHEM oder auch im Android-Client angezeigt werden. Die Option <pre>mode=read</pre> ist wichtig, weil Pulseaudio meckert, wenn es die FIFO-Dateien nicht selbst anlegen darf.  


Auf der Clientseite sieht die Datei <em>/etc/default/snapclient</em> dann so aus:
Auf der Clientseite sieht die Datei ''/etc/default/snapclient'' dann so aus:
<source lang="bash">
<syntaxhighlight lang="bash">
START_SNAPCLIENT=true
START_SNAPCLIENT=true
SNAPCLIENT_OPTS="-d -s dmix:CARD=Aureon51MkII,DEV=0"
SNAPCLIENT_OPTS="-d -s dmix:CARD=Aureon51MkII,DEV=0"
</source>
</syntaxhighlight>
Den Server findet der Snapclient automatisch, er kann aber auch angegeben werden. Wie hier zu sehen kann ein spezielles Output-Device angegeben werden. Dies ist bei den PIs mit externer USB-Soundkarte meistens notwendig, da ansonsten der interne Sound genutzt würde. Eine Liste der verfügbaren Devices wird mit dem Aufruf von <pre>snapclient -l</pre> ausgegeben, hier muss dann das passende genommen werden. GGf. so lange ausprobieren, bis der Sound an der richtigen Stelle rauskommt.
Den Server findet der Snapclient automatisch, er kann aber auch angegeben werden. Wie hier zu sehen kann ein spezielles Output-Device angegeben werden. Dies ist bei den PIs mit externer USB-Soundkarte meistens notwendig, da ansonsten der interne Sound genutzt würde. Eine Liste der verfügbaren Devices wird mit dem Aufruf von <pre>snapclient -l</pre> ausgegeben, hier muss dann das passende genommen werden. GGf. so lange ausprobieren, bis der Sound an der richtigen Stelle rauskommt.


Zeile 148: Zeile 150:
In diesem Beispiel wird Mopidy als MPD-Ersatz verwendet, genau so gut kann aber auch direkt MPD verwendet werden. Die genauen Konfigurationsoptionen sind natürlich anders, und jeweils in entsprechenden Tutorials oder Dokumentationen beschrieben. Mopidy ist relativ umfangreich und modular aufgebaut, es bietet u.a. die Möglichkeit, neben lokal gespeicherten Dateien auch Dateien von verschiedenen, teilweise kommerziellen, Streamingdiensten abzuspielen. Die Detailkonfiguration all dieser Komponenten geht über diesen Artikel hinaus. Entscheidend hier ist die Konfiguration in einer Weise, so dass mehrere Mopidy-Instanzen gleichzeitig ausgeführt werden können und dann auf unterschiedlichen Ports zur Verfügung stehen.  
In diesem Beispiel wird Mopidy als MPD-Ersatz verwendet, genau so gut kann aber auch direkt MPD verwendet werden. Die genauen Konfigurationsoptionen sind natürlich anders, und jeweils in entsprechenden Tutorials oder Dokumentationen beschrieben. Mopidy ist relativ umfangreich und modular aufgebaut, es bietet u.a. die Möglichkeit, neben lokal gespeicherten Dateien auch Dateien von verschiedenen, teilweise kommerziellen, Streamingdiensten abzuspielen. Die Detailkonfiguration all dieser Komponenten geht über diesen Artikel hinaus. Entscheidend hier ist die Konfiguration in einer Weise, so dass mehrere Mopidy-Instanzen gleichzeitig ausgeführt werden können und dann auf unterschiedlichen Ports zur Verfügung stehen.  


Nach Installation von Mopidy findet sich die Konfiguration in der Datei <em>/etc/mopidy/mopidy.cfg</em>. Mopidy unterstützt hierarische Konfigurationen, es reicht also, den für jede Instanz spezifischen Teil aus dieser allgemeinen Konfiguration zu entfernen und in jeweils eigene Dateien zu verschieben. In diesem Beispiel sollen das die Dateien <em>/etc/mopidy/kind1.conf</em> bis <em>/etc/mopidy/kueche.conf</em> sein. Die folgenden Zeilen gehören jeweils in diese 4 Dateien und werden dort entsprechend angepasst. Hier das Beispiel für Kind2:
Nach Installation von Mopidy findet sich die Konfiguration in der Datei ''/etc/mopidy/mopidy.cfg''. Mopidy unterstützt hierarische Konfigurationen, es reicht also, den für jede Instanz spezifischen Teil aus dieser allgemeinen Konfiguration zu entfernen und in jeweils eigene Dateien zu verschieben. In diesem Beispiel sollen das die Dateien ''/etc/mopidy/kind1.conf'' bis ''/etc/mopidy/kueche.conf'' sein. Die folgenden Zeilen gehören jeweils in diese 4 Dateien und werden dort entsprechend angepasst. Hier das Beispiel für Kind2:


<source lang="bash">
<syntaxhighlight lang="bash">
[logging]
[logging]
config_file = /etc/mopidy/logging_kind2.conf
config_file = /etc/mopidy/logging_kind2.conf
Zeile 156: Zeile 158:


[audio]
[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! pulsesink  device=kind2
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! pulsesink  device=kind2 stream-properties="props,media.role=music"


[mpd]
[mpd]
Zeile 168: Zeile 170:
port=6681
port=6681
zeroconf = Musik Kind2
zeroconf = Musik Kind2
</source>
</syntaxhighlight>


Im Audioteil wird der entsprechende Sink aus der Pulseaudiokonfiguration genommen. Beim MPD muss der Port für jede Instanz unterschiedlich sein, ebenso beim HTTP-Modul für die Weboberfläche der jeweiligen Instanz. Der Zerokonfname sollte auch eindeutig sein. Neben dieser Datei ist noch die dazu passende logging-Konfiguration anzulegen, hier also <em>/etc/mopidy/logging_kind2.conf</em>. Dazu wird die Standarddatei kopiert und darin nur der Name der Logdatei angepasst.
Im Audioteil wird der entsprechende Sink aus der Pulseaudiokonfiguration genommen. Die Angabe von stream-properties ermöglicht dem Duck-Modul den Stream als Musik zu erkennen und beim Abspielen von Announcements in der Lautstärke abzusenken. Beim MPD muss der Port für jede Instanz unterschiedlich sein, ebenso beim HTTP-Modul für die Weboberfläche der jeweiligen Instanz. Der Zerokonfname sollte auch eindeutig sein. Neben dieser Datei ist noch die dazu passende logging-Konfiguration anzulegen, hier also ''/etc/mopidy/logging_kind2.conf''. Dazu wird die Standarddatei kopiert und darin nur der Name der Logdatei angepasst.


Um nun auch die entsprechende Anzahl Instanzen automatisch zu starten, sind die entsprechenden Startdateien anzulegen. Dazu kann die Datei <em>/etc/systemd/system/mopidy.cfg</em> z.B. in <em>/etc/systemd/system/mopidy_kind1.cfg</em> umbenannt werden und dann 3 mal mit den Endungen der anderen Instanzen kopiert werden. Der Inhalt ist dann wie folgt:
Um nun auch die entsprechende Anzahl Instanzen automatisch zu starten, sind die entsprechenden Startdateien anzulegen. Dazu kann die Datei ''/etc/systemd/system/mopidy.cfg'' z.B. in ''/etc/systemd/system/mopidy_kind1.cfg'' umbenannt werden und dann 3 mal mit den Endungen der anderen Instanzen kopiert werden. Der Inhalt ist dann wie folgt:


<source lang="bash">
<syntaxhighlight lang="bash">
[Unit]
[Unit]
Description=Mopidy_kind1
Description=Mopidy_kind1
Zeile 192: Zeile 194:
[Install]
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
</source>
</syntaxhighlight>


Abschließend sollten die 4 Instanzen durch den Aufruf von <pre>systemctl enable mopidy_kind1</pre> usw. aktiviert werden. Es empfiehlt sich nach dem Start von Mopidy die korrekte Funtkionsweise mit dem [https://www.musicpd.org/clients/mpc/ MPC]-Client oder mit [http://rybczak.net/ncmpcpp/ NCMPCPP] auf der Konsole zu testen.
Abschließend sollten die 4 Instanzen durch den Aufruf von <pre>systemctl enable mopidy_kind1</pre> usw. aktiviert werden. Es empfiehlt sich nach dem Start von Mopidy die korrekte Funtkionsweise mit dem [https://www.musicpd.org/clients/mpc/ MPC]-Client oder mit [http://rybczak.net/ncmpcpp/ NCMPCPP] auf der Konsole zu testen.


Hierbei sollte es dann bereits möglich sein, die Multiroom-Fähigkeiten von Snapcast mit Hilfe des Android-Clients von Snapcast zu testen und so auch festzustellen, dass die restliche Konfiguration von Snapcast und Pulseaudio korrekt sind.  
Hierbei sollte es dann bereits möglich sein, die Multiroom-Fähigkeiten von Snapcast mit Hilfe des Android-Clients von Snapcast zu testen und so auch festzustellen, dass die restliche Konfiguration von Snapcast und Pulseaudio korrekt sind.  
=== FHEM ===
In FHEM sind nun in der ''fhem.cfg'' die entsprechenden Module einzurichten:
* Ein Snapcast-Modul im Server Modus
* Pro Raum ein Snapcast-Modul im Clientmodus
* Pro Raum ein MPD-Modul
* Pro Raum ein OpenMultiroom-Modul
* Optional pro Raum ein Text2Speech-Modul
* weitere Text2Speech-Module, falls man diese in Pulseaudio mit dem per Combine-Sink vorgesehen hat.
<syntaxhighlight lang="bash">
define          scs.snap              Snapcast
define          scc.kind1            Snapcast          client scs.snap b827eb9aec84
  attr          scc.kind1            constraintDummy  freestring
  attr          scc.kind1            constraints      standard|07:00 0 20:00 100 21:00 50 21:30 30 24:00 0,beforefree|07:00 0 21:00 100 22:00 50 23:00 30 24:00 0,beforeschool|07:00 0 08:30 50 20:00 100 21:00 50 21:30 30 24:00 0,free|07:00 0 08:30 50 21:00 100 22:00 50 23:00 30 24:00 0
define          scc.kind2            Snapcast          client scs.snap 025009413c29
  attr          scc.kind2            constraintDummy  freestring
  attr          scc.kind2            constraints      standard|07:00 0 20:15 100 20:30 50 24:00 0,beforefree|07:00 0 21:00 100 22:30 50 24:00 0,beforeschool|07:00 0 08:30 50 20:15 100 20:30 50 24:00 0,free|07:00 0 08:30 50 21:00 100 22:30 50 24:00 0
define          scc.kueche            Snapcast          client scs.snap b827eb9a2ad3
define          scc.wohn              Snapcast          client scs.snap 00aefa4aa3a9
</syntaxhighlight>
Oben zu sehen ist das define für das Server-Modul. Ohne Parameter verbindet sich mit localhost auf dem Standardport 1705. Es folgt die Definition von 2 Clients. Der erste Parameter "client" versetzt das Snapcastmodul in den Clientmodus. Der zweite Parameter verweist auf das Servermodul, der dritte Parameter ist die Client-ID. Diese besteht bei der aktuellen Snapcast-Version meistens aus der MAC-Adresse des Clients. Für die Kinder werden noch die Attribute constraintDummy ond constraints vergeben. Hiermit wird eine tagestyp- und tageszeitabhängige Lautstärkebegrenzung konfiguriert. Für die vier Tagestypen "standard", "beforefree", "beforeschool" und "free" wird ein jeweils anderes Lautstärkezeitprofil definiert.
Das Zeitprofil wird hier nach dem gleichen Muster wie die Temperaturlisten der Homematic-Thermostate, erklärt hier: [HomeMatic_Type_Thermostat]. Für den Tagestyp wird zusätzlich das Attribut constraintDummy verwendet. Es definiert, dass in dem Dummy "freestring" jeweils drin steht, welcher Tagestyp gerade ist. Diese Variable wirkt somit als Selektor auf die Liste der erlaubten Maximallautstärken. Wie eine solche Dummyvariable jeweils mit einem entsprechenden Wert befüllt werden kann, z.B. abhängig vom Wochentag, von Schulferien oder Feiertagen, wird hier nicht erläutert. Es ist auch möglich, nur ein Lautstärkeprofil anzugeben. Ohne dass ein Attribut constraintDummy gesetzt ist, verwendet das Snapcastmodul immer den Wert "standard". Wie man hier sehen kann, gibt es im Beispiel 4 Typen, hierbei fallen Freitage normalerweise in die Kategorie "beforefree" (es sind Tage, bevor dann frei ist, es kann also typischerweise länger und lauter Musik gehört werden), Samstage normalerweise in die Kategorie "free" und Sonntage in die Kategorie "beforeschool", ebenso landen dort Feiertage vor Schultagen usw.
<syntaxhighlight lang="bash">
define          tts.wohn              Text2Speech      pulsewohn
  attr          tts.wohn              TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.wohn              TTS_UseMP3Wrap    true
  attr          tts.wohn              TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
define          tts.kind1            Text2Speech      pulsekind1
  attr          tts.kind1            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kind1            TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kind1            TTS_UseMP3Wrap    true
define          tts.kind2            Text2Speech      pulsekind2
  attr          tts.kind2            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kind2            TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kind2            TTS_UseMP3Wrap    true
define          tts.kueche            Text2Speech      pulsekueche
  attr          tts.kueche            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kueche            TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kueche            TTS_UseMP3Wrap    true
define          tts.kinder            Text2Speech      pulsekinder
  attr          tts.kinder            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kinder            TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kinder            TTS_UseMP3Wrap    true
define          tts.unten            Text2Speech      pulseunten
  attr          tts.unten            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.unten            TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.unten            TTS_UseMP3Wrap    true
define          tts.alle              Text2Speech      pulsealle
  attr          tts.alle              TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.alle              TTS_MplayerCall  PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.alle              TTS_UseMP3Wrap    true
</syntaxhighlight>
Hier sind die Definitionen der Text2Speech Module zu sehen (optional). Sie werden jeweils mit den in Pulseaudio definierten Sinks verbunden. Die Nutzung eines TemplateDirs ist ebenfalls optional, hier können bereits fertige MP3s verwendet werden, die dann anstelle der von der Google TTS API erzeugten Dateien benutzt werden. Dies können auch Bestätigungs und Fehlertöne sein, die bei Benutzern ohne Display, die rein mit Fernbedienung arbeiten, auf Fehlbedienungen etc. aufmerksam zu omrhen. Der Aufruf von mplayer wird noch modifiziert, um dafür zu sorgen, dass die Ausgabe bei Pulseaudio als media.role "announcement" eingehen. Dies wird dann vom duck-Modul erkannt, und führt dazu, dass die Lautstärke der ggf. ablaufenden Musik, etc. abgesenkt wird, so lange die tts-Ausgabe läuft.
<syntaxhighlight lang="bash">
define          mpd.kind1              MPD              192.168.2.2 6600
  attr          mpd.kind1              player            mopidy
  attr          mpd.kind1              bookmarkDir      mpdstates
  attr          mpd.kind1              autoBookmark      1
define          mpd.kind2            MPD              192.168.2.2 6702
  attr          mpd.kind2            player            mopidy
  attr          mpd.kind2            bookmarkDir      mpdstates
  attr          mpd.kind2            autoBookmark      1
define          mpd.kueche            MPD              192.168.2.2 6703
  attr          mpd.kueche            player            mopidy
  attr          mpd.kueche            bookmarkDir      mpdstates
  attr          mpd.kueche            autoBookmark      1
define          mpd.wohn              MPD              192.168.2.2 6704
  attr          mpd.wohn              player            mopidy
  attr          mpd.wohn              bookmarkDir      mpdstates
  attr          mpd.wohn              autoBookmark      1
</syntaxhighlight>
Pro laufender MPD oder Mopidy-Instanz wird ein MPD-Modul eingerichtet. Der Hostname und die Ports sind entsprechend anzupassen. Durch die bookmarkDir und autoBookmark - Attribute wird erreicht, dass der Zustand von Playlisten beim Wechsel derselben gespeichert und später wiederhergestellt werden kann. So lässt sich das Hören eines Hörbuchs unterbrechen, auf z.B. eine Radiostreamplayliste schalten, um dann später zur gleichen Stelle im Hörbuch zurückzukehren.
<syntaxhighlight lang="bash">
define          omr.kind1              OpenMultiroom
  attr          omr.kind1              mr                scc.kind1
  attr          omr.kind1              soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kind1              playlistPattern  kind1
  attr          omr.kind1              ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kind1              defaultTts        tts.kind1
  attr          omr.kind1              defaultStream    kind1
  attr          omr.kind1              defaultSound      mpd.kind1
define          omr.kind2            OpenMultiroom
  attr          omr.kind2            mr                scc.kind2
  attr          omr.kind2            soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kind2            playlistPattern  kind2
  attr          omr.kind2            ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kind2            defaultTts        tts.kind2
  attr          omr.kind2            defaultStream    kind2
  attr          omr.kind2            defaultSound      mpd.kind2
define          omr.kueche            OpenMultiroom
  attr          omr.kueche            mr                scc.kueche
  attr          omr.kueche            soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kueche            playlistPattern  wohn
  attr          omr.kueche            ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kueche            defaultTts        tts.kueche
  attr          omr.kueche            defaultStream    kueche
  attr          omr.kueche            defaultSound      mpd.kueche
define          omr.wohn              OpenMultiroom
  attr          omr.wohn              mr                scc.wohn
  attr          omr.wohn              soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.wohn              playlistPattern  wohn
  attr          omr.wohn              ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.wohn              defaultTts        tts.wohn
  attr          omr.wohn              defaultStream    wohn
  attr          omr.wohn              defaultSound      mpd.wohn
</syntaxhighlight>
Die Konfiguration der OpenMultiroom-Module schließt die Einrichtung von FHEM ab. Jede Instanz benötigt mindestens das "mr"- und das "soundMapping"-Attribut. Nur so kann sich das Modul mit den entsprechenden Snapcast und MPD-Modulen verbinden. Durch das "mr"-Attribut wird ein OpenMultiroom-Modul einem Snapcast-Client-Modul fest zugeordnet. Das Soundmapping ordnet die in Snapcast definierten Streams (siehe oben, Konfiguration vom Snapserver) den entsprechenden Instanzen des MPD-Moduls zu. Dadurch weiß FHEM, welcher MPD auf welchem Stream abspielt und kann je nachdem, welchem Stream ein Raum gerade zuhört, den dazu passenden MPD steuern und seine Readings durchreichen. Das OpenMultiroom-Modul bildet alle Readings des MPD-Moduls nochmal direkt ab. Wechselt ein Benutzer aber den Stream, dem er zuhört, aktualisieren sich auch alle Readings dementsprechend mit denen des dann aktuellen MPD-Moduls.
Das Attribut playlistPattern ist optional und sorgt dafür, dass beim Durchschalten der Playlists mit den Kommandos "channelUp" und "channelDown" nur diejenigen Playlists berücksichtigt werden, die auf das Pattern passen.
Analog zum soundMapping definiert das Attribut ttsMapping die Zuordnung der TTS-Module zu den Streams. Beim Ausgeben von Announcement kann so das OpenMultiroom-Modul ermitteln, auf welchem Stream welcher Raum gerade zuhört, und wo dementsprechend die TTS-Ausgaben zu erzeugen sind, damit sie auch in den gewünschten Räumen ankommen. Dieser Umweg ist zurzeit nötig, da ein Snapcast-Client nur auf einem einzigen Stream lauschen kann. Lauschen noch andere Clients auf demselben Stream, hören sie allerdings zwangsweise auch die Announcements.
Die 3 Default-Attribute legen fest, welche der TTS-Module, welcher Stream und welcher MPD dem entsprechenden Modul fest zugeordnet sind. Dies wird u.a. von einer Resetfunktion im Modul verwendet.
== Bedienung des OpenMultiroom-Moduls ==
=== set-Kommandos ===
=== Readings ===
=== Attribute ===
== Anbindung einer Fernbedienung an ein OpenMultiroom-Modul ==
=== Konfiguration von LIRC und IRExec ===
=== Zuordnung der Tasten: Beispiel ===


[[Category:Examples]]
[[Category:Examples]]
[[Category:HOWTOS]]
[[Category:HOWTOS]]
[[Category:Unterhaltungselektronik]]
[[Category:Unterhaltungselektronik]]

Aktuelle Version vom 12. Juli 2022, 14:40 Uhr

OpenMultiroom
Zweck / Funktion
Steuern der einzelnen Multiroom-Systemkomponenten
Allgemein
Typ Gerätemodul
Details
Dokumentation EN / DE
Support (Forum) Multimedia
Modulname 98_OpenMultiroom.pm
Ersteller unimatrix
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


Snapcast
Zweck / Funktion
Steuern eines Snapcast-Servers
Allgemein
Typ Gerätemodul
Details
Dokumentation EN / DE
Support (Forum) Multimedia
Modulname 96_Snapcast.pm
Ersteller Beta-User (Forum /Wiki)
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!
Schaubild des Zusammenspiels der einzelnen Komponenten eines Multiroomsystems mit den Backends MPD und Snapcast sowie der Nutzung von Text2Speech

Achtung: Das Modul ist noch in der Entwicklung und bisher nur im Forum bzw. auf dem Github des ursprünglichen Autors (beide veraltet) oder aktualisiert im Forum verfügbar.

OpenMultiroom ist ein Steuerungsmodul sowie auch ein Gesamtkonzept zur Realisierung eines Multiroom-Audio-Systems unter Nutzung von ausschließlich frei verfügbarer Software und ohne Bezug auf die Hardware eines bestimmten Herstellers. Es ist so ausgelegt, dass es prinzipiell flexibel bezüglich der Auswahl der Backendsysteme ist. Zurzeit ist es für die Nutzung mit MPD bzw. Mopidy und Snapcast implementiert. Daher wird in diesem WIKI-Eintrag immer von diesen Systemen gesprochen. Einen grundsätzlichen Überblick über das Konzept bietet das Schaubild.

Grobe Übersicht des Funktionsumfangs der Gesamtlösung

Features

  • Integrierte Steuerung des Musikplayers über das MPD-Modul sowie des Multiroom-System Snapcast in einem einzigen Modul
  • Implementierung einer Schnittstelle gemäß DevelopmentGuidelinesAV als Basis für eine Visualisierung mit z.B. SmartVISU oder FHEM Tablet UI
  • Synchrones Playback auf z.B. Raspberry Pi oder Android-Geräten (Snapcast-Feature)
  • optionale Komprimierung der Soundübertragung als OGG oder FLAC (Snapcast-Feature)
  • Möglichkeit der Bedienung völlig ohne Display über eine Fernbedienung und entsprechender Text2Speech Rückmeldung, insbesondere
    • Durschalten von Playlisten mit entsprechenden Channel - Tasten unter Nutzung von raumspezifischen Filtern
    • Forward und Rewind mit definierbaren Sprungweiten (implementiert direkt im MPD-Modul)
    • Direktanwahl von Playlisten, Tracks oder Trackpositionen durch Zifferneingabe und anschließende Funktionstaste
    • Abfrage von Statusinformationen durch Funktionstasten und Text2Speech Rückmeldungen
    • Mithören in anderen Räumen und Übernahme des Playerzustandes anderer Räume durch Nutzung von Funktionstasten
    • Einschlaftimer per Zifferneingabe oder per vordefinierten Zeitabständen, hierbei wird auch die Restlaufzeit des aktuellen Tracks angeboten.
  • manuelles oder automatisches Speichern und Laden von Playlistbookmarks (implementiert direkt im MPD-Modul)
  • Möglichkeit der Festlegung von tageszeit- und tagestypabhängigen Lautstärkebegrenzungen bis auf 0% z.B. für Kinderzimmer
  • individuelles Verwalten von Playlisten für verschiedene Familienmitglieder
  • Nutzung des Audiosystems für systemunabhängige FHEM-Announcements. Ein entsprechendes Announcement-Modul ist in Planung. Dabei können mehrere Räume gleichzeitig oder auch getrennt angesprochen werden

Anwendungszweck und Kurzbeschreibung der Funktionsweise

Wie der Name des Systems vermuten lässt, ist die Lösung vor allem dann sinnvoll einzusetzen, wenn Audiodateien in mindestens 2 verschiedenen Räumen oder "Zonen" sowohl synchron als auch unabhängig abgespielt werden soll und wenn hierzu eine komfortable und integrierte Steuerung über FHEM verwendet werden soll. Mit Einschränkungen ist die Lösung auch dann sinnvoll, wenn es nur um das Abspielen in einem Raum geht. Hier kann dann z.B. die Steuerung über eine Fernbedienung mit Hilfe des OpenMultiroom-Moduls genutzt werden, die über eine reine Nutzung des MPD-Moduls hinausgeht.

Für die Nutzung ist nicht zwingend ein zentraler Server notwendig. Diese Rolle kann auch von einem der Clients übernommen werden, z.B. einem Pi. Zur einfacheren Darstellung wird in diesem Eintrag jedoch immer von der Nutzung eines Servers ausgegangen, der nicht gleichzeitig auch Client ist.

Das Abspielen von Audio funktioniert prinzipiell in 2 Stufen:

  1. Nutzung von MPD oder einem MPD-kompatiblen Player zum direkten Abspielen von Sounddateien. Pro existierendem Raum gibt es mindestens eine Instanz von MPD. Hier wird davon ausgegangen, dass es genau eine Instanz pro Raum gibt. Jeder Raum hat also "seinen" MPD.
  2. Nutzung von Snapcast zur Verteilung des von MPD abgespielten Sounds an den entsprechenden Raum. Snapcast übernimmt hierbei die zeitliche Synchronisation

Durch das Modul OpenMultiroom steuert der Nutzer sowohl MPD als auch Snapcast. Für jeden Raum wird eine Instanz des Moduls definiert.

Verwendete Komponenten

Folgende Komponenten kommen zum Einsatz:

Server:

  • MPD oder Mopidy oder ein anderer MPD-kompatibler Player. 1 Instanz pro Raum
  • Snapserver
  • mplayer (bei Nutzung von Text 2 Speech)
  • Optional Pulseaudio (im System-Mode) bei Nutzung von Text 2 Speech oder erweiterten Konfigurationen. Hierbei wird Pulseaudio zwischen MPD und Snapcast geschaltet.
  • Optional Anbindung an Subsonic oder Libresonic (hier zurzeit nicht beschrieben) zur Synchronisation von Playlisten uvm.
  • FHEM: Modul 98_OpenMultiroom.pm
  • FHEM: Modul 96_Snapcast.pm
  • FHEM: Modul 73_MPD.pm
  • FHEM: Optional Modul 98_Text2Speech.pm

Client:

  • Linux: Alsa oder Pulseaudio zur Soundwiedergabe
  • Linux: Snapclient
  • Android: Nur der Android Snapclient
  • Webbrowser zur Steuerung per Visualisierung
  • ggf. Infrarot oder Funkfernbedienung. In diesem Artikel wird das Beispiel anhand der Nutzung von X10-Funkfernbedienungen gezeigt, diese gibt es sehr günstig in der Bucht o.ä.
  • Vision: Nutzung von Tastern und Display am PI oder Nutzung eines Steuergerätes mit Tastern und Display auf Basis eines Arduino mit WLAN, z.B. im alten Gehäuse eines Küchenradios usw.


Aufbau anhand einer vollständigen Beispielkonfiguration

In diesem Artikel soll beispielhaft eine vollständige Konfiguration gezeigt werden. Jeder Nutzer muss diese Konfiguration an seine eigenen Bedürfnisse anpassen. Es seien folgende Komponenten vorhanden:

  • Server mit Ubuntu 16.04, hier befindet sich eine MP3-Sammlung
  • Kind1: Raspberry Pi Model 1 mit Raspbian
  • Kind2: BananaPi mit Ubuntu, an diesem Pi ist auch ein X10 Empfänger angeschlossen, da er zentral im Haus positioniert ist
  • Wohnzimmer: Raspberry Pi3 mit OSMC und KODI, wird primär zum Fernsehen verwendet
  • Küche: Raspberry Pi Model 1 mit Raspbian

Anmerkung: Es ist möglich, mehrere Räume mit nur einem physikalischen Client zu bedienen. Hierbei werden auf einem Client mehrere Instanzen des Snapclients laufen gelassen. Der physikalische Client hat dann z.B. mehrere USB Soundkarten, dessen Audioausgänge in verschiedene Räume verkabelt sind. Dies wird hier zurzeit nicht näher beschrieben.

Pulseaudio Konfiguration

Will man Pulseaudio verwenden, z.B. um Text2Speech Nachrichten in laufende Musik einzublenden, sollte dieses am besten zuerst konfiguriert werden. Pulseaudio muss hierzu im System-Mode laufen. Dies ist auf einem Headless-Server kein Problem. Bei Ubuntu 16.10 wird dies durch folgenden Inhalt in /etc/systemd/system/pulseaudio.service erreicht:

[Unit]
Description=PA
After=network.target sound.target

[Service]
ExecStart=/usr/bin/pulseaudio --system

# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=infinity

# disallow writing to /usr, /bin, /sbin, ...
ProtectSystem=yes

[Install]
WantedBy=multi-user.target

Weiterhin ist der Befehl

sudo systemctl enable pulseaudio

einzugeben, um Pulseaudio beim Systemstart automatisch zu starten.

Ausgehend von der Standardkonfiguration werden nun in /etc/pulse/system.pa die benötigten Module eingetragen

load-module module-pipe-sink file=/tmp/wohn.fifo   sink_name=wohn
load-module module-pipe-sink file=/tmp/kind1.fifo   sink_name=kind1
load-module module-pipe-sink file=/tmp/kind2.fifo  sink_name=kind2
load-module module-pipe-sink file=/tmp/kueche.fifo sink_name=kueche

load-module module-combine-sink slaves=kind1,kind2 sink_name=kinder
load-module module-combine-sink slaves=wohn,kueche sink_name=unten
load-module module-combine-sink slaves=wohn,kueche,kind1,kind2 sink_name=alle

pactl load-module module-role-ducking trigger_roles=announcement ducking_roles=music

Snapcast benötigt die Audioquelle in Form von FIFOs. Daher wird hier in den erstem 4 Zeilen je ein FIFO von Pulseaudio erzeugt. Der sink_name wird später bei der Konfiguration von MPD als Ausgang verwendet. In den 3 weiteren Zeilen werden noch 3 Sinks als Combine-Sinks erstellt. Diese erzeugen keine neuen FIFOs, sondern machen unter entsprechenden Sink-Namen eine vorgegebene Kombination von Räumen nach außen hin verfügbar. Der Sink "alle" kann also genutzt werden, um Audio auf allen 4 FIFOs gleichzeitig abzuspielen (und somit später potentiell in allen Räumen gleichzeitig). Dies kann für Announcements sinnvoll sein. Die Nutzung dieser Combine-Sinks ist optional. Ebenso optional ist das Laden des Ducking-Moduls am Ende. Das Ducking Modul führt dazu, dass Pulseaudio automatisch die Lautstärke der durch MPD abgespielten Tracks absenkt, wenn etwas über die Text2Speech-Module abgespielt wird. Ohne dies sind die Ausgaben speziell über die Google API unter Umständen nur schwer hörbar.

Snapcast Konfiguration

Snapcast muss entsprechend der Angaben auf der Webseite installiert werden. Auf dem Server muss logischerweise die Serverkomponente und auf den Clients die Clientkomponente installiert werden. Bei Android-Clients wird die auf der Webseite zur Verfügung gestellt APK installiert. Snapcast befindet sich selbst noch in fortlaufender Entwicklung. Die hier vorgestellte Lösung ist mit dieser Version kompatibel und getestet.

Die Konfiguration des Servers beschränkt sich auf die Definition der Streams in /etc/default/snapserver

START_SNAPSERVER=true
SNAPSERVER_OPTS="-d -s pipe:///tmp/kind1.fifo?name=kind1&mode=read -s pipe:///tmp/kind2.fifo?name=kind2&mode=read -s pipe:///tmp/wohn.fifo?name=wohn&mode=read -s pipe:///tmp/kueche.fifo?name=kueche&mode=read"

Hier werden die 4 Streams erstellt, diese entsprechen vom Dateinamen her der Pulseaudiokonfiguration. Der hier verwendete Name kann später in FHEM oder auch im Android-Client angezeigt werden. Die Option

mode=read

ist wichtig, weil Pulseaudio meckert, wenn es die FIFO-Dateien nicht selbst anlegen darf.

Auf der Clientseite sieht die Datei /etc/default/snapclient dann so aus:

START_SNAPCLIENT=true
SNAPCLIENT_OPTS="-d -s dmix:CARD=Aureon51MkII,DEV=0"

Den Server findet der Snapclient automatisch, er kann aber auch angegeben werden. Wie hier zu sehen kann ein spezielles Output-Device angegeben werden. Dies ist bei den PIs mit externer USB-Soundkarte meistens notwendig, da ansonsten der interne Sound genutzt würde. Eine Liste der verfügbaren Devices wird mit dem Aufruf von

snapclient -l

ausgegeben, hier muss dann das passende genommen werden. GGf. so lange ausprobieren, bis der Sound an der richtigen Stelle rauskommt.

In der hier betrachteten Konfiguration soll auf dem Wohnzimmer-PI ein Snapclient laufen, dieser wird aber normalerweise zum TV und Filme schauen mit KODI verwendet. Sowohl KODI als auch der Snapclient blockieren aber das ALSA-Device und funktionieren beide meistens entweder gar nicht oder nicht richtig zusammen, insbesondere dann nicht, wenn von KODI Mehrkanalsound oder sogar Passthrough ausgegeben wird. Die Entwicklung eines nativen Snapcast-Clients innerhalb von KODI wird gerade an verschiedenen Stellen diskutiert, z.B. hier. Bis dahin kann ein kleiner Workaround Abhilfe schaffen. Mit folgendem (nur rudimentär getesteten) Hack für den Snapcast-Client wird erreicht, dass der Client das ALSA-Device frei gibt, sobald er über den Server auf Mute gestellt wird. KODI selbst gibt das Device ebenfalls frei, wenn es im Zustand "Stop" ist. Bei dieser Lösung kann der Snapclient auf dem KODI-Rechner immer laufen gelassen werde. Es ist jedoch in der Verantwortung des Benutzers, den Client zu "muten". Vergisst er dies, wird ggf. die Wiedergabe in KODI nicht möglich sein.

Nach Abschluss der Snapcastkonfiguration und dem Starten von Server und den Clients empfiehlt es sich, die Android-App ebenfalls zu verwenden, da diese einen schnellen Überblick über den Zustand des Servers, der konfigurierten Streams und der Clients bietet.

Mopidy Konfiguration

In diesem Beispiel wird Mopidy als MPD-Ersatz verwendet, genau so gut kann aber auch direkt MPD verwendet werden. Die genauen Konfigurationsoptionen sind natürlich anders, und jeweils in entsprechenden Tutorials oder Dokumentationen beschrieben. Mopidy ist relativ umfangreich und modular aufgebaut, es bietet u.a. die Möglichkeit, neben lokal gespeicherten Dateien auch Dateien von verschiedenen, teilweise kommerziellen, Streamingdiensten abzuspielen. Die Detailkonfiguration all dieser Komponenten geht über diesen Artikel hinaus. Entscheidend hier ist die Konfiguration in einer Weise, so dass mehrere Mopidy-Instanzen gleichzeitig ausgeführt werden können und dann auf unterschiedlichen Ports zur Verfügung stehen.

Nach Installation von Mopidy findet sich die Konfiguration in der Datei /etc/mopidy/mopidy.cfg. Mopidy unterstützt hierarische Konfigurationen, es reicht also, den für jede Instanz spezifischen Teil aus dieser allgemeinen Konfiguration zu entfernen und in jeweils eigene Dateien zu verschieben. In diesem Beispiel sollen das die Dateien /etc/mopidy/kind1.conf bis /etc/mopidy/kueche.conf sein. Die folgenden Zeilen gehören jeweils in diese 4 Dateien und werden dort entsprechend angepasst. Hier das Beispiel für Kind2:

[logging]
config_file = /etc/mopidy/logging_kind2.conf
debug_file = /var/log/mopidy/mopidy-debug_kind2.log

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! pulsesink  device=kind2  stream-properties="props,media.role=music"

[mpd]
enabled = true
hostname = 0.0.0.0
port=6601

[http]
enabled = true
hostname =  0.0.0.0
port=6681
zeroconf = Musik Kind2

Im Audioteil wird der entsprechende Sink aus der Pulseaudiokonfiguration genommen. Die Angabe von stream-properties ermöglicht dem Duck-Modul den Stream als Musik zu erkennen und beim Abspielen von Announcements in der Lautstärke abzusenken. Beim MPD muss der Port für jede Instanz unterschiedlich sein, ebenso beim HTTP-Modul für die Weboberfläche der jeweiligen Instanz. Der Zerokonfname sollte auch eindeutig sein. Neben dieser Datei ist noch die dazu passende logging-Konfiguration anzulegen, hier also /etc/mopidy/logging_kind2.conf. Dazu wird die Standarddatei kopiert und darin nur der Name der Logdatei angepasst.

Um nun auch die entsprechende Anzahl Instanzen automatisch zu starten, sind die entsprechenden Startdateien anzulegen. Dazu kann die Datei /etc/systemd/system/mopidy.cfg z.B. in /etc/systemd/system/mopidy_kind1.cfg umbenannt werden und dann 3 mal mit den Endungen der anderen Instanzen kopiert werden. Der Inhalt ist dann wie folgt:

[Unit]
Description=Mopidy_kind1
After=network.target sound.target

[Service]
EnvironmentFile=/etc/default/mopidy
ExecStart=/usr/bin/mopidy --quiet --config /etc/mopidy/kind1.conf

# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=infinity

# disallow writing to /usr, /bin, /sbin, ...
ProtectSystem=yes

[Install]
WantedBy=multi-user.target

Abschließend sollten die 4 Instanzen durch den Aufruf von

systemctl enable mopidy_kind1

usw. aktiviert werden. Es empfiehlt sich nach dem Start von Mopidy die korrekte Funtkionsweise mit dem MPC-Client oder mit NCMPCPP auf der Konsole zu testen.

Hierbei sollte es dann bereits möglich sein, die Multiroom-Fähigkeiten von Snapcast mit Hilfe des Android-Clients von Snapcast zu testen und so auch festzustellen, dass die restliche Konfiguration von Snapcast und Pulseaudio korrekt sind.

FHEM

In FHEM sind nun in der fhem.cfg die entsprechenden Module einzurichten:

  • Ein Snapcast-Modul im Server Modus
  • Pro Raum ein Snapcast-Modul im Clientmodus
  • Pro Raum ein MPD-Modul
  • Pro Raum ein OpenMultiroom-Modul
  • Optional pro Raum ein Text2Speech-Modul
  • weitere Text2Speech-Module, falls man diese in Pulseaudio mit dem per Combine-Sink vorgesehen hat.
define          scs.snap              Snapcast

define          scc.kind1             Snapcast          client scs.snap b827eb9aec84
  attr          scc.kind1             constraintDummy   freestring 
  attr          scc.kind1             constraints       standard|07:00 0 20:00 100 21:00 50 21:30 30 24:00 0,beforefree|07:00 0 21:00 100 22:00 50 23:00 30 24:00 0,beforeschool|07:00 0 08:30 50 20:00 100 21:00 50 21:30 30 24:00 0,free|07:00 0 08:30 50 21:00 100 22:00 50 23:00 30 24:00 0

define          scc.kind2             Snapcast          client scs.snap 025009413c29
  attr          scc.kind2             constraintDummy   freestring
  attr          scc.kind2             constraints       standard|07:00 0 20:15 100 20:30 50 24:00 0,beforefree|07:00 0 21:00 100 22:30 50 24:00 0,beforeschool|07:00 0 08:30 50 20:15 100 20:30 50 24:00 0,free|07:00 0 08:30 50 21:00 100 22:30 50 24:00 0

define          scc.kueche            Snapcast          client scs.snap b827eb9a2ad3

define          scc.wohn              Snapcast          client scs.snap 00aefa4aa3a9


Oben zu sehen ist das define für das Server-Modul. Ohne Parameter verbindet sich mit localhost auf dem Standardport 1705. Es folgt die Definition von 2 Clients. Der erste Parameter "client" versetzt das Snapcastmodul in den Clientmodus. Der zweite Parameter verweist auf das Servermodul, der dritte Parameter ist die Client-ID. Diese besteht bei der aktuellen Snapcast-Version meistens aus der MAC-Adresse des Clients. Für die Kinder werden noch die Attribute constraintDummy ond constraints vergeben. Hiermit wird eine tagestyp- und tageszeitabhängige Lautstärkebegrenzung konfiguriert. Für die vier Tagestypen "standard", "beforefree", "beforeschool" und "free" wird ein jeweils anderes Lautstärkezeitprofil definiert.

Das Zeitprofil wird hier nach dem gleichen Muster wie die Temperaturlisten der Homematic-Thermostate, erklärt hier: [HomeMatic_Type_Thermostat]. Für den Tagestyp wird zusätzlich das Attribut constraintDummy verwendet. Es definiert, dass in dem Dummy "freestring" jeweils drin steht, welcher Tagestyp gerade ist. Diese Variable wirkt somit als Selektor auf die Liste der erlaubten Maximallautstärken. Wie eine solche Dummyvariable jeweils mit einem entsprechenden Wert befüllt werden kann, z.B. abhängig vom Wochentag, von Schulferien oder Feiertagen, wird hier nicht erläutert. Es ist auch möglich, nur ein Lautstärkeprofil anzugeben. Ohne dass ein Attribut constraintDummy gesetzt ist, verwendet das Snapcastmodul immer den Wert "standard". Wie man hier sehen kann, gibt es im Beispiel 4 Typen, hierbei fallen Freitage normalerweise in die Kategorie "beforefree" (es sind Tage, bevor dann frei ist, es kann also typischerweise länger und lauter Musik gehört werden), Samstage normalerweise in die Kategorie "free" und Sonntage in die Kategorie "beforeschool", ebenso landen dort Feiertage vor Schultagen usw.

define          tts.wohn              Text2Speech       pulsewohn
  attr          tts.wohn              TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.wohn              TTS_UseMP3Wrap    true
  attr          tts.wohn              TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120

define          tts.kind1             Text2Speech       pulsekind1
  attr          tts.kind1             TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kind1             TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kind1             TTS_UseMP3Wrap    true

define          tts.kind2             Text2Speech       pulsekind2
  attr          tts.kind2             TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kind2             TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kind2             TTS_UseMP3Wrap    true

define          tts.kueche            Text2Speech       pulsekueche
  attr          tts.kueche            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kueche            TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kueche            TTS_UseMP3Wrap    true

define          tts.kinder            Text2Speech       pulsekinder
  attr          tts.kinder            TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.kinder            TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.kinder            TTS_UseMP3Wrap    true

define          tts.unten             Text2Speech       pulseunten
  attr          tts.unten             TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.unten             TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.unten             TTS_UseMP3Wrap    true

define          tts.alle              Text2Speech       pulsealle
  attr          tts.alle              TTS_FileTemplateDir /data/misc/announcements/
  attr          tts.alle              TTS_MplayerCall   PULSE_PROP='media.role=announcement' /usr/bin/mplayer -softvol -volume 120
  attr          tts.alle              TTS_UseMP3Wrap    true

Hier sind die Definitionen der Text2Speech Module zu sehen (optional). Sie werden jeweils mit den in Pulseaudio definierten Sinks verbunden. Die Nutzung eines TemplateDirs ist ebenfalls optional, hier können bereits fertige MP3s verwendet werden, die dann anstelle der von der Google TTS API erzeugten Dateien benutzt werden. Dies können auch Bestätigungs und Fehlertöne sein, die bei Benutzern ohne Display, die rein mit Fernbedienung arbeiten, auf Fehlbedienungen etc. aufmerksam zu omrhen. Der Aufruf von mplayer wird noch modifiziert, um dafür zu sorgen, dass die Ausgabe bei Pulseaudio als media.role "announcement" eingehen. Dies wird dann vom duck-Modul erkannt, und führt dazu, dass die Lautstärke der ggf. ablaufenden Musik, etc. abgesenkt wird, so lange die tts-Ausgabe läuft.

define          mpd.kind1              MPD               192.168.2.2 6600
  attr          mpd.kind1              player            mopidy
  attr          mpd.kind1              bookmarkDir       mpdstates
  attr          mpd.kind1              autoBookmark      1

define          mpd.kind2             MPD               192.168.2.2 6702
  attr          mpd.kind2             player            mopidy
  attr          mpd.kind2             bookmarkDir       mpdstates
  attr          mpd.kind2             autoBookmark      1

define          mpd.kueche            MPD               192.168.2.2 6703
  attr          mpd.kueche            player            mopidy
  attr          mpd.kueche            bookmarkDir       mpdstates
  attr          mpd.kueche            autoBookmark      1

define          mpd.wohn              MPD               192.168.2.2 6704
  attr          mpd.wohn              player            mopidy
  attr          mpd.wohn              bookmarkDir       mpdstates
  attr          mpd.wohn              autoBookmark      1

Pro laufender MPD oder Mopidy-Instanz wird ein MPD-Modul eingerichtet. Der Hostname und die Ports sind entsprechend anzupassen. Durch die bookmarkDir und autoBookmark - Attribute wird erreicht, dass der Zustand von Playlisten beim Wechsel derselben gespeichert und später wiederhergestellt werden kann. So lässt sich das Hören eines Hörbuchs unterbrechen, auf z.B. eine Radiostreamplayliste schalten, um dann später zur gleichen Stelle im Hörbuch zurückzukehren.

define          omr.kind1              OpenMultiroom
  attr          omr.kind1              mr                scc.kind1
  attr          omr.kind1              soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kind1              playlistPattern   kind1
  attr          omr.kind1              ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kind1              defaultTts        tts.kind1
  attr          omr.kind1              defaultStream     kind1
  attr          omr.kind1              defaultSound      mpd.kind1

define          omr.kind2             OpenMultiroom
  attr          omr.kind2             mr                scc.kind2
  attr          omr.kind2             soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kind2             playlistPattern   kind2
  attr          omr.kind2             ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kind2             defaultTts        tts.kind2
  attr          omr.kind2             defaultStream     kind2
  attr          omr.kind2             defaultSound      mpd.kind2

define          omr.kueche            OpenMultiroom
  attr          omr.kueche            mr                scc.kueche
  attr          omr.kueche            soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.kueche            playlistPattern   wohn
  attr          omr.kueche            ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.kueche            defaultTts        tts.kueche
  attr          omr.kueche            defaultStream     kueche
  attr          omr.kueche            defaultSound      mpd.kueche

define          omr.wohn              OpenMultiroom
  attr          omr.wohn              mr                scc.wohn
  attr          omr.wohn              soundMapping      kind1:mpd.kind1,kind2:mpd.kind2,kueche:mpd.kueche,wohn:mpd.wohn
  attr          omr.wohn              playlistPattern   wohn
  attr          omr.wohn              ttsMapping        kind1:tts.kind1,kind2:tts.kind2,kueche:tts.kueche,wohn:tts.wohn
  attr          omr.wohn              defaultTts        tts.wohn
  attr          omr.wohn              defaultStream     wohn
  attr          omr.wohn              defaultSound      mpd.wohn

Die Konfiguration der OpenMultiroom-Module schließt die Einrichtung von FHEM ab. Jede Instanz benötigt mindestens das "mr"- und das "soundMapping"-Attribut. Nur so kann sich das Modul mit den entsprechenden Snapcast und MPD-Modulen verbinden. Durch das "mr"-Attribut wird ein OpenMultiroom-Modul einem Snapcast-Client-Modul fest zugeordnet. Das Soundmapping ordnet die in Snapcast definierten Streams (siehe oben, Konfiguration vom Snapserver) den entsprechenden Instanzen des MPD-Moduls zu. Dadurch weiß FHEM, welcher MPD auf welchem Stream abspielt und kann je nachdem, welchem Stream ein Raum gerade zuhört, den dazu passenden MPD steuern und seine Readings durchreichen. Das OpenMultiroom-Modul bildet alle Readings des MPD-Moduls nochmal direkt ab. Wechselt ein Benutzer aber den Stream, dem er zuhört, aktualisieren sich auch alle Readings dementsprechend mit denen des dann aktuellen MPD-Moduls.

Das Attribut playlistPattern ist optional und sorgt dafür, dass beim Durchschalten der Playlists mit den Kommandos "channelUp" und "channelDown" nur diejenigen Playlists berücksichtigt werden, die auf das Pattern passen.

Analog zum soundMapping definiert das Attribut ttsMapping die Zuordnung der TTS-Module zu den Streams. Beim Ausgeben von Announcement kann so das OpenMultiroom-Modul ermitteln, auf welchem Stream welcher Raum gerade zuhört, und wo dementsprechend die TTS-Ausgaben zu erzeugen sind, damit sie auch in den gewünschten Räumen ankommen. Dieser Umweg ist zurzeit nötig, da ein Snapcast-Client nur auf einem einzigen Stream lauschen kann. Lauschen noch andere Clients auf demselben Stream, hören sie allerdings zwangsweise auch die Announcements.

Die 3 Default-Attribute legen fest, welche der TTS-Module, welcher Stream und welcher MPD dem entsprechenden Modul fest zugeordnet sind. Dies wird u.a. von einer Resetfunktion im Modul verwendet.

Bedienung des OpenMultiroom-Moduls

set-Kommandos

Readings

Attribute

Anbindung einer Fernbedienung an ein OpenMultiroom-Modul

Konfiguration von LIRC und IRExec

Zuordnung der Tasten: Beispiel