Den Music Player Daemon (mpd) per Fernbedienung steuern (Teil3)

Dies ist der letzte Teil dieses dreiteiligen Tutorials (Teil1, Teil2) und es geht darum, wie mpd konfiguriert werden muss, damit es mit dem Kontrollprogramm zusammenarbeitet. Und letztendlich geht es natürlich um das besagte Kontrollprogramm in C++.

Konfiguration des mpd
Wie vorher schon einmal erwähnt, kann das Kontrollprogrammm zwischen den Radio Streams wechseln, in dem es in einer Playlist zwischen den Songs wechselt. Die Playlist ist eine Textdatei, welche URLs der entsprechenden Streams enthält. Von dem Kontrollprogramm wird nur die erste Playlist verwendet, welche mpd zurückliefert. Es wäre zwar auch möglich weitere Playlists zu verwenden, dies ist für unseren Anwendungsfall aber nicht notwendig.

Auf meinem RPi liegt die Playlist Streams.m3u im Verzeichnis des Standardusers /home/pi/mpd/playlists. Die Playlist kann zum Beispiel folgende Einträge enthalten:
http://92.48.107.35:8000

http://directe-http.emissio.catradio.cat:8000/catradio.cat/cat_radio
http://directe-http.emissio.catradio.cat:8000/catradio.cat/mediterradio
http://stream.hoerradar.de:80/antennemv-mp3

Der Name der Playlist kann beliebig gewählt werden, wichtig ist nur, dass mpd diese Playlist auf Anfrage per lsinfo-Kommando als ersten Eintrag zurückliefert. Dies ist übrigens auch ein Punkt, an dem das Programm verbessert werden kann, in dem der Name der gewünschten Playlist als Argument übergeben und dann explizit in der List der Playlists gesucht wird.

Das Kontrollprogramm

Sourcecode
Der Sourcecode ist auf der Plattform sourceforge.net gehostet und kann auf verschiedenen Wegen heruntergeladen werden.

(A) Entweder per GIT (git):

git clone git://git.code.sf.net/p/blogtransbits/code blogtransbits-code/raspberrypi/mpd-remote-control

(B) oder GIT (https)

git clone https://transietbits@git.code.sf.net/p/blogtransbits/code blogtransbits-code/raspberrypi/mpd-remote-control

(C) Oder einfach als tar.gz-Archiv direkt von Sourceforge.net.

 

Die vom Kontrollprogramm verwendeten Klassen

Die vom Kontrollprogramm verwendeten Klassen

Beteiligte Klassen
Das Programm besteht aus der Startklasse, welche die main()-Methode beherbergt und drei Klassen.

MPDConnection
Die Klasse MPDConnection kümmert sich um den Verbindungsaufbau mit mpd und stellt Methoden zum Senden der Kommandos zur Verfügung. Weil die Klasse eine statische Factorymethode besitzt, ist sie zum Teil eine Factory und zum Teil eine normale Klasse. Dies ist nicht unbedingt ein gutes Pattern, der Code sollte aber so einfach wie möglich gehalten werden, so dass auf dedizierte Factories verzichtet wurde.

InputDevice
Die Klasse InputDevice enthält den Programmcode zum Öffnen eines Gerätes über seinen Pfad. Die Methode handleKeys() delegiert bei Tastendruck den Keycode und das KeyValue an die Programmlogik in Form der Klasse RemoteControlLogic weiter. Der Einfachheit halber wurde an dieser Stelle kein „Observer“-Pattern verwendet um so wenig wie möglich Klassen zu erzeugen.

RemoteControlLogic
RemoteControlLogic ist eigentlich nichts weiter als ein Zustandsautomat, welcher die gedrückte Tasten von InputDevice auswertet und entsprechend die Radio Streams wechselt, oder das Playback stoppt bzw. startet.

Die main()-Methode besteht im Kern nur aus wenigen Programmzeilen:

MPDConnection* mpdConn = NULL;
InputDevice* inputDev = NULL;
try {
  // etablish a connection to the MPD server
  mpdConn = MPDConnection::initMpdServerConnection(argv[1], portNo);

  // open the input device
  inputDev = InputDevice::initDevice(argv[3]);

  // start the endless loop for handling the pressed keys...
  RemoteControlLogic logic(mpdConn);
  inputDev->handleKeyEvents(logic);
} catch (const exception& e) {
  ..
}

Kompilieren des Quellcodes
In dem tar.gz-Archiv ist eine makefile-Datei enthalten, welche im besten Fall einfach per:

$ make

im korrekten Verzeichnis aufzurufen ist und eine ausführbare Datei namens RRMpdControl erzeugt. Außer dem GNU g++-Kompiler und den Standardbibliotheken sind keine weiteren Abhängigkeiten vorhanden.

Einklinken in den Linux-Bootprozess
Damit das Program sofort nach dem Start des RPi verfügbar ist, ist es in der Datei /etc/rc.local wie folgt verknüpft:

# start the MPD remote control program
/home/pi/RaspiInetRadio/RRMpdControl raspi2 6600 /dev/input/event2 > /home/pi/RaspiInetRadio/RRMpdControl.log 2>&1 &

In dem Beispiel wird das Kontrollprogramm im Hintergrund gestartet und auf den mpd-Server auf http://raspi2:6600 verbunden. Die Logausgaben der Standard- und Fehlerkonsole werden in die Datei RRMpdControl.log umgeleitet.

Probleme mit mpd
Während des Betriebes mit dem mpd sind einige Fehler aufgetreten, auf die ich hinweisen möchte:

  • „Das Kontrollprogramm kann das Stream-Playback nicht starten“: Hin- und wieder passiert es, dass der mpd-Server zwar eine TCP-Verbindung akzeptiert, dann aber keine Antwort liefert. In diesen Fall funktioniert das Playback nicht. Hier hilft oft nur ein Neustart des mpd und danach des Kontrollprogrammes.
  • „Nach Wechsel des Radio Streams, erfolgt kein Playback“: Hier ist nicht klar, ob dies ein Problem des mpd-Servers oder des Servers ist, welcher den Radio Stream zur Verfügung stellt.

Verbesserungen

Derzeit wird die read()-Funktion im blocking-Modus aufgerufen. Dies führt dazu, dass sich die Anwendung „aufhängt“ wenn der mpd nicht mehr antwortet, d.h. unerwartet keine Daten liefert. Dieser Modus kann über fcntl(sock, F_SETFL, flags | O_NONBLOCK) angepasst werden. Dieser Modus ist noch nicht implementiert.

Beim Wechseln zwischen den Radio Streams ist ein so gut wie immer ein lautes Knacken zu hören. Es gibt hierfür im Internet eine Lösungsvorschläge, die noch nicht im Kontrollprogramm implementiert sind.

Da oft nicht klar ist, auf welchen Radio Stream man sich gerade befindet, wäre die Ausgabe auf einen LCD oder Bildschirm notwendig. Solche Ausgaben haben aber meistens den Umfang eines eigenen kleinen Projektes.

Alternativ könnte per Sprachausgabe der Radio Stream angesagt werden.

Und zu guter Letzt könnte der Programmcode robuster und schöner gestaltet werden.

Links zum Thema:

I'm an independent german IT consultant for Java, J2E and C++ - in my spare time I work on embedded devices, digital Image- and Signal processing, riding motorcycle, doing sports and do many other things.

Tagged with: , , , , , ,
Veröffentlicht in Raspberry Pi

Hinterlasse einen Kommentar