HomeRaspberry Pi › Radio
Equipment | Preparation | Station Database | The Script | How to Use | Version History | To Do
Raspberry Pi Model B

Radio Script

This will probably work on any computer that has a network connection and runs mpd but I used a Raspberry Pi. Goal: play internet radio via the command line and learn about Bash programming.

top↑

Equipment

top↑

Preparation

My setup is as follows: RPi Model B powered by micro-USB cable, ethernet cable from RPi to router, HDMI cable from HDMI port to home stereo. I use ssh -x pi@raspberrypi to log in to the RPi from another computer on the same router via ssh, without X11. Audio output might be impacted by more connections or other forms of remote access.

Bring your system up-to-date, install base audio tools and mpd/mpc, add yourself to the audio group (standard user pi is already a member), create a file called piradio in the /usr/local/bin directory (file content to be copied now or later from The Script), configure the mpd server dæmon. Commands:

sudo apt-get update
sudo apt-get -y dist-upgrade
sudo apt-get -y install avahi-daemon avahi-utils alsa-base alsa-tools alsa-utils mpd mpc
sudo adduser `whoami` audio
sudo touch /usr/local/bin/piradio
sudo chmod 755 /usr/local/bin/piradio
sudo nano /etc/mpd.conf
sudo service mpd restart

When editing the mpd.conf file, check or add the following lines, where raspberrypi is the hostname of your RPi (change it with sudo raspi-config but then also change these lines!) and .fritz.box is the DNS suffix of your local router (modem). It could be this or .lan or something else entirely. If you don't bind to "any" or to IP addresses explicitly, the following will work on a mixed IPv4/IPv6 network. At least it does on mine :)

bind_to_address		"localhost"
bind_to_address		"raspberrypi"
bind_to_address		"raspberrypi.local"
bind_to_address		"raspberrypi.fritz.box"

You might need to expressly select either the headphone jack or the HDMI port for audio output. In the cset variant of the following command, the last number determines which way the audio output goes: 0 = automatic (system default), 1 = headphone, 2 = hdmi.

amixer cget numid=3
amixer cset numid=3 0

You may also use amixer to set the system volume independent from mpd/mpc or other audio programs. Use a percentage from zero to a hundred:

amixer cset numid=1 85%
top↑

Station Database

The piradio script uses a file called .radiodb in your home directory to look up radio stations. Any station you wish to use, should be listed in that plain text file. Every station goes on a new line. Start with a Station ID (just make one up) and finish with the Stream URL. Separate the IDs and URLs with spaces or tabs. No spaces or tabs at the start or end of the line! Also, no spaces in the Station ID. Station IDs don't have to be unique but only the first match will be accessible. Below is my ~/.radiodb file with mostly Dutch and BBC radio stations. To create this file, upload it to your home directory (get it from my GitHub) or start with nano ~/.radiodb. If you change the name or location of the station database file, make sure to change The Script correspondingly where it says DBNAME=name and DBFILE=location.

fip	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-midfi.mp3
fip5	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio5.mp3
arrow	http://91.221.151.155:80/
10	http://stream.radio10.nl/radio10aac
class	http://19333.live.streamtheworld.com:80/CLASSICFMAAC.aac
1	http://icecast.omroep.nl/radio1-bb-aac
2	http://icecast.omroep.nl/radio2-bb-aac
3	http://icecast.omroep.nl/3fm-bb-aac
4	http://icecast.omroep.nl/radio4-bb-aac
5	http://icecast.omroep.nl/radio5-bb-aac
6	http://icecast.omroep.nl/radio6-bb-aac
bbc1	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio1_p
bbc1x	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_1xtra_p
bbc2	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio2_p
bbc3	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio3_p
bbc4	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio4_p
bbc4x	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio4extra_p
bbc5	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_5live_p
bbc5x	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_5sportxtra_p
bbc6	http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_6music_p
bbcws	http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-eieuk
bbcwn	http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws
stubru	http://mp3.streampower.be/stubru-high.mp3
mnm	http://mp3.streampower.be/mnm-high.mp3
klara	http://mp3.streampower.be/klara-high.mp3
frclass	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/francemusique-midfi.mp3
ancient	http://5.152.208.98:8058/
trip	http://ice.somafm.com/thetrip
ds1	http://ice.somafm.com/deepspaceone
space	http://ice.somafm.com/spacestation
192	http://server-14.stream-server.nl:8030/
bnr	http://81.173.3.251/
veron	http://8633.live.streamtheworld.com:80/VERONICAAAC_SC
sky	http://8543.live.streamtheworld.com:80/SKYRADIOAAC_SC
538	http://82.201.100.23/RADIO538_WEB_AAC
fresh	http://stream12.freshfmonline.com/
dB	http://91.221.151.253:80/
slam	http://vip-icecast.538.lw.triple-it.nl:80/SLAMFM_MP3
funx	http://icecast.omroep.nl/funx-bb-mp3
fip1	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio1.mp3
fip2	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio2.mp3
fip3	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio3.mp3
fip4	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio4.mp3
fip6	http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio6.mp3
nprmp3	http://current.stream.publicradio.org/kcmp.mp3
npraac	http://current.stream.publicradio.org/kcmp.aac
top↑

