This is an update to my recent post on this topic.
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 e.g. 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.
The scripts described on this page are available to download from github as part of a larger project which I’ll be blogging on soon.
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.
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 (very often), but their contents does. Lets look at one using the curl command:
$ curl http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_one/supplier/ll_icy2/format/pls.pls NumberOfEntries=1 File1=http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio1_q?s=1414757382&e=1414771782&h=9533b45c836fee7271d17f9a4bdd7eff Title1=No Title Length1=-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:
raspberry-radio/scripts/bbc_radio_update (Source)
#!/bin/bash # This script is based on one found in what is assumed to be the public domain. set -e playlist=/var/local/bbc_radio/urls rm -f $playlist declare -A radios radios["BBC1"]="http://www.radiofeeds.co.uk/bbcradio1.pls" radios["BBC1x"]="http://www.radiofeeds.co.uk/bbc1xtra.pls" radios["BBC2"]="http://www.radiofeeds.co.uk/bbcradio2.pls" radios["BBC3"]="http://www.radiofeeds.co.uk/bbcradio3.pls" radios["BBC4"]="http://www.radiofeeds.co.uk/bbcradio4fm.pls" radios["BBC4x"]="http://www.radiofeeds.co.uk/bbcradio4extra.pls" radios["BBC5l"]="http://www.radiofeeds.co.uk/bbc5live.pls" radios["BBC5lx"]="http://www.radiofeeds.co.uk/bbc5livesportsextra.pls" radios["BBC6"]="http://www.radiofeeds.co.uk/bbc6music.pls" for k in "${!radios[@]}" do pls=${radios[$k]} curl -s $pls | grep File1 | sed "s/File1=/$k, /" >> "$playlist" done
We then need to make the script executable (by all users), create a directory for the output URLs to be placed (that all users can write to) and run the script:
$ sudo chmod 755 /usr/local/bin/bbc_radio_update $ sudo mkdir /var/local/bbc_radio $ sudo chmod 777 /var/local/bbc_radio/ $ bbc_radio_update
It is normally not considered very secure to have a directory such as /var/local/bbc_radio which all users can write to but it is the simplest way of making it so that all users can run the command and it really doesn’t matter for a Raspberry Pi in the home.
To look at the output, just cat the file (note the contents of this file changes: yours 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 ...etc
You can make this script run periodically by linking it to e.g. /etc/cron.hourly with the command sudo ln -s /usr/local/bin/bbc_radio_update /etc/cron.hourly/ but there will still be times when the URLs are out of date. The script to run the radio will take care of this instead.
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 the /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:
raspberry-radio/scripts/radio (Source)
This script needs some explanation. It has got more complicated that the first version I posted a week ago.
The script supports the commands stop, status, stations, reset and any other command is assumed to be the name of a radio station. The first argument to a script is put into the $1 variable automatically, so the case statement on line 10 causes different bits of script to be run depending on what command you type.
Before we get to the main script, line 9 checks to see if the URLs file exists and, if not, runs the bbc_radio_update script to fetch them.
To work out what is going on with the other commands, you can just try typing most of the commands at the command line. For instance, for the status command, try typing mpc when nothing is playing. It just prints:
$ mpc volume: n/a repeat: off random: off single: off consume: off
The additional pipe to grep -vE "^volume: on line 18 means that everything except lines starting “volume:”” is printed: we are not interested in those lines so we filter them out. The sed command replaces any line starting with “http:” with “Unknown station” as sometimes when a radio station is playing it will print the station name and sometimes it doesn’t know it and just prints the stream URL (which is not very useful so we replace it). If you were playing BBC Radio 4 then the mpc and the radio status command would give:
$ mpc BBC Radio 4 [playing] #1/1 0:05/0:00 (0%) volume: n/a repeat: off random: off single: off consume: off $ radio status BBC Radio 4 [playing] #1/1 0:08/0:00 (0%)
The radio reset command clears the mpc queue (so stops it playing) and runs the bbc_radio_update command (this is why all users need to be able to run it). It shouldn’t normally be necessary to do this by hand though as the complicated command for playing a radio station takes care of it most of the time.
So, if you type radio bbc4 then we get to line 35 in the script where there is a grep command. That searches the URLs file (ignoring case) for e.g. “BBC4, ” and sends the output to /dev/null (so we don’t see it). It is actually searching for the script’s argument (e.g. “BBC4”) followed by anything (the “.*”) followed by a comma and space. This means that the script will work if you just type radio 4. 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 (on line 38) we clear the mpc playlist (and suppress the status message with “-q”) then (on line 42) we get the correct URL out of the file and add it to the playlist. To do this we use grep again and pipe the output first into head -1 to get only the first matching line, then into the cut command which splits a line, setting the delimiter to a comma and choosing the second field. We play the station on line 43 (again suppressing output).
That pretty much what I had in the previous version. Sometimes this failed silently if the radio station URLs were out of date. Also, if it did work then it just told you the URL you are playing. If instead you wait a moment and then do mpc then you get the name of the radio station. This is why there is now a sleep 2 statement on line 44. It is followed by mpc | grep "ERROR: problems decoding": if the URL is out of date (or there are other issues) then you get back from mpc the text ‘ERROR: problems decoding “http://bbcmedia.ic.llnwd.net/…etc“’. We use grep to see if we have this error, testing the grep output on line 48. If we have an error then we want to do the radio reset command sequence and try playing the station again. Lines 48-53 achieve this. Finally we do the status command again.
Make it executable and try it out:
$ chmod 755 /usr/local/bin/radio $ radio bbc4 BBC Radio 4 [playing] #1/1 0:01/0:00 (0%) $ radio status BBC Radio 4 [playing] #1/1 0:14/0:00 (0%) $ radio stop
If your URLs file is out of date then you will see something like:
$ radio bbc4 Fetching station URLs... BBC Radio 4 [playing] #1/1 0:01/0:00 (0%)
That’s all for now!
Updates:
Comments
Comments powered by Disqus