Hungry Children: update

Please sir can I have some more time?

Well, since I posted my open letter to the school about children going hungry at lunchtime, there have been over 4000 page views and no response from the school as yet (apart from an acknowledgement). I have done a fair bit of reading around the subject though – both comments here and on Facebook and other articles on the web.

Let me be clear, I am not out to bash Bitterne Park school. I think they do a good job but I think they have some problems because of the school’s buildings not being improved whilst the number of students increases. Whatever the reasons though (and I await their response), I don’t find it acceptable that children ever go hungry and I want something to change. There are some indications that the situation at Bitterne Park has got worse since the introduction of fingerprints for food (a.k.a cashless catering). That would be ironic as it was claimed it would speed service up. I argued that it could not speed it up as the slowest point in the queue was getting served. I didn’t expect it to slow it down though: has it?

What is more concerning though is that this doesn’t seem to be an isolated issue. Back in 2007 The Guardian wrote about school lunchtimes being cut. They attributed this to teachers contracts being changed so that only the senior management team are permitted to supervise lunchtimes. That means that a school must employ more lunchtime supervisors to manage the free-for-all, or alternatively cut down the time so that there is less chance of any unwanted incidents. Is that the right choice for the children’s health and well-being though? Various comments say that similar things happen at other schools in the city: if so, how have we let this happen so widely?

There are some great resources online around school lunches and making the food and the environment healthy for our children:

Fundamentally, an adult would not put up with it. Why should our children?

Children going hungry at Bitterne Park Secondary School

Please sir can I have some more time?
What follows is the text of a a letter sent to Bitterne Park Secondary School, Southampton on 29th September 2014.

Dear Mrs Trigger,