The Script

If you hadn't already, create an executable bash script file called piradio in the /usr/local/bin directory and start editing it: sudo nano /usr/local/bin/piradio. Copy all text from the block below and paste it into the piradio script, or download it from my GitHub. The GitHub might be slightly more up-to-date.

#!/bin/bash

#######################################################################
# Made by    : Ewoud Dronkert
# Licence    : GNU GPL v3
# Platform   : Raspberry Pi
# Requires   : Bash, mpd, mpc
# Location   : /usr/local/bin/
# Name       : piradio
# Version    : 1.0.0
# Date       : 2014-12-02
# Purpose    : Play radio streams via local mpd audio server
#              Use station abbreviations from user file .radiodb
# Parameters : <none> | <station> | list |
#              vol [ + | - | min | max | def | 0..100 ] |
#              on | off | help
# Exit     0 : success
#          1 : help displayed
#          2 : .radiodb local user file not found
#          3 : station abbreviation not recognised
#          4 : mpc executable not found
#######################################################################

# Variables
PLAYER=/usr/bin/mpc
DBNAME=.radiodb
DBFILE=/home/pi/$DBNAME
DEFVOL=85
ADJVOL=5

# Error codes
declare -i ERR_OK=0
declare -i ERR_HELP=1
declare -i ERR_DBNOTFOUND=2
declare -i ERR_IDNOTFOUND=3
declare -i ERR_APPNOTFOUND=4

# Copy/redirect output to stderr
function StdErr () {
	cat - 1>&2
}

if [ ! -x "$PLAYER" ]; then
	echo | StdErr
	echo "   Radio player not found: $PLAYER" | StdErr
	echo | StdErr
	exit $ERR_APPNOTFOUND
fi

# Help
if [[ "$1" == "help" || "$1" == "--help" || "$1" == "/help" || \
      "$1" == "-h" || "$1" == "/h" || \
      "$1" == "?" || "$1" == "-?" || "$1" == "/?" ]]; then
	echo | StdErr
	echo "   Usage:" | StdErr
	echo "   - Which station is on?  : radio" | StdErr
	echo "   - Tune to a station     : radio <station-id>" | StdErr
	echo "   - List all stations     : radio list" | StdErr
	echo "   - Show or adjust volume : radio vol [ + | - | min | max | def | 0..100 ]" | StdErr
	echo "   - Mute or unmute        : radio mute" | StdErr
	echo "   - Turn radio on or off  : radio on | off" | StdErr
	echo | StdErr
	exit $ERR_HELP
fi

# Display current station/stream/volume if no argument
if [ -z "$1" ]; then
	curvolume=$($PLAYER volume | grep --colour=never -m 1 -oP '\d+')
	curstream=$($PLAYER -f "%file%" current)
	if [ -z "$curstream" ]; then
		curstation="(no stream found)"
	else
		if [ -f $DBFILE ]; then
			curstation=$(cat $DBFILE | grep --colour=never -m 1 -F "$curstream" | grep --colour=never -oP '^\S+')
			if [ -z "$curstation" ]; then
				curstation="(station not found)"
			fi
		else
			curstation="(station database not found at \"$DBFILE\")"
		fi
	fi
	echo
	[ -z "$curstation" ] || echo "   Station : $curstation"
	[ -z "$curstream" ]  || echo "   Stream  : $curstream"
	[ -z "$curvolume" ]  || echo "   Volume  : $curvolume"
	echo
	exit $ERR_OK
