A few years ago I was working with little via eden boards as thin clients with the Linux Terminal Server Project (LTSP). This worked great and I quickly became excited about using these little mini-ITX boards for other projects. At one point (about three or four years ago) I bought one of these boards on ebay for a hundred bucks to play with. Due to priorities it had sat collecting dust since. Well recently my wife started talking about wanting to play the same audio content from multiple devices synchronously. This led to some discussion about streaming from one location and finally to the idea that I might have a use for that little board.
After some playing with different streaming technologies such as icecast and squeeze server I finally landed on shoutcast. There are pro’s and con’s to each of the different servers and tech but for her purposes shoutcast just seemed to be obvious choice. The streaming server is on a winxp system with winamp on the same system to direct the stream. Of course if you’ve ever messed with shoutcast you know you can pretty much stream from any system using winamp so it’s kind of flexible.
Once I had all of the services set up I broke out the eden board. It’s one of those spiffy ones with the pcmcia slot on board. I set it up with an old linksys wpc11 card and a 2Gb CF IDE drive for a hard disk that cost me $40. I used an external usb cdrom to install debian from netinstall. Now would be a good time to point out that this could probably be done ALOT cheaper other means but since I had a bunch of this junk laying around I thought why not just use it. After getting deb setup and all updated I started to tackle the problem of making it do what I initially intended for it.
I configured the wireless tools to automatically join my wifi network. I then setup dns and dhcp to give this box a static address that is resolvable from inside the house network. This box would be named thinplayer.castleberry-farms.com. Once the box was setup and accessible from the network I had to figure out how I was going to play a shoutcast stream headless without any user intervention. Well it turns out that you can play shoutcast streams using a cli utility call mpg123. The problem lies in getting the command to act like a daemon. In comes DJB Daemontools to the rescue. If you’ve never used daemontools before let me give you a brief rundown.
Daemontools allows you to automatically monitor a command and treat it like a daemon. Where I work we use it for running j2ee web containers such as tomcat and it works beautifully. If the process exits the supervise process kicks off a new one. It has a built in logger that handles rotation and removal and can be setup with all kinds of environmental variables that are used solely within it’s process management.
In order to stream a shoutcast stream using mpg123 you would use a command such as: mpg123 -C -b 4096 -@ http://stream/listen.pls. If the stream somehow dies or the connection is broken then mpg123 exits. So here is how I setup daemontools to take that command and run it like a daemon. First I needed to setup a directory structure. In opt I created a thinplayer/service directory. Then I set up an env and log directory under service. Under log you need an env and main directory. Then I went into /opt/thinplayer/service/env and created some environmental variables. I created the variables: ARGS, COMMAND, URL and USER. I populated them with simple echo statements such as: echo “/usr/bin/mpg123″ > COMMAND. The variables represent the arguments passed to mpg123, where the command itself is located, the url of the stream and the user to run as. Initially I have this all running as root which is a bad idea. I was having some difficulty allowing my player user to access the sound card and just didn’t want to mess with it yet. Once I get that lined out I will change this to be running as a protected user. After the arguments are set up I went back to /opt/thinplayer/service and created a file called “run” (vi run). It looks like this:
#!/bin/sh
exec 2>&1 \
envdir ./env \
sh -c ‘
exec setuidgid ${USER+”$USER”} ${COMMAND+”$COMMAND”} ${ARGS} -@ ${URL}
‘
I then went into the log/env directory and created the environmental variables MAXFILESIZE, MAXLOGFILES, and USER just like I did previously. I then went to /opt/thinplayer/service/log and created a run file (vi run) which looks like this:
#!/bin/sh
exec \
envdir ./env \
sh -c ‘
exec \
setuidgid ${USER+”$USER”} \
multilog \
t \
${MAXFILESIZE+”s$MAXFILESIZE”} \
${MAXLOGFILES+”n$MAXLOGFILES”} \
./main
‘
I then touched the file status (touch status). Now that everything is set up I linked in the service (ln -s /opt/thinplayer/service /etc/service/thinplayer). I ran an svstat /etc/service/thinplayer and tailed the logs to make sure everything looked good (tail -f /etc/service/thinplayer/log/main/current). In the log I see something a bit like this:
@400000004a90b29726bc0dc4 High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
@400000004a90b29726bdd2e4 version 1.4.3; written and copyright by Michael Hipp and others
@400000004a90b29726be4fe4 free software (LGPL/GPL) without any warranty but with best wishes
@400000004a90b2972c378ea4 Can’t get terminal attributes
@400000004a90b2972f67f2bc
@400000004a90b29730735fac Directory: http://stream:80/
@400000004a90b29730744624 Playing MPEG stream 1 of 1: …
@400000004a90b2973074af9c ICY-NAME: diskbox-stream
@400000004a90b29730751914 ICY-URL: http://stream
@400000004a90b29730fac3d4 MPEG 1.0 layer III, 128 kbit/s, 44100 Hz stereo
Which of course is the terminal output from mpg123.
After getting my streamer to work I needed some way for my wife to be able to interface with this without having to ssh to the box. It was all fine and good that I ssh and run svc -d /etc/service/thinplayer when I wanted to shut it down but not so fine for her. After thinking it over and because I’m rather partial to python I ended up going with python server pages on apache as the interface. I set up basic apache authentication with users for both her and I. Then I coded up a little python server pages application to control it. Here is a picture of the app I came up with:

So all in all an interesting weekend to set this up and get it going.