BBC Radio on the Raspberry Pi

Posted in Posted on 2014-05-11 17:09

This page shows how to create a simple radio command to play and stop different BBC radio stations on a Raspberry Pi. Once set up, you can just type radio BBC4 to get your favourite station playing. This is useful for various reasons, for instance if you have a room with just an amplifier and speakers in then, with a Raspberry Pi, you can listen to the radio (and with other software your music collection). You can also listen to BBC 6 Music which you cannot get on FM.

Attention!

2014-05-18: There is now a second, updated post on getting BBC radio on a Raspberry Pi.

Getting BBC radio streaming from a Raspberry Pi is something I’ve been wanting to do since I started playing around with them. I’ve seen various impressive solutions involving re-purposing old portable radios but I never got the hang of what needed doing in software.

This tutorial is based on a Raspberry Pi with the latest version of Raspbian installed (2014-01-07), updated using rpi-update. The OS also has some other packages installed to enable it to be a UPnP renderer. This is all documented in a previous post.

Regularly updating the stream addresses

Part of the complication with BBC radio stations is that the URLs required to stream from change periodically. First of all therefore we need a script to find the URLs and cache them. The “playlist” URLs do not change, but their contents does. Lets look at one using the “curl” command:

$ curl http://www.bbc.co.uk/radio/listen/live/r1_aaclca.pls
NumberOfEntries=2

File1=http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_lc_radio1_p?s=1399793891&e=1399808291&h=6c19055ef19b6b3acafc59f381af6fc6
Title1=No Title
Length1=-1

File2=http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_lc_radio1_q?s=1399793891&e=1399808291&h=5ada50d070397aa72d01532281aad710
Title2=No Title
Length2=-1

The actual URL for streaming is the one following File1=. What we need to do is download all the playlists we want and extract each of these URLs. To do this, create a script called bbc_radio_update, e.g. using sudo vi /usr/local/bin/bbc_radio_update:

#!/bin/bash
set -e
URLS=/var/local/bbc_radio/urls
rm -f $URLS

declare -A radios
radios["BBC1"]="http://www.bbc.co.uk/radio/listen/live/r1_aaclca.pls"
radios["BBC1x"]="http://www.bbc.co.uk/radio/listen/live/r1x_aaclca.pls"
radios["BBC2"]="http://www.bbc.co.uk/radio/listen/live/r2_aaclca.pls"
radios["BBC3"]="http://www.bbc.co.uk/radio/listen/live/r3_aaclca.pls"
radios["BBC4"]="http://www.bbc.co.uk/radio/listen/live/r4_aaclca.pls"
radios["BBC4x"]="http://www.bbc.co.uk/radio/listen/live/r4x_aaclca.pls"
radios["BBC5l"]="http://www.bbc.co.uk/radio/listen/live/r5l_aaclca.pls"
radios["BBC5lsx"]="http://www.bbc.co.uk/radio/listen/live/r5lsp_aaclca.pls"
radios["BBC6"]="http://www.bbc.co.uk/radio/listen/live/r6_aaclca.pls"
radios["BBCan"]="http://www.bbc.co.uk/radio/listen/live/ran_aaclca.pls"

for k in "${!radios[@]}"
do
    pls=${radios[$k]}
    curl -s $pls | grep File1 | sed "s/File1=/$k, /" >> "$URLS"
done

We then need to make the script executable (by root), create a directory for the output URLs to be placed and run the script:

$ sudo chmod 744 /usr/local/bin/bbc_radio_update
$ sudo mkdir /var/local/bbc_radio
$ sudo bbc_radio_update

To look at the output, just cat the file (note the contents of this file changes: your will not be the same):

$ cat /var/local/bbc_radio/urls
BBC4, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio4_p?s=1399723465&e=1399737865&h=2cebe3f0ad99df0e6f0f4e56ca4d7736
BBC6, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_6music_p?s=1399723579&e=1399737979&h=b85295564b4afb786f533d75023ba57c
BBC1, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio1_p?s=1399723596&e=1399737996&h=7a36c56eac5cc55114da6d8f5dfa8558
BBC3, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio3_p?s=1399723367&e=1399737767&h=5857c11d8507a3bef9ed74ae6d59921a
BBC2, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio2_p?s=1399723512&e=1399737912&h=dad579513911b0b087cb474b7a448c6f
BBC4x, http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio4extra_p?s=1399723639&e=1399738039&h=60b10f86626cb7150269aa08e2b27910