fi

# List station IDs from station database
if [[ "$1" == "list" ]]; then
	if [ -f $DBFILE ]; then
		echo
		echo "   List of all stations:"
		cat $DBFILE | grep --color=never -oP "^\S+" | sort | sed s/^/\\t/
		echo
		exit $ERR_OK
	else
		echo | StdErr
		echo "   Station database not found at \"$DBFILE\"" | StdErr
		echo | StdErr
		exit $ERR_DBNOTFOUND
	fi
fi

# Turn radio on
if [[ "$1" == "on" || "$1" == "play" ]]; then
	# TODO: check if a radio stream is lined up
	$PLAYER play > /dev/null
	exit $ERR_OK
fi

# Turn radio off
if [[ "$1" == "off" || "$1" == "stop" ]]; then
	$PLAYER stop > /dev/null
	exit $ERR_OK
fi

# Display volume, optionally set or adjust or mute/unmute
if [[ "$1" == "vol" || "$1" == "mute" ]]; then
	declare -i curvol=$($PLAYER volume | grep --colour=never -m 1 -oP '\d+')
	declare -i newvol=$curvol
	declare -i minvol=10
	declare -i maxvol=100
	if [[ "$1" == "mute" || "$2" == "mute" ]]; then
		if (( curvol > minvol )); then
			# mute
			newvol=$minvol
		else
			# unmute
			newvol=$DEFVOL
		fi
	else
		if [ -n "$2" ]; then
			case "$2" in
				min) newvol=$minvol;;
				max) newvol=$maxvol;;
				def) newvol=$DEFVOL;;
				+)   (( newvol = curvol + ADJVOL ));;
				-)   (( newvol = curvol - ADJVOL ));;
				*)   newvol="$2";;
			esac
			if (( newvol >= maxvol )); then
				newvol=$maxvol
			elif (( newvol <= minvol )); then
				newvol=$minvol
			fi
		fi
	fi
	if (( newvol != curvol )); then
		# volume adjustment
		$PLAYER volume $newvol > /dev/null
		curvol=$newvol
	fi
	echo
	echo "   Volume: $curvol"
	echo
	exit $ERR_OK
fi

# Argument is a Station ID
# Escape argument for use with grep -P
# Is it really safe? Not sure. Couldn't make escaping ] work, for instance.
safe=$(echo "$1" | sed -e 's/\s*//g' | sed -e 's/[\[\\^$.*?"-]/\\\0/g')
[ -f $DBFILE ] && stream=$(cat $DBFILE | grep --color=never -m 1 -P "^$safe\s" | grep --color=never -oP '\S+$')

if [ -z "$stream" ]; then
	echo | StdErr
	echo "   Station \"$1\" not found." | StdErr
	echo "   List stations : radio list" | StdErr
	echo "   Usage info    : radio help" | StdErr
	echo | StdErr
	exit $ERR_IDNOTFOUND
fi

$PLAYER stop > /dev/null
$PLAYER clear > /dev/null
#$PLAYER volume $DEFVOL > /dev/null
$PLAYER add $stream > /dev/null
$PLAYER play > /dev/null
exit $ERR_OK
top↑

How to Use

Type piradio help to see all options.

pi@raspberrypi ~ $ piradio
pi@raspberrypi ~ $ piradio list
pi@raspberrypi ~ $ piradio fip
pi@raspberrypi ~ $ piradio 1
pi@raspberrypi ~ $ piradio vol +
pi@raspberrypi ~ $ piradio off
top↑

Version History

2014-12-02: 1.0.0
Switch from xmms to mpd, rename script to piradio, restart from 1.0.0 because GitHub.
2013-03-13: 1.0.2
Removed nyxmms2 because it was only a symlink, pulled volume step size to variable ADJVOL at top, location for radio script now /usr/local/bin instead of ~/bin because logins without a terminal might not get ~/bin added to path, added amixer info, minor cleanup.
2013-03-12: 1.0.1
Added mute toggle, minor script cleanup, removed "vol+" option (use "vol +"), better BBC streams (not part of the script download).
2013-03-11: 1.0.0
Initial release.
top↑

To Do