Starting a user-controlled streaming radio station

The dream:
I want a streaming radio station for my company that itunes can tune in to, where anyone at work can upload tracks and add them to the playlist.

The ingredients:

Explanation:
MusicPD is an awesome music server that I’ve talked about before, and it would be perfect for setting up my little radio station. Users would be able to add files to the playlist from any browser, and mpd now supports shoutcast, which should make turning it into a streaming station easy.

However, right now mpd only supports shoutcast streaming in OGG Vorbis format, and iTunes can’t play OGG. Since everyone in the office is on iTunes, I need some way of getting mpd to spit out mp3 to icecast.

Enter JACK! Jack is a “pro-audio” subsystem for connecting applications, kind of like shell pipes for audio. It can be kind of daunting to work with, but in this case it’s best to just think of it as glue connecting one program with another.

For instance, mpd has a JACK output plugin, and there’s another program, Darkice, that has a JACK input and sends audio to icecast. I can link mpd and darkice with jack, and that should solve my mp3 problem.

So, to review:
mpd (links via JACK to) darkice (which encodes mp3s for) icecast (which streams to) itunes

The Wrinkle:
Make it work on a mac server. At work we don’t have a recent machine running linux that’s up all the time and that isn’t mission-critical, so I have to make due with one of the mac workstations. Luckily macports will do a lot of the heavy lifting.

A Note:
This took a lot of building, installing, and configuration that I don’t have space to cover here. I’m trying to record everything I did that was abnormal or not obvious. If you’re comfortable installing software on unix and you know how to configure a program based on the examples and READMEs, there should be enough information here to reproduce my work.

Getting the software:

  1. Install macports on the mac
  2. Install the following ports: apache2 faac faad2 flac id3lib mad lame libid3tag libvorbis speex
  3. Install this port: php5 +apache2 +macosx +pear
  4. Install the following by source: curl, jack (do not use “jackosx”, build it from source), icecast, darkice, mpd
  5. Apply my patch to mpd/src/audioOutputs/audioOutput_jack.c to make it work on mac osx.

Details:

JACK:
Built with these options: ./configure --prefix=/opt/local --with-default-tmpdir=/tmp
I just start JACK with jackd -d dummy -r 44100

If I don’t specify a default tmpdir, jack crashes complaining it can’t stat /dev/shm. I don’t need to use a real audio device in jack because I’m not outputting the audio to the speakers.

Icecast:
built with ./configure --prefix=/opt/local
No special configuration needed other than what’s specific to my site.

Darkice:
Built with ./configure --prefix=/opt/local/ --with-lame-prefix=/opt/local/ --with-vorbis-prefix=/opt/local/ --with-faac-prefix=/opt/local/ --with-jack-prefix=/opt/local/
I probably didn’t need all those options, but heck, it works.
I set up the configuration file so that the audio device is jack (no quotes).

MusicPD:
built with ./configure --prefix=/opt/local --with-faad=/opt/local --with-libFLAC=/opt/local --with-mad=/opt/local --with-libvorbis=/opt/local/ --with-id3tag=/opt/local
I set up the configuration file to use jack as a device. I need to tell mpd to connect to darkice when it starts up, but darkice picks its port names based on its pid, so it’s always different. What I did is create mpd.conf.in, with this as the device config:

audio_output {
type "jack"
name "MPDJack"
ports "darkice-REPLACEME:left,darkice-REPLACEME:right"
}

Then I run a script to actually start mpd:
#!/bin/bash
pid=`jack_lsp | grep darkice | cut -d '-' -f 2 | cut -d ':' -f 1 | uniq`
cat mpd.conf.in | eval sed -e 's/REPLACEME/$pid/g;' > mpd.conf
mpd ./mpd.conf

Putting it all together:
Once all of those pieces are in place, I can start the radio station by starting the various programs in this order:

  • Jack first,
  • then icecast,
  • then darkice, (-v 10 for debugging)
  • and finally mpd. (--verbose --stdout --no-daemon for debugging)

That’s it. I can control the mpd server and it plays music. If I run jack_lsp -c -p I can see mpd is connected to darkice. I can tune in to the icecast stream from itunes and hear it. With simple mac file sharing, users can connect to the server and drop music in the database. Then mpd can either rescan every hour or so with cron, or when the user clicks “update db” in pitchfork.

Setting up pitchfork is left as an exercise for the reader.

Linux Tip: How to clear some room

I’ve been running out of disk space on my laptop. Multiple development environments, vmware images, my music collection, and especially my camera RAW originals take a heavy toll. Most data on a computer is already highly-compressed, but the whole idea behind RAW files is that they are not compressed — they represent the original image sensor data. So, here’s a one-liner I used for freeing up some disk space. (I have an Olympus camera, whose raw file format has the ORF extension.)

find ~/Documents/images/photos/raw -name "*.ORF" | xargs -n 1 bzip2

Just using standard bzip compression reduces each file by about 50%. And, since I had 10 gigs of raw files, that translates into 5 gigs of space I’ve freed up.