A small Linux appliance that played audiobooks in different rooms of a facility, each room on its own. Pause one, rewind another, browse a shared library on a tablet. I built it for a family member, because none of the off-the-shelf options did this well or cheaply enough.
Architecture
MPD's multi-output mode mixes at the ALSA layer, so you can't pause one output without the others. So each zone is a separate MPD instance, with its own port, state file, sound card, playlist, clock and volume. Twelve by default, all sharing one music directory.
The Go service
The AngularJS UI talked to a small Go HTTP service, not to MPD. It used
fhs/gompd for the MPD protocol and
gorilla/mux for routing.
/mpd/{command}: status, library, current track, pause, resume, fast-forward, rewind./tracks/...: changes to the playlist.
case param == "longstatus":
var longstatus string
status, _ := conn.Status()
track, _ := conn.CurrentSong()
switch {
case status["state"] == "play":
longstatus = "Playing - " + track["Album"] + " by " + track["Artist"]
case status["state"] == "pause":
longstatus = "Paused - " + track["Album"] + " by " + track["Artist"]
default:
longstatus = "Stopped"
}
return longstatus, nil
The 30-second fwd and rwd jumps clamp at the start and end of the track. An
audiobook chapter is sometimes only a minute and a half, and without the clamp
the seek ran off the edge.
The Python configurator
Twelve zones meant twelve mpd.conf files, twelve Upstart scripts and twelve
state directories. A Python script generated them from a config string with
NNN placeholders:
for x in range(1, 13):
xstr = str(x).zfill(2)
# Generate a per-zone "Hello world. This is zone N" greeting, one-time
textToWav('Hello world. This is zone ' + str(x),
'/usr/share/mpd/music/zone' + xstr)
directory = "/usr/share/mpd/zone" + xstr
# ... per-zone mpd.conf and Upstart script written from templates
mpdconf.write(confstring.replace("NNN", xstr))
textToWav bakes an espeak greeting into each zone's music directory, so
the first sound out of every speaker after provisioning is "Hello world. This
is zone three." in a robot voice. If the right number comes out of the right
speaker, the wiring is right.
Library
Books are folders on disk with ID3 tags for the metadata, Artist for the author and Album for the book, and adding one meant SFTPing the folder in, hitting Rescan in the UI, and letting every MPD update its database. The UI's filter pane narrows the library to one book, and Add Book queues the whole thing. That one button is most of what anybody ever touched.