Introduction
The two previous posts have tallked about design/installation and configuration for the Multiroom Server (MRS). All the main pieces are in place for a working system but it isn't easy to start the system up or use it exactly as you want. This post tries goes through steps to take it from a working prototype to a solution for daily use.It also includes extra features which can be used to expand MRS functionality.
Controlling MRS environment through the web
websocketd
A previous post described ympd which allows you to view and update music being played via the web. A page was setup to monitor bluetooth, pulseaudio and mpd tasks running on RPi server. Using the lighttpd application it was possible to start bluetooth but not easy to manage pulseaudio or MPD. A lovely general purpose linux app called websocketd from Joe Walnes provides a web-socket interface for any linux application (e.g. python, C, bash).It runs as a single executable which opens a linux port and passes data to and from an associated linux program. For my purposes I setup port 8080 communicating with a bash script webmrs.sh. In a JavaScript webpage a user opens a web socket ws://PI3:8080. Links within the webpage cause data to be sent to the socket. This data is passed via websocketd to webmrs.sh which looks at it to determine which script to call. Any output from the script is sent back to the web page for display or processing.
For testing we can run scripts locally as user pi. We can then associate a script with the daemon starting websocketd as user pi. There is a high likelihood that the script will work in the same way which is different from lighttpd cgi scripts that run as user www-data. User pi also has the sudoers capability so sudo can be inserted in scripts to use system functions. Finally the daemon can be added to startup to run as user pi (which is required for pulseaudio control).
Web programming interface
Demo program
MPD clients are available to control our music from phone, ipad, Windows and web browsers. If we want our own tailored interface we need tools so that we can write programs which communicate over the LAN with RPi. MPD.js provides exactly that functionality. You build a webpage using JavaScript, html, css as normal and MPD.js provides you with functions interrogate MPD about its setup and status and control MPD in the same way as other clients.On the server MPD doesn't provide a capability to communicate via web sockets and a python program call websockify runs on PI3 listen on port 8800 and pass any information to /from the MPD port 6600. It is a beautifully elegant solution, which can work for other applications as well.
A test program is provided by bobboau to show how MPD.js works. As suggested I started a simple web server on PI3 port 8001 as user pi with python -m SimpleHTTPServer 8001 and put the demo application folder plus mpd.js in /home/pi/html. Accessing port 8001 from a browser provided me with a /home/pi directory and I was able to run demo/index.html to view / control MPD.
Debugging
Initially playlist functionality didn't work on the demo app so I needed to dig into the code a bit. The application is written in html, javascript and jquery. Two js include files (websock and util) provide the interface to websockify. The main processing script mpd.js contains code to obtain information from mpd or send commands to mpd via websockify. It keep track of the playlist queue, current track, time, volume, available playlists etc available in js objects. UI.js provides a number of jquery functions to format this information in html. A html webpage can then be constructed calling UI classes and methods to view information and send mpd commands.Due to my very rusty js knowledge I initially had problems writing my own js functions to communicate with mpd using mpd.js. However as soon as I realised that I needed to use the function on('StateChanged',xxx) and obtain the mpd state within that function all was straightforward.
Using the developer console (F12) in chrome or edge with console.log statements makes it quite easy to follow code. One area that tripped me up is that, particularly with chrome, javascript code needs to be manually refreshed in the browser to update it.
A small error was found in UI.js which referred to an element playlists.playlist.playlist which should have been playlists.playlist. Presumably this was caused by a change to mpd. I updated websockify include files to make sure we have the latest software but mpd.js is 3 years old so some incompatibilities may have crept in.
Implementation
We chose which MPD.js functions to use in the web app.Information Display
- Artist, title
- song duration, time elapsed
- play state (play, pause, stop)
- track current playlist
Control
- Choose radio station to stream
- Choose recorded radio playlists (without adverts)
In addition, when looking for the best way to play an album I found that there was already feature to browse the music directory structure and add tracks. I was able to modify this to add entire albums instead.