Wednesday, 9 May 2018

Multiroom RPi Music Server Added Functionality

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.


Friday, 4 May 2018

Multiroom RPi Music Server - Superstructure

Introduction

Previous blogs told the story of the Multiroom Music Server (muse) upto the point where music can be played throughout the house and controlled by various clients.  There is more to be done to make the system "multi-user", by which I mean that others in the house can and will use it.  Without a little bit of useability it will quickly become a relic.

System Startup

The components that need to be running at system startup are:
1 Share(s) to music folders on other systems need to be mounted
2 pulseaudio needs to be started - as user pi
3 ympd is started to allow web access/control on port 6800
4 bluetooth connection is made to the jongo
5 mpc play command is issued to start playlist if there is one.

Bluetooth and mpd services start automatically
Pulseaudio currently has to be started as user pi so some care would be necessary if this was automated.
MPD can access Samba/cifs shares if they have been defined on the host and a mount command has been issued at startup.
MPD can also access music via a web-site URL if it has been setup.  I have made albums available through shares.  Rplay, my internet personal music player, accesses music through the RPIP web-site so Rplay playlists coopied into MPD contain web URLs which MPD can use to obtain music over the network.

Bluetooth Connection

My RPi version 3 (PI3) connects to bluetooth quite reliably using the in-built bluetooth adapter.  However it disconnects from a Jongo after about 10 minutes activity so will not be always available.  Clearly we don't want our users to have to ssh into the server to start bluetooth.
The easiest way to start up bluetooth is to run a CGI script from RPI3 web-site which does a bluetooth connection with the utility bluetoothctl.  Similarly to check the bluetooth status from the webpage we can use the bluetoothctl info command.
Pulseaudio should be running before bluetooth is started so that can see the new bluetooth device as a "sink".

bluetoothctl is a good utility, intended for command line use, which provides the functions you require to manage connections.  As a one-off you need to pair with a device and make it trusted. At any stage you can use the info command to obtain status for a device.  The connect and disconnect are used to link/unlink a device. Tab is very useful on the bluetoothctl command line to complete mac addresses or commands.  Two formats used in scripts to pipe input in are shown below:
echo -e "info $jongoAdr\nquit" | bluetoothctl
and
bluetoothctl << EOF >/dev/null
power on
agent on
default-agent
disconnect 00:15:83:6B:38:93
quit
EOF

URLs

Music Server Web based functions should only be used within the local network so utilise local IP addresses.  To provide easy access we have a public DNS name music.helliwell.org which works anywhere.
The main option provided is access to the ympd program running on PI3.  It may be useful for this to have its own public DNS.
For the sysadmin the most useful option is to to control the application on server PI3.  Shell scripts can obtain information on whether pulseaudio, bluetooth and MPD are running.  I use lighttpd which runs as user www-data.  This is able to switch bluetooth functions but cannot easily start pulseaudio (pi user) or MPD (mpd user).  For the moment the screen allows me to check whether pulseaudio and bluetooth are running and, if pulseaudio is active but bluetooth is not I can start bluetooth.  MPD shows results of status command.  Screen refresh every 5 seconds confirms whether start/stop bluetooth commands are successful.
A third Music Server option is provided allowing you to access MPD port 8000.  This streams music directly to your device as opposed to sending it to bluetooth speakers.
An instruction page has also been included for those keen enough to install client apps on Windows, IoS or Android.  You need to know the music server IP (192.168.0.33) and port address (6600) to be able to do this.  There is also a learning curve to use the clients, eg to find and play albums, to find radio stations amongst the playlists.

Music

Albums are stored on rpip and accessed via a samba share rpipmusic.  Within client apps they can be browsed through artist or file-system lists.  Generally you want to play an entire album.
Some streaming radio stations, notably capital, absolute, BBC 4, absolute 70s and absolute 80s have been setup up as playlists which are accessible with names ending in _radio.

Rplay

Rplay is my music playing app based on streamripper which divides the stream into individual songs and stores them on disk.  Files are labelled with the track name (transmitted in the stream).  My scripts takes these tracks, removes advertisement breaks (which have different names) and creates track name and location lists.  These are then inserted into the Rplay web page and can be controlled by the user.
Rplay was designed to work in a browser on a device, it resides on rpip is accessible externally so can be used on a train, at the gym etc (providing you have wifi or enough data).
I amended Rplay so each playlist has an M3U file containing track information.  This is passed to PI3  (there is a copy each time PI3 is started using playlistupdate.sh) and the playlists are available to select in MPD client playlists.  MPD loads tracks as web URLs like Rplay.