Wednesday, September 14, 2011

HOWTO: Stream mp3's with icecast on Ubuntu / Rackspace Cloud

In this post I'll explain how to set up a streaming audio server in the cloud. We'll be using Rackspace Cloud (Slicehost) running Ubuntu Lucid in the examples. I'll explain the steps in brief first, and then in detail, indicating places where you may need to back up and do extra work, depending on how your system is configured. This howto is meant for people who have experience configuring Linux servers, but are a little lost in the particulars of getting an Icecast server up and running (I couldn't find a good step-by-step guide when I did this). You should be familiar with ssh, installing packages with apt-get, and using make to compile from source.

Streaming mp3's, the basic concept: you put mp3's on your cloud server, you set up a streaming audio server, and people listen using a web client that points to your cloud server. This requires 2 applications - Icecast2 and Ices. This was the first point of confusion for me. Icecast2 is a web server that clients (like iTunes, or a browser) connect to in order to get the streaming audio signal. However, the conversion of binary files to streamable audio data is accomplished by a different app, Ices. Ices and Icecast2 don't have to run on the same server - you can configure them so that the mp3's come from one machine (like one in your home or office) and then get streamed up to your Icecast server, which in turn streams out to multiple listeners on the internet. For this example, both Ices and Icecast2 will be running on the same virtual machine.

Setting up Icecast2 is straightforward enough - I used the instructions in this tutorial on Ices2 requires a little bit more work though. The problem with the example is that by default Ices only works for files encoded in the Ogg Vorbis format (.ogg). In order to get Ices to play mp3's, we need to grab the right libraries and build it from source.

If you have an account you can check the thread here for instructions. If you don't have an ubuntuforums account, I'll explain here (since getting an account on that forum just to read an archived thread took like 20 validation steps).

You'll need to install the following packages:

libmp3lame-dev isn't part of the standard Ubuntu distro so you'll need to edit your /etc/apt/sources.list file to include packages from the Ubuntu Multiverse.

I also already had libxml and jackd installed on this system - so install these packages as well. (TODO: figure out if these packages or any of their dependencies (more likely) are actually needed for Icecast / Ices)

To install Ices from source:
Download the ices0 source package from and extract it to your home directory on your cloud server. Then cd to the source directory and run the following commands:
sudo make install

Now you'll need to set up an Ices configuration file to tell Ices where to find your mp3's. This thread gives a good example of the format (the last code sample posted). You can also check the ices.conf.dist file in /usr/local/etc/ The file should be called ices.conf and live in /etc/ices/ I use a playlist file called "playlist.txt" in the same directory as the ices.conf. The playlist.txt file is just a plaintext file with the full path of each mp3 I want to play on its own line (be sure to trim any whitespace from the end of the lines, I had problems with ices not finding files due to trailing whitespace.).

You may need to tweak your icecast2 file in /etc/init.d - make sure it has the line
ICES="/usr/local/bin/ices -c /etc/ices/ices.conf"
To load the right ices.conf file when the daemon starts.
You can now start icecast by running /etc/init.d/icecast2 start - if you want uptime insurance, you can set up a monit process to restart icecast if it crashes. Just add the following code to your monitrc file (assumes you have icecast running on port 8000):

check process icecast2 with pidfile /var/run/icecast
start program = "/usr/bin/sudo /etc/init.d/icecast2 start"
stop program = "/usr/bin/sudo /etc/init.d/icecast2 stop"
if failed port 8000 protocol HTTP
request /
with timeout 60 seconds
then start

if failed port 8000 protocol HTTP
request /
with timeout 60 seconds
then alert