I am writing to you because one of my children was not able to eat any lunch last Thursday: a situation seemingly caused by inadequate facilities at the school. This is completely unacceptable. In discussing the situation with my three children I have found out about other aspects of the catering arrangements which also concern me. I am publishing this letter on my blog (http://blog.scphillips.com) in order that other parents may contribute their experience and so I am using the letters “T”, “F” and “R” to refer to my children in order to preserve some anonymity.

The context:

  • the lunch break is 35 minutes long, from 12:20 to 12:55
  • it is followed by a registration period of 5 minutes
  • there are 1500+ children at the school, plus numerous members of staff
  • there are three places to buy food: the main canteen, the “Taste Station” and “Pasta King”
  • there are two points to pay in the canteen and one each at the other two outlets

Basically, from what I understand, the queue to be served lunch in the canteen is so long that it takes most of the lunch break to queue and be served. Not wanting to spend the whole 35 minutes queueing, F prefers to socialise for most of the lunch break and queue up near the end of the period. Generally he eats his food on the way to and during the 5 minutes registration period outside of the classroom (with others) as his tutor does not mind. On Thursday last week the queue at the end of lunch was still too long and F did not get served and hence went hungry.

Another of my children, T, tells me that when she has school lunches she queues from the start of the period and very often has to throw food away uneaten as there is not enough time to eat it. When the bell goes, she eats some more of her food on the way to registration and then puts the rest in a bin before she gets there (along with the disposable container and cutlery that all the children use every day) as food is not permitted in classrooms.

My other child, R, only tried school lunches once. She spent almost all of the lunch break queueing, bought a curry, ate a few mouthfuls and then the bell went so she had to leave the rest. This was a while ago. She now knows that her tutor lets children eat their lunch in the classroom during registration time as her tutor thinks it is not right that they do not have enough time.

It just is not acceptable that children are regularly not able to get an adequate lunch. In my opinion, lunchtime should be an opportunity for social interaction as well as food, but even the basic necessity of being able to eat food is lacking. It seems clear that there is a serious problem at your school. I guess it has been caused by the catering facilities not keeping up with the expansion in school numbers and, increasingly, children not being allowed off-site in the lunch break. My main question is:

  • Do you agree there is a problem?
  • If so, what strategy is in place to change things so that children don’t go hungry and don’t have to throw away food due to lack of time?

In addition,

  • How long do you think someone should have to eat their lunch? (My children thought 20 minutes would be good)
  • How many people do you expect to serve during the period?
  • Why was the additional food outlet known as the “Snack Shack” opened just for the two days of the last OFSTED inspection?

Last term I corresponded with members of staff about the biometric system you introduced. One of the main reasons for installing it given in both the school’s information and by the vendor of the system was that it would speed up lunchtime queues. At the time I suggested that it most likely would not (as the evidence from my children suggested that actually getting served was the bottleneck) and enquired as to why the lunch break was so short. I ask again: why is the lunch break only 35 minutes? I do understand that extending the lunch break time would also mean extending the length of the school day. I can also see that this would cut into extra-curricular activity time after school, but, as I said last term, surely actually getting children fed is the most important thing and the school still seems to be failing in this regard.

I am aware that I am perhaps overloading this letter with questions but I am also concerned that there are vending machines in the school containing crisps, chocolate and fizzy drinks. Similar machines were removed when the government’s “Healthy School” scheme was running from September 2006 but returned sometime after April 2011 when the scheme closed. Why are these vending machines there? Surely the school should strive to be healthy regardless of government schemes?

I would appreciate it if you could carefully address each of my questions (highlighted).

Yours sincerely,
Dr S Phillips.


Since then I have written another short post about the topic more generally.

Fingerprints for Food

What follows is the text of a letter sent to Bitterne Park Secondary School, Southampton on 24th June 2014.

Dear Mrs Trigger,

Re: cashless catering

I approve of the cashless catering idea in principle: it removes any difference between those who have free school meals and those that don’t. It stops anyone stealing someone’s money or losing their own. I should also note that I am not irrationally worried about the technology: I work in IT research and fully understand how these systems work.

Basically my issue with the system is that it just is not necessary to use a fingerprint: a swipe card or PIN can be used with the same point of sale system and would be more appropriate. My main concern is that is normalises giving away personal data at a point in history when people in general are struggling to appreciate its value. We try to teach our children not to post things they would regret on Facebook and yet the school is telling them that handing over their fingerprints just to pay for food is just fine.

By law the children have to be educated about the system and be told about their right to refuse and what the alternative is. To my understanding this has not yet been done. Instead I have one of my children being told by their tutor that they need to bring the form back or they will not be able to get any food in September. And what about that form? There is no explanation as to what the alternative is, no option on the form to say you do not want to permit your child to take part and we were given just 4 days to return it.

From talking to parents of children due to join the school in the 2014 academic year, I understand that they have been asked up-front to give their consent for the fingerprint system. Again though, if this is the same information that we, as current parents, were sent then it does not describe the alternative or give an easy way to refuse. Will the new intake (every year) receive education on the reasons for requiring the data, their right to refuse and on personal data safety in general?

The alternative, I have now been told, would be to use a PIN: the student would type in their PIN and their photo would appear on the cashier’s screen as a check. I do wonder why the alternative cannot be using cash as they do now: it works, has no privacy implications and we all have it.

European and UK data protection law has a principle called “proportionality”: basically, if you want to request and store personal data then there has to be a good enough reason for it. I am not saying the use of this system is illegal – I am not a lawyer, and the system only records a few pieces of data about the fingerprint rather than a scan of the fingerprint itself – but it comes back to the psychological issue: the children do not understand that it is not the actual fingerprint and many will happily hand over the fingerprint for food happy in the knowledge that the school has asked them to and that therefore it is okay.

I am left wondering what problem this system has been brought in to solve. The salesman at the information evening repeatedly pointed out how fast it was compared to people fumbling for change and this was repeated in the letter about the system we received. The school seem to recognise that there is (unsurprisingly) a problem in getting 1600 people fed in 45 minutes [edit: apparently it is actually 35 minutes], however, my children tell me that it is not the paying for the food that holds the queues up but the getting served. In other words, even if the food was free it wouldn’t be any faster. I have received no good explanation as to why the lunch hour cannot be just that: 1 hour long.

So, we have a system, now ordered, to be used from September which seems unlikely to solve the problem of lunchtime queues and sends an inappropriate educational message to our children. We, as parents, are given no option to refuse on the form, the school has not yet discussed alternatives with the children (as they must do by law) or with the parents in general.

Mr (REDACTED) asked me if I had any input for the assembly round this week. I would suggest:

  • You must follow the law:
    • describe what the alternative is
    • let them know they have the right to refuse at any time, even once signed up to the system
  • You must not pressurise them into using the system:
    • My youngest daughter has been told by her tutor that she must bring the form back in or she will not get any food – this is unacceptable
  • I think you should explain why you want to install the system: I would also like to know. As described above, I don’t believe it will speed up the whole serving process.
  • You should point out that the system is not taking a police-style record of their fingerprint and that for this reason it is okay to do this.
  • I would take the opportunity to point out to the students that although the school is asking for this data, in general they should be very careful in giving away personal data such as this (or phone numbers, email addresses, date of birth, etc.).
    • It’s a bit tricky, as I think the fact the school is asking for this data unnecessarily is a bad educational message so you’ll have to do the best you can to turn this around.

Yours sincerely,
Dr S Phillips.


The response from the school did not address most of my points. I was informed that there was an “alternative pin system” (which I actually mention in my letter) and that they would support parents who felt unhappy about the fingerprint system (and presumably children who do not want it either?). I was told that they would like parents to support what they were trying to do “in terms of speeding up the lunchtime service” and to “reduce the amount of cash that students have to have within school”. My letter clearly explains in the very first sentence that I am in favour of cashless catering (I am in favour of cashless anything to be honest) and also that I dispute their claim that it will speed up the lunchtime service.

I was told that “Extending the lunch hour is not an option” as adding more time to the lunch break would mean a reduction in after-school club time. I would argue that giving children enough time to eat was more important than after-school clubs.

I was told that the system “is common to most of others schools in Southampton and across the UK” but I just don’t see the relevance of that. Cashless catering: fine. Fingerprints: not so good. You can have both cashless catering and no fingerprints so why not do that?

Finally, I am told that the system “will allow us to have greater benefits for the catering dept. and ultimately our students”. I can see that an electronic point of sale (EPoS) system is useful to the school as it can record what has been sold (and when) but again, this is unrelated to the fingerprint issue and I am frankly surprised that they didn’t already have such a system.

My children reported to me that the assemblies following this exchange did not explain about the alternatives or go into any of my suggested points.

I have to admit, at this point I gave up on this particular argument as the school just did not seem to be addressing the issues and (as ever) there were plenty of other things to do. It would be interesting to know what information was provided to the 2014 intake though. Can anyone tell me?

BBC Radio on the Raspberry Pi (v2)

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.

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 (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”:

#!/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://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_one/format/pls.pls"
radios["BBC1x"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_1xtra/format/pls.pls"
radios["BBC2"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_two/format/pls.pls"
radios["BBC3"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_three/format/pls.pls"
radios["BBC4"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_fourfm/format/pls.pls"
radios["BBC4x"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_four_extra/format/pls.pls"
radios["BBC5l"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_five_live/format/pls.pls"
radios["BBC5lx"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_radio_five_live_sports_extra/format/pls.pls"
radios["BBC6"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_6music/format/pls.pls"
radios["BBCan"]="http://open.live.bbc.co.uk/mediaselector/5/select/mediaset/http-icy-aac-lc-a/vpid/bbc_asian_network/supplier/ll_icy2/format/pls.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.

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 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

Making it Easy With a “radio” Command

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

#!/bin/sh
 
# This code is copyright Stephen C Phillips (http://scphillips.com).
# It is licensed using GPL v3.
 
URLS=/var/local/bbc_radio/urls

# get the radio URLs if they are not there
[ ! -f $URLS ] && bbc_radio_update

case "$1" in
    "stop")
        mpc -q clear
    ;;
    "status")
        # Run the "mpc" command, remove any line starting "volume"
        # and replace any line starting with "http" with "Unknown station"
        mpc | grep -vE "^volume:" | sed "s/^http:.*/Unknown station/"
    ;;
    "stations")
        # Take the URLS file, split each line at the comma
        # and just print the first field, then sort them
        cat $URLS | cut -d',' -f1 | sort
    ;;
    "reset")
        # Stop whaever is playing and then update the URL list
        echo "Fetching station URLs..."
        mpc -q clear
        bbc_radio_update
    ;;
    *)
        # Search the URLS file for this script's argument ($1) followed
        # by anything and then a comma. Redirect it to /dev/null so the result
        # isn't shown in the console.
        grep -i "$1.*, " $URLS > /dev/null
        # Check if we found a URL in the URLs file matching the argument.
        if [ $? -eq 0 ]; then
            mpc -q clear
            # Again, search for the argument, take just the first line that matches
            # (using "head"), split the line at the comma and take the second field.
            # Add this to the playlist with "mpc add".
            mpc -q add `grep -i "$1.*, " $URLS | head -1 | cut -d',' -f2`
            mpc -q play
            sleep 2
            # Check if we just found an error (often caused by URLs being out of date).
            mpc | grep "ERROR: problems decoding" > /dev/null
            if [ $? -eq 0 ]; then
                # If mpc reported an error then fetch the URLS and try again.
                echo "Fetching station URLs..."
                mpc -q clear
                bbc_radio_update
                mpc -q add `grep -i "$1.*, " $URLS | head -1 | cut -d',' -f2`
                mpc -q play
            fi
            # Get the status, remove the volume line, replace any URL with
            # "unknown station" and this time let it appear on the console.
            mpc | grep -vE "^volume:" | sed "s/^http:.*/Unknown station/"
        else
            echo "No such station"
        fi
    ;;
esac

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
pi@raspberrypi ~ $ 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 47. 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:

  • 2014-05-19: made some improvements to the radio script
  • 2014-05-21: radio script bug fix
  • 2014-05-24: made radio script automatically fetch URLs the first time and added in “Unknown station” feature
  • 2014-06-29: added lots of comment to radio script, made the grep better, added links to github
  • 2014-10-31: updated the BBC playlist URLs (thanks to Daniel J Wilcox)

BBC Radio on the Raspberry Pi

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

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.

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 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”:

#!/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:

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

Playing music on a Raspberry Pi using UPnP and DLNA (v3)

What we are aiming for

A music system with a Raspberry Pi plugged in to an amplifier playing music that you choose with your mobile phone. The music can come from MP3s on your phone, from files on your server, files “in the cloud” or from internet radio stations. If there’s more than one Android phone in your household you can have them all synchronised, showing the same playlist and controlling the same music. If you have multiple Raspberry Pis you can put one in each room and choose which one to play the music with. This is all achieved with free software and open standards. I’ve just written some instructions to show how to do it.

I have blogged on this topic two times previously (here and here). Each time it gets simpler as the Raspberry Pi eco-system evolves. I needed a new Raspberry Pi UPnP renderer to be attached to an amplifier and speakers.

My previous post explains lots more about how the system as a whole works, how to test it and how you control the music. This post merely updates the instructions for installing gmediarender and includes some info on using a USB sound card.

Setting up a Raspberry Pi to be a UPnP Media Renderer

Installing the Base Operating System

As usual I started from the latest Raspbian distribution (2014-01-07) which needs a 4GB SDCard card apparently. Once the Raspberry Pi is up and running and on the network, log in (user: “pi”, password “raspberry”), run the first-time configuration command and then update to the very latest firmware. These following commands also show the before and after versions in case that is useful for people:

$ uname -a
Linux raspberrypi 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l GNU/Linux
$ sudo raspi-config
$ sudo apt-get install rpi-update
$ sudo shutdown -r now

Once it has rebooted, log in again check the new status and upgrade all the installed packages:

$ uname -a
Linux raspberrypi 3.12.19+ #681 PREEMPT Fri May 9 16:36:10 BST 2014 armv6l GNU/Linux
$ /opt/vc/bin/vcgencmd version
May  9 2014 16:52:52
Copyright (c) 2012 Broadcom
version c8ed097f7c23249e702bea3ed6b5720136ba00e4 (tainted) (release)
$ sudo apt-get update
$ sudo apt-get upgrade

Installing gstreamer 1.0

Henner Zeller has made the gmrender-resurrect UPnP renderer and it is known to work best with gstreamer 1.0. Unfortunately Raspbian currently still comes with gstreamer 0.10. Fortunately, Christi Scarborough has compiled the necessary gstreamer 1.0 packages for the Raspberry Pi and provided them as debian packages. She has documented it all and very honestly included the warning that using these packages means you have to trust her not to have slipped in some malware or something. Some of the instructions on this page are just a duplication of hers. Christi also provides a ready-made build of gmediarender but as I wasn’t sure which version that was, I wanted to use Henner’s directly.

First we have to install Christi’s GPG key to show that we trust her packages:

$ sudo wget -O - http://www.chiark.greenend.org.uk/~christi/debian/christi@coraline.org.gpg.key | sudo apt-key add -

Then, using “vi”, “nano” or whatever, create a new file to hold the address of Christi’s Debian repository, call it /etc/apt/sources.list.d/upnprender.list and add just one line “deb http://www.chiark.greenend.org.uk/~christi/debian/ wheezy main”.

We then need to update the local cache of available packages to include Christi’s packages and then follow Henner’s instructions for installing gmrender-resurrect:

$ sudo apt-get update
$ sudo apt-get install libupnp-dev libgstreamer1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-alsa

Installing gmediarender

Continuing with Henner’s instructions:

$ cd
$ git clone https://github.com/hzeller/gmrender-resurrect.git
$ cd gmrender-resurrect
$ sudo apt-get install autoconf
$ ./autogen.sh
$ ./configure
$ sudo make install

This puts gmediarender into /usr/local/bin and a couple of icons into /usr/local/share/gmediarender

Henner has provided an init script to start and stop the gmediarender software, so we’ll copy this into the appropriate place:

$ sudo cp scripts/init.d/gmediarenderer /etc/init.d

Edit the init script if you need to (e.g. set the name of the renderer). Then use the “update-rc.d” command to put in the necessary symbolic links to the init script that start or stop the service at different runlevels (the following “ls” command shows these for interest):

$ sudo update-rc.d gmediarenderer defaults
$ ls -l /etc/rc*.d/*gmed*
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc0.d/K01gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc1.d/K01gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc2.d/S04gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc3.d/S04gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc4.d/S04gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc5.d/S04gmediarenderer -> ../init.d/gmediarenderer
lrwxrwxrwx 1 root root 24 May 10 11:03 /etc/rc6.d/K01gmediarenderer -> ../init.d/gmediarenderer

Rebooting now should give us a system with gmediarender running, which we can test with “ps”:

$ sudo shutdown -r now
(wait a bit and log in again)
$ ps aux|grep gmed
pi        2078 15.5  9.1 198996 40828 ?        Ssl  11:05   0:05 /usr/local/bin/gmediarender -f Garden -d -u bd1dcf3e746aa69812943cb1d00f7ebc --gstout-audiosink=alsasink --gstout-audiodevice=sysdefault --gstout-initial-volume-db=-10
pi        2123  0.0  0.1   3548   800 pts/0    S+   11:06   0:00 grep --color=auto gmed

Using a USB Audio Card

Basically it all works at this point, though using the built-in audio output of the Raspberry Pi never gives a great quality sound. There are various really interesting high quality DAC cards now available for the RPi which connect directly to the circuit board but for now I went for the simple option of getting a dirt-cheap USB audio card (for 99p you can’t really go wrong…). It does sound much better than the built-in output and is automatically picked up by the latest Raspbian version.

Plug in your USB audio card (which can cause the RPi to reboot…) and then
set it up by following an Adafruit tutorial.

I have a CM109 chipset so all I had to do was edit /etc/modprobe.d/alsa-base.conf and change “options snd-usb-audio index=-2″ to “options snd-usb-audio index=0″.

Reboot again and decent sound comes out of the USB sound card!

Morse Code Transcriber

I have been working for a while on a tool to “listen to” and transcribe Morse code. I’ve been wanting to do it for ages and considered a variety of ways, but with more browsers supporting the Web Audio API the time seemed right to give it a go.

Ultimately, the tool will be integrated into my Morse code trainer to listen to students practising the segments of Morse code in that tool and let them know if they are doing it well enough. For now though, the Morse code transcriber is just an alpha-release stand-alone tool which only works properly in Chrome (I should be able to make it work in Firefox as well).

I recently came across a website that is transmitting Morse code as part of some marketing campaign I guess. I think the transcriber would be very useful to people who want to know what it is saying. It actually seems to work quite well! You need to use the transcriber with the target frequency set to 1000 Hz and the volume on your computer right up. To get it to work reliably you really have to fiddle with the settings. I’ll sort out an auto-calibrating version as soon as I can.

I’ll post some technical details of how it all works later, but I just wanted to let people have a go with it for now.

Here’s a screenshot of it transcribing the sound from the site I mentioned above:

transcriber

Getting a Python script to run in the background (as a service) on boot

For some of my projects I write a simple service in Python and need it to start running in the background when the Raspberry Pi boots. Different Linux distributions use different ways of starting and stopping services (some now use Upstart, some systemd). I am using the “Wheezy” Debian distribution on my Raspberry Pi, and in this case the proper way to do this is using an “init script”. These are stored in the /etc/init.d folder. In there you can find scripts that for instance, start the networking system or a print server. Debian Wheezy uses the old Sys V init system which means that these scripts are run according to symbolic links in the /etc/rc.x directories. The Debian documentation explains this.

Anyway, the following init script makes getting a Python script (or e.g. a Perl script) to run when the Raspberry Pi boots fairly painless. Services are supposed to run as “daemons” which is quite complicated in Python and involves forking the process twice and other nasty bits. Instead we can make use of the handy start-stop-daemon command to run our script in the background and basically deals with everything we need.

Changing the init script

Lines 14 and 15 define where to find the Python script. In this case I have said that there is a folder /usr/local/bin/myservice and that the script is called myservice.py inside there. This is so that any additional Python files or other bits that your Python script needs can also be tidily put into that one place (not really how you're supposed to do it, but is easy).

Line 16 defines what we call the service. You should call this script by the same name.

Line 23 sets what user to run the script as. Using root is generally not a good idea but might be necessary if you need to access the GPIO pins (which I do). You might want to change this to the "pi" user for instance.

Line 28 loads a some useful functions from a standard file. We later use the logging functions for instance. We then define functions do_start and do_stop that will be used to start and stop the script.

start-stop-daemon needs to be able to identify the process belonging to a service so that (1) it can see it is there and does not start it again, and (2) it can find it and kill it when requested. In the case of a Python script then process name is "python" so this is not a very useful identifier as there may well be other Python processes running and things would get confusing. Instead we get start-stop-daemon to store the PID (the or process ID) using the --pidfile $PIDFILE --make-pidfile arguments. When told to start the process it looks for the file $PIDFILE which is defined in line 26 to be /var/run/myservice.pid (which on a Raspberry Pi is actually found at /run/myservice.pid thanks to a symbolic link.

Other than that, we use the --background flag of start-stop-daemon to run our script in the background, "--chuid" to set the user that the script runs as (with "--user" to look for scripts run by that user when we are trying to determine if it is already running) and "--startas" to define what we want to run. The options to start-stop-daemon end with the double-hyphen and then we add on $DAEMON_OPTS in case there are any parameters to pass to the daemon itself.

When stopping the daemon the --retry 10 means that first of all a TERM signal is sent to the process and then 10 seconds later it will check if the process is still there and if it is send a KILL signal (which definitely does the job).

Using the init script

To actually use this script, put your Python script where you want and make sure it is executable (e.g. chmod 755 myservice.py) and also starts with the line that tells the computer to use the Python interpreter (e.g. #!/usr/bin/env python). Edit the init script accordingly. Copy the init script into /etc/init.d using e.g. sudo cp myservice.sh /etc/init.d. Make sure the script is executable (chmod again) and make sure that it has UNIX line-endings. At this point you should be able to start your Python script using the command sudo /etc/init.d/myservice.sh start, check its status with the /etc/init.d/myservice.sh status argument and stop it with sudo /etc/init.d/myservice.sh stop.

To make the Raspberry Pi use your init script at the right time, one more step is required: running the command sudo update-rc.d myservice.sh defaults. This command adds in symbolic links to the /etc/rc.x directories so that the init script is run at the default times. you can see these links if you do ls -l /etc/rc?.d/*myservice.sh

An example service

If you run a Python script in this way then you don't get to see any output on the terminal so you need to do proper logging (rather than just print statements). The example Python service here shows how to parse command-line arguments and do simple logging to a file.

By default it logs to a file in /tmp and at midnight will save the day's log file and start a new one, keeping 3 at most. To change where it logs to you need to use the "--log" or "-l" command line argument, so when running this from the init script you need to set the "$DAEMON_OPTS" variable. For instance, if you run the service as root then you could set $DAEMON_OPTS="/var/log/myservice.log" (the normal user cannot write files in there).

The example service above is heavily commented to explain what is going on, but one bit which is a little unusual is line 36-51 which I added to help people debug their services. Those lines set up a class called MyLogger which is initialised with the standard logger object just constructed along with a log level. The class only defines a write method which is all that is needed to emulate a normal stream of the standard output (or "stdout") or standard error (or "stderr") type. Normally when you do e.g. print "hello" in Python it actually does sys.stdout.write("hello") but line 49 changes this so that the stdout stream is replaced by an instance of MyLogger logging at the INFO level. Therefore, later in the example when the statement print "This is a print" is executed, that string actually goes into the log file. In the same way the standard error stream is replaced which means that when the program crashes because of the deliberate division by zero, the error and the traceback all appear in the log file at the ERROR level.

Please note that for both of these scripts to work you must make sure that the files have UNIX line-endings (just a LF) not DOS line-endings (CRLF). If you copy and paste from the web page into a Windows text editor and then transfer to a Linux machine (such as a Raspberry Pi) then they may end up with DOS line endings and will not work. If the shell script has DOS line-endings then if you run it using ./myservice.sh you will see -bash: ./myservice.sh: /bin/sh^M: bad interpreter: No such file or directory. If the Python script has DOS line-endings and you run it using ./myservice.py you will see : No such file or directory. You can fix this problem using the dos2unix command: just do e.g. dos2unix myservice.py (and sudo apt-get install dos2unix if you don't have the command). To avoid the problem in the first place you could copy the "raw" link from above and do e.g. wget https://gist.github.com/scp93ch/cdb15468b84a8b3eb0aa/raw/myservice.py on the Raspberry Pi to download it directly.

Updates

  • 2013-09-30: corrected mistake in use of --make-pidfile (thanks to Max Sistemich).
  • 2014-06-29: added DAEMON_OPTS, more explanations and an example service with logging and arguments.
  • 2014-07-07: added redirection of stdout and stderr.
  • 2014-08-01: added instructions on sorting out the line-endings.

Playing music on a Raspberry Pi using UPnP and DLNA (revisited)

Edit, 2014-05-11: Please note there are (yet again) updated instructions for installing gmediarender. The rest of this tutorial is still valid though.

What we are aiming for

A music system with a Raspberry Pi plugged in to an amplifier playing music that you choose with your mobile phone. The music can come from MP3s on your phone, from files on your server or from internet radio stations. If there’s more than one Android phone in your household you can have them all synchronised, showing the same playlist and controlling the same music. If you have multiple Raspberry Pis you can put one in each room and choose which one to play the music with. This is all achieved with free software and open standards. I’ve just written some instructions to show how to do it.

With any luck your initial outlay will only be about £45. The end result will be similar to the systems from Sonos and Squeezebox costing loadsamoney. Further additional devices to play music through another Hi-Fi or TV would also be £45.

My earlier post about getting Raspberry Pis to play music using your phone or phones as the controller has been very popular. Since then though the software has developed with new releases of the Debian distribution, gmrender-resurrect and the Raspberry Pi firmware. Taking all these new releases the process is now very much simpler and the sound does not have annoying pops.

What you need

  • A Raspberry Pi
    • I got mine with a case from ModMyPi for £35
  • A wireless USB dongle (or wired ethernet connection near your Hi-Fi)
  • A micro-USB power supply (most phones use these so you might have one already)
  • An SD Card (2GB minimum) – perhaps an old one from a camera?
  • An SD Card reader/writer – often built in to a computer
  • Your music available on a linux server (e.g. CDs ripped to MP3 files) – this could be replaced with e.g. a NAS device or a Windows machine or just MP3s on your phone
  • An amplifier with a 3.5mm auxiliary input and speakers (perhaps a TV sound bar?)
  • An audio cable to connect the Pi to the amplifier
  • At least one Android device
  • Some sort of router / wireless network to connect the media server to the Raspberry Pi
  • You might need a USB keyboard and a TV/monitor to do the initial set-up (hopefully you have these lying around)

Setting up a Raspberry Pi to be a UPnP Media Renderer

The one essential thing is to get gmrender-resurrect (also known as GMediaRenderer, gmrenderer, gmrender, …) installed and working. Once that is done you will be able to play MP3s from your phone through the Raspberry Pi. GMediaRenderer is what is known as a UPnP Media Renderer: that is a destination for media files using the UPnP protocol. There is a lot of software that supports UPnP and many modern “Smart TVs” can also play your music in this way. This is also related to DLNA but I have to confess I don’t understand the interplay between these standards.

Installing the Operating System

I started from fresh, downloading the latest “Wheezy” Debian Linux distribution from the Raspberry Pi downloads page. At the time of writing this was 2013-05-25-wheezy-raspbian.zip.torrent. Following instructions on the Raspberry Pi site, I copied it onto an SD Card and turned the RPi on.

Get the Raspebrry Pi on the network

This is one of the more involved parts, which I wrote about last time. It depends on your network basically so have a look at my instructions and use Google to find some more.

First steps and updates

We now have to get everything updated to the latest versions. Note, that these instructions will get the latest software and latest firmware so you might end up with something more recent than me and therefore slightly different behaviour. To see what operating system you have:

$ uname -a
Linux raspberry2 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l GNU/Linux

Do the initial configuration:

$ sudo raspi-config

You need to enable ssh access, set your password, set the hostname and reboot.

When I looked at this last time, even with my final solution of using Pulse audio there were annoying pops when music started and stopped. This issue was investigated by the Raspberry Pi developers and has now been fixed in the latest firmware.

To update the firmware to the latest drivers etc, we can use the rpi-update tool:

$ sudo apt-get install rpi-update
$ sudo rpi-update
 *** Running ldconfig
 *** Storing current firmware revision
 *** Syncing changes to disk
 *** If no errors appeared, your firmware was successfully setup
 *** A reboot is needed to activate the new firmware
$ sudo shutdown -r now

Once the RPi has rebooted you can see what version you have:

$ /opt/vc/bin/vcgencmd version
Jun 17 2013 20:49:11
Copyright (c) 2012 Broadcom
version d380dde43fe729f043befb5cf775f99e54586cde (clean) (release)

Now you need to update all the software. This can take a little while but it’s all automatic:

$ sudo apt-get update
$ sudo apt-get upgrade

Installing GMediaRenderer

Please note there are (yet again) updated instructions for installing gmediarender.

Log in to your RPi and make sure you are in your home directory. Get a copy of the gmrender-resurrect project from GitHub and enter the new directory that appears:

$ cd
$ git clone https://github.com/hzeller/gmrender-resurrect.git
$ cd gmrender-resurrect

Henner Zeller has done a great job in fixing bugs and adding features to the old gmrender project and now has a Raspberry Pi himself so has made sure the instructions included with gmrender-resurrect work very nicely. All you have to do now is follow the instructions in the INSTALL.md file (type “more INSTALL.md” to see them, or go see them online at GitHub):

$ sudo apt-get install autoconf automake libtool
$ sudo apt-get install libupnp-dev libgstreamer0.10-dev \
                gstreamer0.10-plugins-base gstreamer0.10-plugins-good \
                gstreamer0.10-plugins-bad gstreamer0.10-plugins-ugly \
                gstreamer0.10-ffmpeg \
                gstreamer0.10-pulseaudio gstreamer0.10-alsa
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
$ sudo cp scripts/init.d/gmediarenderer /etc/init.d

If you followed up to that point you will have just copied the “init script” that starts and stops the gmrender service into the /etc/init.d directory where all these scripts live. Henner’s script may need editing for your situation but it is all commented to tell you what to do. I use two Raspberry Pis in two rooms so I just changed the UPNP_DEVICE_NAME to “kitchen” and one to “bedroom”. The init script automatically generates a unique identifier (UUID) for each Raspberry Pi that you use it on so if you use more than one then they won’t clash on your network. If you need to edit the file, use “vi” or “nano” to edit the file /etc/init.d/gmediarenderer

To actually get the operating system to run the init script at the right times we need one more command and then we might as well reboot to test it:

$ sudo update-rc.d gmediarenderer defaults
$ sudo shutdown -r now

Test that GMediaRenderer is running by listing all the processes with “ps” and searching the output for gmediarender with “grep”:

$ ps aux|grep gmedia
 2279 ?        Ssl   69:52 /usr/local/bin/gmediarender -f Bedroom -d -u bd1dcf3e746aa69812943cb1d00f7ebc --gstout-audiosink=alsasink --gstout-audiodevice=sysdefault --gstout-initial-volume-db=-10

Your output won’t be exactly the same as that but as long as you get something then it’s running.

Setting the default volume

Probably the easiest way to turn the volume up is to run the alsamixer command and press the up arrow cursor until the screen looks like this:
alsamixer on a Raspberry Pi
Press the Escape key to exit. You then need to store that configuration so that it is the default when the machine is turned on:

$ sudo alsactl store

At this point you should move the Raspberry Pi so that you can plug it in to your amplifier. These instructions assume you are just going to use the 3.5mm stereo audio jack. The sound quality from that is not the best in the world but for many people it is good enough. If you want better then you can buy a USB sound card very cheaply but then the sound configuration will be different and I can’t help you on that (yet).

Checking that ALSA is fine

To summarise this part, I didn’t have to change anything even though it looked like it wasn’t working. I’m not sure what’s going on but I’ve included some diagnostic output here in case it is useful. You can probably skip on to the next section!

Check what the “sysdefault” audio sink is that GMediaRenderer is going to use:

$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
sysdefault:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device

More information from “amixer”. This looks suspicious as it says that the playback is “Mono” when we’d expect “Stereo”:

$ amixer
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -1862 [79%] [-18.62dB] [on]

Confirm that the correct driver is loaded (bcm2835):

$ lsmod|grep snd
Module                  Size  Used by
snd_bcm2835            16304  1
snd_pcm                77560  2 snd_bcm2835
snd_seq                53329  0
snd_timer              19998  2 snd_pcm,snd_seq
snd_seq_device          6438  1 snd_seq
snd                    58447  6 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
snd_page_alloc          5145  1 snd_pcm

Run a speaker test:

$ speaker-test

I found this kept testing what it thought was “Front Left” and sending noise out of both speakers. There are files on the RPi that are supposed to play out of only one speaker which should be useful for testing:

$ aplay ./share/sounds/alsa/Front_Right.wav
$ aplay ./share/sounds/alsa/Front_Left.wav

I found that both of these came out of both speakers. Another speaker test showed that stereo was possible:

$ speaker-test -c 2

That resulted in sound coming from each speaker in turn! Finally I tried playing two MP3s (left and right) from a useful page and they also worked fine:

$ sudo apt-get install mpg123
$ cd /tmp
$ wget http://www.richardfarrar.com/audio/right.mp3
$ wget http://www.richardfarrar.com/audio/left.mp3
$ mpg123 right.mp3
$ mpg123 left.mp3

Once I found that MP3s were in stereo I finished the rest of the installation and found that music from GMediaRenderer was also in stereo. There’s definitely something wrong but as it doesn’t affect what we want to do I’m leaving it well alone for now.

Using your phone as a controller

To control the music with your phone I use BubbleUPnP for Android. Go to Google Play and install BubbleUPnP. It is a UPnP renderer and control point and also works with the OpenHome protocol (more on that later). In other words, it will play music (and videos and pictures) from the a media server if you have one and can also tell the Pi to play music. The free app has some limitations (not too restrictive) and you can pay £3 to have it unrestricted which is well worth it whether you need to or not if you ask me. Other UPnP controllers exist and are no doubt also available for iPhone but I haven’t tried them.

If you run BubbleUPnP and go to the “Devices” screen then you should see your Raspberry Pi listed under the “Renderers” section along with the “Local Renderer” which is the phone itself. Select the Raspberry Pi. In the “Libraries” section you should see “Local Media Server” which is the files (e.g. music) on your phone and you may see other music libraries as well if you have a media server in the house. To play music from your phone through the Raspberry Pi select the Local Media Server, choose some music from the “Library” screen and get it to play.

If someone else in the house also has BubbleUPnP installed on their phone and configured correctly then you can also choose music from their phone to play on the Raspberry Pi.

Playing music from a media server

I have all my music stored in FLAC and MP3 format on a small Linux computer that is on all the time: this is my “media server”. You may have a laptop or computer with music on which is on sometimes, or a NAS drive with music, or you might put music on a USB disc and plug that into the Raspberry Pi. All these options can be considered to be media servers.

To “serve” the music there must be a computer with software on that understands the UPnP protocol so that the phone can find it and select music from it. When you do this, the phone just tells the Raspberry Pi to fetch the music directly from the media server so it doesn’t all stream via the phone, which is good because it doesn’t suck the battery.

I’ll try to cover some of the options here. There is a big list of UPnP servers on Wikipedia.

Serving music from a Windows computer

I haven’t done this, but there are various options that are known to work:

Configure the software and it should appear in the “Libraries” list on the BubbleUPnP “Devices” screen.

Serving music using MiniDLNA on a separate Linux computer

This is what I have: a computer running Linux with the music stored on it. Again, there are many options but I have chosen to use the
MiniDLNA software. You can most likely find MiniDLNA in your package manager. For me I did:

$ sudo apt-get install minidlna

Point minidlna at your music files by editing the /etc/minidlna.conf file, e.g.:

# set this to the directory you want scanned.
media_dir=A,/mnt/usbdisc1/music/albums

# set this if you want to customize the name that shows up on your clients
friendly_name=My DLNA Server

# set this if you would like to specify the directory where you want MiniDLNA to store its database and album art cache
db_dir=/var/cache/minidlna

I also had to “sudo chown minidlna.minidlna /var/cache/minidlna” to get it to work, but YMMV.

The log for minidlna is in /var/log/minidlna.log so to see the latest messages do “tail -f /var/log/minidlna.log” and use Ctrl-C when you’ve had enough. Sometimes you need to force minidlna to rescan your media files, in which case use “sudo service minidlna force-reload”.

Serving music using MiniDLNA on the Raspberry Pi

If you have no other computer that is on all the time then you can put your music on a USB hard drive and plug that into the Raspberry Pi. The Raspberry Pi should find the USB drive automatically and mount it, making it available for use (type “mount” to see what’s available). You will still need to have the UPnP server so follow the instructions above to install MiniDLNA. You will have to set the “media_dir” config option to point to your USB drive. (Sorry this is a bit brief, I haven’t tried it.)

Serving music using a NAS

If you have a NAS on your network, or you have a Windows computer that is sharing a drive with your music on then you can mount the network drive on your Raspberry Pi and get the music as if it is on a local disc (i.e. follow the previous section). To get the network drive mounted, follow these helpful instructions.

Using multiple synchronised controllers

If you’ve stuck with it so far then you have one or more Raspberry Pis playing music from one or more media servers, all controlled from your phone. If you have more than one Android device in your house then there is one remaining problem that needs to be solved. Each BubbleUPnP controller on a phone can see the music files on the server and can tell the Raspberry Pi to play music but they will be fighting each other with no shared playlist or shared “playing now” indication.

To achieve the situation shown in the video at the start we need to use the OpenHome protocol on top of all the UPnP devices so that all your controllers (phones, tablets) share the same playlist, volume and “playing now” view. To do this we need BubbleUPnP server. Again, there are many places this last piece of software can be installed. There are instructions provided at on the BubbleUPnP server page but I’ll explain a little more. To me it makes most sense to have BubbleUPnP server running on the same machine as the MiniDLNA service.

BubbleUPnPServer on a separate Linux computer

My server runs Ubuntu so all I had to do was:

$ sudo apt-get install openjdk-7-jre-headless
$ sudo add-apt-repository ppa:bubbleguuum/bubbleupnpserver
$ sudo apt-get update
$ sudo apt-get install bubbleupnpserver
$ sudo start bubbleupnp

BubbleUPnPServer on the Raspberry Pi

Firstly install Java:

$ sudo apt-get install openjdk-7-jre-headless

Then download BubbleUPnPServer, make a place to install it and unzip the package. We’ll also install ffmpeg so that it can transcode files if necessary:

$ cd /tmp
$ wget http://www.bubblesoftapps.com/bubbleupnpserver/BubbleUPnPServer-distrib.zip
$ cd /usr/local/bin
$ sudo mkdir BubbleUPnPServer
$ cd BubbleUPnPServer
$ sudo unzip /tmp/BubbleUPnPServer-distrib.zip
$ sudo apt-get install ffmpeg

The easiest way to get the BubbleUPnPServer running is to use the provided launch.sh script, firstly making it executable:

$ sudo chmod +x launch.sh
$ sudo ./launch.sh > /dev/null 2>&1 &

That second command is running the launch script and sending all its output to /dev/null (which means it doesn’t appear on your terminal). The final “&” means it is run in the background so you get your terminal prompt back. Check it’s running like this:

$ ps aux |grep Bubb
13089 pts/0    Sl     1:18 java -Xss256k -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -jar BubbleUPnPServer.jar
13212 pts/0    S+     0:00 grep --color=auto Bubb

The log file for the service can be found in /usr/local/bin/BubbleUPnPServer/BubbleUPnPServer.log.0 so if you are still in the same directory, typing “tail -f BubbleUPnPServer.log.0″ will show you the latest messages (use Ctrl-C to stop viewing).

The problem with this approach is that the BubbleUPnPServer process will not start automatically if you reboot your Raspberry Pi so we need an init script for it. Chris Mobberley has written one just for this purpose, but you’ll need to change the DAEMON_PATH definition from “/var/www/bubbleupnp” to “/usr/local/bin/BubbleUPnPServer” to be consistent with my previous instructions. I’ve also just posted a more generic guide to init scripts that could be adapted to this case.

Setting up BubbleUPnPServer

Wherever you have installed BubbleUPnPServer you should now have it running. You need to go to the server’s admin web page to configure it. The admin page can be found on port 58050 so in your web browser go to http://hostname:58050 where “hostname” is the name of the computer running BubbleUPnPServer. If you’ve just installed it on a Raspberry Pi then you might not have a hostname that the web browser recognises. In which case use the Pi’s IP address, finding this as so:

$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether b8:27:eb:94:63:30 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.59/24 brd 192.168.1.255 scope global eth0

So in this case the RPi’s address is 192.168.1.59 (under “eth0″ as it is plugged in with an ethernet cable) and I need to go to http://192.168.1.59:58050 in my web browser. If you had it on a wireless network then the IP would be under the “wlan0″ category.

Once you have the admin page then follow the instructions from the BubbleUPnPServer website. You should see you Raspberry Pi listed in the Media Renderers tab. Tick the box to “Create an OpenHome renderer”.

Using the BubbleUPnPServer

Once you have created the OpenHome renderer then you can use it from your phones. Go back to BubbleUPnP on your phone and go to the “Devices” screen. You should now see you Raspberry Pi there twice, once as before and now also there with “(OpenHome)” after it. If you use this renderer from your phones then all instructions go via the BubbleUPnPServer and all your phones can share the same playlist etc.

BubbleUPnP for Android using OpenHome

BubbleUPnP for Android using OpenHome

Final thoughts

Finally, there is a lot more to the BubbleUPnP client and server that I couldn’t cover here and which isn’t to do with the Raspberry Pi. The client for instance can play music from internet radio stations and from Google Music. You can also set up the server so that you can access it from outside your house and by some clever configuration make it so that if you go to a friend’s house who has a DLNA renderer (lots of TVs do these days) then you can use your phone to tell your friend’s TV to play music from your server!

This solution does not create synchronised music coming from several RPi’s at once. I understand this can be done with Squeezelite (more info here).

If you have Apple devices then you might want to use Airplay, in which case look at shairport.

There is a new protocol called MagicPlay which is an open version of AirPlay. Again, I’ve not tried it but it looks very promising.

Lots of people are doing the same sort of thing. There’s a particularly good post from Mark.

I’m happy to answer questions below, but do read the massive comment thread on the previous post and the Raspberry Pi forum. I’ve tried to address some ALSA issues in another post (though please note that that was with a different Wheezy and firmware version).


2013-07-22, edit: fixed typo in alsactl command.
2013-07-23, edit: included more info on the init script for BubbleUPnP server.
2013-08-11, edit: added BubbleUPnP for Android screenshot showing OpenHome.
2014-02-20, edit: updated BubbleUPnP server version to 0.8.
2014-08-31, edit: updated BubbleUPnP server version to 0.8.3.

Sound configuration on Raspberry Pi with ALSA

While setting up a Raspberry Pi to play streamed music using UPnP, I have had quite a bit of trouble understanding how to configure the sound on my Raspberry Pi. This is partly because I am running it in headless mode (no graphical desktop) and partly because sound on Linux is fiendishly complicated.

Anyway, I am making progress in understanding what’s going on but I am no expert. Here are my findings on how to control the ALSA system from the command line. All I am focussed on here is getting control of the sound output by the 3.5mm stereo socket. If you want to control the output over the HDMI socket or an external USB sound card then you’ll need to do some of your own investigation.

ALSA is the lowest level of the Linux sound stack.  The “alsa-utils” package comes ready installed on the debian wheezy distribution I am using (2012-12-16-wheezy-raspbian.zip).  It provides some useful commands: amixer, alsamixer, alsactl, aplay and speaker-test.

Testing

It’s good to be able to test things as you go a long to see what affect configuration changes have. You can do this with the “speaker-test” command for one, which will by default play white (actually pink) noise out of the speakers. Press Ctrl-C to stop it.

Another command to try is “aplay”. This command will play WAV files for instance as well as lots of other basic sound file types (but not things with complex compression such as MP3, FLAC, OGG, etc). The Pi comes with some sound files already present, for instance in /usr/share/scratch/Media/Sounds. Try:

$ aplay /usr/share/scratch/Media/Sounds/Vocals/Singer2.wav

To get more information while the sound is playing, use the “-v” and “-V” options, e.g.

$ aplay /usr/share/scratch/Media/Sounds/Vocals/Singer2.wav -v -V mono

That will print a lot of info about the sound file and what device it is being sent to as well as a VU meter as the sound plays.

To see the available devices, use “aplay -L”. My machine gives this output (since installing PulseAudio):

$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
pulse
    Playback/recording through the PulseAudio sound server
sysdefault:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device

It shows that the default device to use is directly to the ALSA device. Interestingly, if I try to play via PulseAudio using aplay with “aplay -D pulse ” then I get a bit of a pop but no sound…

amixer

$ amixer
Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined penum
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 65536
  Mono:
  Front Left: Playback 65536 [100%] [on]
  Front Right: Playback 65536 [100%] [on]
Simple mixer control 'Capture',0
  Capabilities: cvolume cswitch cswitch-joined penum
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 65536
  Front Left: Capture 0 [0%] [on]
  Front Right: Capture 0 [0%] [on]

Looking at the top part of the output, we can see that the playback volume for the left and right channels are both at maximum (65536, which is 2^16) and are both unmuted (“on”).

To control these settings we can use the alsamixer command which gives a graphical display (in your terminal) or the amixer command. Let’s look at amixer first:

$ amixer controls
numid=4,iface=MIXER,name='Master Playback Switch'
numid=3,iface=MIXER,name='Master Playback Volume'
numid=2,iface=MIXER,name='Capture Switch'
numid=1,iface=MIXER,name='Capture Volume'

That’s the list of things you can change (control) through the command. We can look at the playback volume in more detail:

$ amixer cget numid=3
numid=3,iface=MIXER,name='Master Playback Volume'
  ; type=INTEGER,access=rw------,values=2,min=0,max=65536,step=1
  : values=65536,65536

This shows the maximum and minimum values for the playback volume and that it is actually a pair of values (for left and right channels). For instance, to change the playback volume we can do:

$ amixer cset numid=3 50%
numid=3,iface=MIXER,name='Master Playback Volume'
  ; type=INTEGER,access=rw------,values=2,min=0,max=65536,step=1
  : values=32768,32768

If you wanted to change the left channel to 50% and the right to 100% for some reason then this command is for you:

$ amixer cset numid=3 50%,100%
numid=3,iface=MIXER,name='Master Playback Volume'
  ; type=INTEGER,access=rw------,values=2,min=0,max=65536,step=1
  : values=32768,65536

To mute the sound you can you control 4:

$ amixer cset numid=4 off
numid=4,iface=MIXER,name='Master Playback Switch'
  ; type=BOOLEAN,access=rw------,values=1
  : values=off

This also affects the volume values on control 3:

$ amixer cget numid=3
numid=3,iface=MIXER,name='Master Playback Volume'
  ; type=INTEGER,access=rw------,values=2,min=0,max=65536,step=1
  : values=0,0

However, the value of the volumes must be stored somewhere because when you unmute it again it restores them.

I have found odd effects when changing the volume while it is muted so best to avoid doing that.

Saving the ALSA state

The operating system saves the ALSA sound configuration when you turn it off and restores it when you turn it on. This is done with the /etc/init.d/alsa-utils script. The state is stored and restored using this file: /var/lib/alsa/asound.state

Once you have the sound configuration as you want it you can store it there using the alsactl command which you have to run with root permissions as it changes a protected file. Let’s set the volume to max, unmute it and store it:

$ amixer cset numid=3 100%
numid=3,iface=MIXER,name='Master Playback Volume'
  ; type=INTEGER,access=rw------,values=2,min=0,max=65536,step=1
  : values=65536,65536
$ amixer cset numid=4 on
numid=4,iface=MIXER,name='Master Playback Switch'
  ; type=BOOLEAN,access=rw------,values=1
  : values=on
$ sudo alsactl store

For me, this gives this changes /var/lib/alsa/asound.state to be:

state.ALSA {
        control.1 {
                iface MIXER
                name 'PCM Playback Volume'
                value 399
                comment {
                        access 'read write'
                        type INTEGER
                        count 1
                        range '-10239 - 400'
                        dbmin -9999999
                        dbmax 400
                        dbvalue.0 399
                }
        }
        control.2 {
                iface MIXER
                name 'PCM Playback Switch'
                value true
                comment {
                        access 'read write'
                        type BOOLEAN
                        count 1
                }
        }
        control.3 {
                iface MIXER
                name 'PCM Playback Route'
                value 2
                comment {
                        access 'read write'
                        type INTEGER
                        count 1
                        range '0 - 2'
                }
        }
}

If we mute it then have another look, line 5 changes to “value -10239″, line 13 changes to “dbvalue.0 -9999999″ and line 19 changes to “false”.

If we were to unmute and then set the volume to 50% (as described above) then line 5 changes to “value -1405″ and line 13 to “dbvalue.0 -1405″ (with line 19 being now set to “true”). Not quite sure where these numbers come from, they are probably the decibel volumes which are logarithmic, but let’s not go there…

If you want to stop the current state being saved when the machine shuts down then you need to disable the alsa-utils init script from running when the machine enters runlevel 0 (halt) and 6 (reboot). A slightly hacky way of doing this is to execute these commands:

$ sudo mv /etc/rc0.d/K01alsa-utils /etc/rc0.d/k01alsa-utils
$ sudo mv /etc/rc0.d/K06alsa-utils /etc/rc6.d/k01alsa-utils

Note that the files have been renamed to have a lowercase “k” at the start. When the machine enters runlevel 0 for instance (it does this when shutting down) all the scripts starting with “K” in the /etc/rc0.d folder are executed. By renaming it to start with a lowercase “k” the file is ignored and the ALSA state is not saved.

alsamixer

As well as using amixer on the command line to change the volumes and so on, you can also use a slightly graphical utility called alsamixer. Just type “alsamixer” and you’ll get something like the screenshot shown below:

alsamixer on a Raspberry Pi

In this utility you can move the volume up and down using the up and down cursor keys, mute and unmute using the “m” key and move from one device to another (if you have them) using the left and right cursor keys. Press the Esc key to exit. If you play with this and then type “amixer” once you’ve exited then you’ll see that the changes are reflected in the output of that command as well.

Final Thoughts

I hope that’s useful to someone like me who is struggling to understand all this. It is only one part of the stack, so I hope to look into PulseAudio in more detail another time as I think that’s where my problems are at the moment.

One last thing: if you completely mess things up then this command should sort it all out and make things sane again (sets volume to 44% for me):

$ sudo /etc/init.d/alsa-utils reset