Building a Shoutcast Server
I visited a friend of mine who had copied all his CDs to hard disk, using the Itunes system, and buying a dedicated player that hooked into his hifi. I began to wonder if I could do the same, but for free (or, more accurately, for no money).
First, I copied all my CDs to mp3 files using ripit, although I installed the standard package available under Debian etch.
Next challenge was how to get these mp3's playing on the hifi. Some
sort of internet radio broadcasting thing, I guessed. I poked
around the Shoutcast site and
discovered I could pretty easily do what I wanted using the Shoutcast server
(agreeing to a licence required) and broadcasting utilities (now no
longer available) from
http://www.shoutcast.com/downloads/sc_trans_posix_040.tgz.
The server handles the delivery of content to clients, while
sc_trans defines what the content is. Both of these come
as Linux binaries, so if you are leary of binaries, you might want
to look at other sources of supply.
I installed both of these packages on my main Debian box and
configured them. The server is fairly easy, and the config file is
well commented. I configured sc_trans to deliver random
content from a playlist file (just a list of mp3 files).
In order to ease the creation of playlist files for my collection of
mp3 files, I wrote a small python program playlist.py, which created
playlists based on a simple database of categorised mp3
directories. All the ripped music lives is the
/rep/music/mp3 directory, each subdirectory holding a CD's
tracks. E.g:
johnny_lytle_-_the_loop_-_new_and_groovy/ josh_rouse_-_nashville/ stacey_kent_-_dreamsville/ kevin_ayers_-_the_confessions_of_dr_dream/
The database is a text file, each line consisting of a directory name (i.e. CD) and category, separated by a colon ":". More than one category may be assigned; multiple categories are comma "," separated. So, the above album directories could be represented as:
johnny_lytle_-_the_loop_-_new_and_groovy:jazz josh_rouse_-_nashville:rock stacey_kent_-_dreamsville:jazz kevin_ayers_-_the_confessions_of_dr_dream:rock,prog
playlist.py allows the creation of playlists, based on
categories one specifies on the command line. For full details,
you'll need to look at the source code.
To control the server and broadcast playlists, I generated a GNU make file. The targets provided are:
- start - start server and broadcaster
- stop - stop server and broadcaster
- playlists - generate all playlists based on current database
- use - make a specific playlist the active playlist
- skip - skip to next song in playlist
- reload - reload playlist (good if you changed it in mid-broadcast)
- clean - delete log files
Once this thing was broadcasting on the LAN, I could use yet another
knackered laptop from work, now running Debian, to act as the
client. It had a wireless card, so all I had to do was fire up
xmms and plug the headphone outlet into the hifi. How easy
was that?
Here's the Makefile:
# Make file to control shoutcast server
.SILENT:
.PHONY: start stop clean skip reload playlists use
MR=/rep/music
PID-TRANS=${MR}/pid.sc_trans
PID-SERV=${MR}/pid.sc_serv
start:
if [ -r ${PID-TRANS} -o -r ${PID-SERV} ]; then \
echo "Server already running" ; \
exit 1 ; \
fi
cd ${MR}/sc/sc_trans_040 ;\
./sc_trans_linux </dev/null >/dev/null 2>&1 & echo $$! >${PID-TRANS}
cd ${MR}/sc/server ;\
./sc_serv </dev/null >/dev/null 2>&1 & echo $$! >${PID-SERV}
echo "Shoutcast server and transcoder started."
stop:
if [ -r ${PID-TRANS} ]; then \
/bin/kill -TERM `cat ${PID-TRANS}` ; \
fi
if [ -r ${PID-SERV} ]; then \
/bin/kill -TERM `cat ${PID-SERV}` ; \
fi
rm -f pid.*
playlists:
find `tools/playlist.py -a` -type f -name "*.mp3" >playlists/all
for genre in `tools/playlist.py -l`; do \
find `tools/playlist.py $$genre` -type f -name "*.mp3" \
>playlists/$$genre ;\
done
use:
ifndef cat
${error Must specifiy category with cat=}
endif
if [ -r ${MR}/playlists/${cat} ]; then \
cp ${MR}/playlists/${cat} ${MR}/sc/sc_trans_040/playlist ; \
else \
echo "No such playlist: ${cat}" ; \
fi
skip:
kill -WINCH `cat ${PID-TRANS}`
reload:
kill -USR1 `cat ${PID-TRANS}`
clean:
find ${MR} -type f -name "*.log" -delete