To make this script run every day (at 6.25am by default), put a symbolic link to it from the cron.daily folder:

$ sudo ln -s /usr/local/bin/bbc_radio_update /etc/cron.daily/

Playing the streams

Now we have the necessary URLs we need to play them. Although I use gstreamer with gmediarender as a UPnP renderer I cannot get it to play the BBC stations so instead we use mpd and control it with mpc. Firstly we need to install them (and ignore the errors):

$ sudo apt-get install mpc mpd
...etc...
Setting up mpc (0.22-1) ...
Setting up mpd (0.16.7-2) ...
insserv: warning: script 'mathkernel' missing LSB tags and overrides
[....] Starting Music Player Daemon: mpdlisten: bind to '[::1]:6600' failed: Failed to create socket: Address family not supported by protocol (continuing anyway, because binding to '127.0.0.1:6600' succeeded)
Failed to load database: Failed to open database file "/var/lib/mpd/tag_cache": No such file or directory
. ok

At this point if we try to use mpc, mpd can’t access the ALSA output. Looking in /var/log/mpd/mpd.log we see:

output: Failed to open "My ALSA Device" [alsa]: Failed to open ALSA
device "hw:0,0": Device or resource busy

Edit /etc/mpd.conf and comment out some lines:

audio_output {
    type "alsa"
    name "My ALSA Device"
# device "hw:0,0" # optional
# format "44100:16:2" # optional
# mixer_device "default" # optional
# mixer_control "PCM" # optional
# mixer_index "0" # optional
}

The key change may be the mixer_device line (not sure). Then restart the mpd service:

$ sudo /etc/init.d/mpd restart

Finally, we need a helpful script to make controlling mpd easy. Save this script as /usr/local/bin/radio:

#!/bin/sh

URLS=/var/local/bbc_radio/urls

case "$1" in
"stop")
    mpc stop
;;
"status")
    mpc status
;;
"stations")
    cat $URLS | cut -d',' -f1 | sort
;;
*)
    grep -i "$1, " $URLS > /dev/null
    if [ $? -eq 0 ]; then
        mpc -q clear
        mpc -q add `grep -i "$1, " $URLS | cut -d',' -f2`
        mpc play
    else
        echo "No such station"
    fi
;;
esac

In the script, “$1” is the first argument given to the radio command. So, for instance, with radio BBC4 $1 will be “BBC4”. The case statement deals with stop, status and stations and then for anything else we get to the “grep” in line 16. That searches the URLs file for e.g. “BBC4, ” and sends the output to /dev/null (to get rid of it). The next line asks if “$?” is equal to zero: “$?” is the return code of the last command (the grep) and if it is zero then it means that grep found something and so the station exists in the URLs file. In this case we clear the mpc playlist (and suppress the status message with “-q”), add the radio station’s URL to the queue and play it. To get the correct URL out of the file (for the mpc add command) we use grep again and pipe the output into the cut command which splits a line, setting the delimiter to a comma and choosing the second field.

Make it executable and try it out:

$ chmod 755 /usr/local/bin/radio
$ radio BBC4

http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio4_p?s=1399790284&e=1399804684&h=32d5597bc6388bb9da0414c501c900ab

[playing] #1/1 0:00/0:00 (0%)
volume: n/a repeat: off random: off single: off consume: off
$ radio status
BBC Radio 4
[playing] #1/1 41:02/0:00 (0%)
volume: n/a repeat: off random: off single: off consume: off
$ radio BBC1

http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio1_p?s=1399790041&e=1399804441&h=6895cc667ccad6176fcfd7618960c7b8
[playing] #1/1 0:00/0:00 (0%)
volume: n/a repeat: off random: off single: off consume: off
$ radio stop

Options are “status”, “stop”, “stations” and the station names as found in the URL file (“BBC1”, “BBC2”, “BBC3”, “BBC4”, “BBC4x”, “BBC5l”, “BBC5lsx”, “BBC6”, “BBCan”). Obviously, the output could be tidied up but it’s good enough for now. If you use this on the same Raspberry Pi as you use for playing music via UPnP then you will find that the sound from both systems is mixed and comes out at the same time.

There’s lots of scope for using this command in other projects to enable easier control of the radio: watch this space!

Updates:

  • 2014-05-13: changed “grep” to “grep -i”
  • 2014-05-13: bugfix and “stations” option, thanks to Greg Fenton
  • 2014-05-14: added more BBC stations, thanks to Brian J Cook
  • 2015-05-18: added link to updated post

Comments

Comments powered by Disqus