LJ Archive

Roaming Media

Michael Nugent

Issue #211, November 2011

Portable music doesn't need to be restricted to headphones. Here's a step-by-step how-to on setting up a music system that follows you around the house like a puppy.

Like many of you, I store all my music digitally on a central server in my home. The problem is when I walk from room to room, my music doesn't come with me. I could carry around an iThingy or put it on my phone, but I'd rather not have to wear headphones, and no matter how awesome they are in their class, tiny phone speakers still are tiny phone speakers. Fortunately, I have a lot of computer hardware lying around from past upgrades, so it was fairly easy for me to come up with some small, older systems for each area of my house. Now, instead of listening to music on a little device, I use a device to tag my location and have the music follow me wherever I go.

The system is easy to build and uses mostly off-the-shelf open-source programs. In addition to the player and control system, you need a way of tagging your location in the house. I use the Bluetooth radio on my phone, but you also could use RFID tags, Webcams with motion detection or facial recognition, or pretty much anything else that will let the system know where you are. For this setup though, I'm assuming you're using a Bluetooth device.

The central piece to this project is a server-based music player. I am using the Music Player Dæmon (MPD), a wonderful server-based system released under the GNU General Public License and available from the repositories of most Linux distributions. Install the software with your favorite package management system. In addition to this player, you need to set up a streaming system. Icecast fulfills this requirement and also is widely available. Install it as well.

Configuring MPD is fairly straightforward. The default file for your distribution is probably very similar to the example below, but you may need to change a few things. The music_directory entry should point to the directory that contains the music files and one bind_to_address should contain the non-loopback name or address of the server. If it binds only to 127.0.0.1, outside boxes may have trouble connecting to it.

The audio_output section defines where the music goes when it plays. In this case, you want to transcode it to Ogg format and send it to the Icecast server on the same host (although you could run these on different systems if it makes sense for your setup). Within this section, the port and password must match the configuration for the Icecast server, and the mount will define the portion of the URI after the server name. For simplicity, I've left it at /. If you start MPD after this configuration file is set up, it will be missing the Icecast socket to play to, so you need to set that up next. I've added some comments to the configuration below to help document the options there:

music_directory     "/data/arown/files/audio"  #Point this at
the top level of your music directory. If you have more than 
one, a directory of symbolic links may help you.
playlist_directory  "/var/lib/mpd/playlists" #The following
files must be writable. I suggest making the directory owned 
by the user running MPD.
db_file             "/var/lib/mpd/database"
log_file            "/var/lib/mpd/log"
state_file          "/var/lib/mpd/state"

user                "mpd" #This is the user that the MPD
program runs under. I highly suggest making this a nonroot user.
bind_to_address     "templar" #Place your machine name here, not
"localhost" or "127.0.0.1" if you want to reach the MPD
server from another machine.

bind_to_address     "/var/lib/mpd/socket"
port                "6600" #This is the client control port for
starting and stopping the MPD player as well as building 
playlists and changing server side volume.
log_level           "verbose"

input {
        plugin "curl"
}

audio_output {
        type        "shout"
        encoding    "ogg" #This is the media type for the stream, 
if your player wants MP3, use encoding "mp3" and be sure you 
have the proper tools to transcode to MP3 on your box.
        name        "MusicPuppy"          
        host        "localhost" #The name of the box
that the Icecast server is hosted on.
        port        "8000" #The port of the
Icecast server.
        mount       "/"  #This is the part
of the URI after the hostname. I have left it to "/" for
simplicity, but often things like "/music.ogg" are used 
to make it clearer to the user.
        password    "passthis"  #The source password to the
Icecast server. You probably should change this to something 
complex because you'll never have to type it in.
        bitrate     "128" #The bitrate to transcode to. You 
may want to raise or lower this based on your CPU, bandwidth 
or your quality preference.
        format      "44100:24:2"  #This is three variables:
44,100 represents the sample frequency, 24 is the bitwidth, 
and 2 is the number of audio channels. Experimenting here 
may give you better or worse quality, depending on your audio 
hardware and number of speakers.
}
filesystem_charset "UTF-8"

In order to finish off the server portion, you need to configure Icecast to stream the music it receives from MPD. The sample Icecast configuration file is quite long, but I've cut out the areas that I've changed.

Make sure that the source-password here matches the password from the MPD server. This allows the MPD server authorization to stream music to Icecast:


<authentication>
    <!-- Sources log in with username 'source' -->
    <!-- This password must match the MPD password above -->
    <source-password>passthis</source-password>
    <!-- Relays log in username 'relay' -->
    <relay-password>passthis</relay-password>

    <!-- Admin logs in with the username given below -->
    <admin-user>admin</admin-user>
    <admin-password>passthis</admin-password>
</authentication>

Be sure that the bind addresses and ports are correct. The bind address can be localhost if the MPD server is on the same box. The port must match the port from the MPD configuration above:


<listen-socket>
    <port>8000</port>
    <bind-address>127.0.0.1</bind-address>
</listen-socket>

While you're in this configuration file, change the default passwords from “hackme” and “hackmemore” to something more secure, and check the location of the logs for debugging. Mine are in /var/log/icecast, but yours may vary.

After you start Icecast, the server configuration should be complete. At this point, start MPD as well. It should hook itself up to the Icecast port, and the logs should be free of errors. Next, an MPD client is needed in order to set up playlists on the server. I use MPDroid for this, an Android variant I use to control playlists from my phone, but there are clients for a wide variety of platforms available via your package manager or from mpd.wikia.com/wiki/Clients. Fire up a client, and add a few songs to a playlist for a test and tell it to play. The Icecast access log (not the MPD logs) should show that a SOURCE has connected, and it should show a 200 return. For example:

127.0.0.1 - - [20/Jul/2011:01:15:03 -0700] "SOURCE / 
 ↪HTTP/1.0" 200 19 "-" "MPD" 424

This shows the incoming connection from MPD on the local box, the current date and time and the fact that this is a SOURCE request as opposed to a player request. It shows the directory accessed “/”, the protocol used and the return code “200”. This is a great source of verification that the connection between MPD and Icecast is up and working properly, though it does not tell you that any data actually is being passed. For that, you'll need to test it end to end.

To test it, you need a music player that supports Ogg format (or MP3 if you've gone that route). I've chosen Rhythmbox for this example, because it supports Ogg, is popular across a wide range of distributions and has a command-line control system that you can use to start and stop the music as well as set the server URI. Install and launch Rhythmbox (or fire up your favorite player with these features) and set it to play from the Icecast URI. For example, mine is at http://templar:8000/. If you have changed the mount directive in the MPD configuration file to "/music.ogg", the URI would then be http://templar:8000/music.ogg. Either way, when the music player is pointed at this URI, the Icecast access.log file should show something like this:

mj-12 - - [01/Aug/2011:15:28:52 -0700] "GET / 
 ↪HTTP/1.1" 200 1194382 "-" "-" 70

The format for this line is very similar to the one above. The only real difference is that this is a GET request instead of a SOURCE request. Seeing this line in the access logs without a corresponding error in the error log shows you that the media player is requesting the music stream from the Icecast server properly.

If you don't hear music at this time, go back over the setup and check the log files. Check the volume level within MPD, and make sure that the MPD client says a song is playing. Many MPD clients also let you stream music directly, so you can verify that it's working as well.

The next step is to set up your Bluetooth token. In my case, this is my Android phone, but pretty much any Bluetooth device will work. Ranges vary, so placement of the Bluetooth receivers is important to avoid overlap or gaps in the area you're trying to cover.

The Linux package for Bluetooth support is called Bluez. It is widely available and comes as part of most distributions. Install this package if it is not installed on your system already. You don't need to make any configuration changes, because all you need to do is identify that the Bluetooth device is in range. You don't need to pair with it or transfer data between devices. After installing the Bluez package, start the software. Your logs should show that the software started correctly and that it identified your Bluetooth hardware properly.

In order to find the Bluetooth token, it needs to be put into discoverable mode temporarily. Turn that on, and run the following scan command from the command line:

mike@templar:~$ hcitool scan
Scanning ...
	D4:E9:C0:37:00:0D	eris

Make a note of the Bluetooth ID, and be sure that the name field is not blank. It can be anything, but it has to be something. After this step, you can turn off the discoverable mode on the Bluetooth device for increased security. You now have all the information that you need.

The following script checks whether the Bluetooth device is in range and stops or starts the music player based on the result. Replace the SERVER_URI variable with your MPD/Icecast server and the BTADDR variable with your device's Bluetooth ID (this ID comes from the hcitool scan command above):

#!/bin/bash
SERVER_URI="http://templar:8000/"
BTADDR="D4:E9:C0:37:00:0D"

DBUSADDR=`grep -z DBUS_SESSION_BUS_ADDRESS /proc/*/environ 2> 
 ↪/dev/null|
sed 's/DBUS/\nDBUS/g' | tail -n 1`

if [ "x$DBUSADDR" != "x" ]; then
  export $DBUSADDR
else
  echo "Cannot find DBUS Session for Rhythmbox. Please 
be sure the application is running"
  exit 1
fi

NAME=`hcitool name $BTADDR`

if [ -z "$NAME" ] ; then
    `rhythmbox-client --pause`
else
    `rhythmbox-client --play-uri=$SERVER_URI`
fi

Save this script as /usr/local/bin/musiccontrol.sh. Next, add the script as a crontab entry that runs every minute. This entry must be run as the same user as the user that owns the Rhythmbox process.

Edit the crontab from the correct user:

mike@templar:~$ crontab -e

Add the following line, and then save and exit:

* * * * * /usr/local/bin/musiccontrol.sh

Now, turn on the Bluetooth device (it does not need to be discoverable this time because you already have the address). At the turn of the next minute, the cron script will see the Bluetooth device and then tell Rhythmbox to start playing the music from the MPD/Icecast server. If you move the Bluetooth device out of range, the cron script will no longer see the Bluetooth device and will stop the music.

Rhythmbox, Bluetooth and this cron script must be set up on every machine that you intend to play music for you. If you do it on only one box, only that box will start and stop music as you enter or leave range. If you set up the system on multiple pieces of hardware, it will transition the music for you. When moving out of the range of one server and into the range of another, the music automatically will stop in the room you were in before and start in the room you are in now.

This is just a simple setup for moving media around automatically. Multiple Bluetooth devices could be set up for different members of the house, and a priority system could be put in place. Motion detection using the “motion” package could be set up to differentiate areas of your home further with overlapping Bluetooth. You even could use facial recognition with help from the OpenCV Project. There are many places you can go from here.

Michael Nugent has spent a good deal of his time designing large-scale solutions to fit into a tiny budget and leveraging Linux to fulfill the roles that typically would be filled by large commercial appliances. Recently, Michael has been working to design map-reduce clusters and elastic cloud systems for growing startups in the Silicon Valley area. When not building systems, he likes sailing, cooking and making things out of other things. Michael can be reached at michael@michaelnugent.org, and code and notes for this article can be found at https://github.com/michaelnugent/MusicPuppy.

LJ Archive