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 20 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 25 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 23 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; 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). 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

Updates

  • 2013-09-30: corrected mistake in use of --make-pidfile (thanks to Max Sistemich).

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

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

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/0.8/BubbleUPnPServer-0.8.zip
$ cd /usr/local/bin
$ sudo mkdir BubbleUPnPServer
$ cd BubbleUPnPServer
$ sudo unzip /tmp/BubbleUPnPServer-0.8.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.

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

Using a Raspberry Pi with Android phones for media streaming with UPnP / DLNA

Edit, 2013-07-21: Please note there is now a completely updated (and simpler) blog post on this subject.

This summarises and completes my previous posts on configuring a Raspberry Pi to play music streamed from another computer in the house, using Android phones as remote controls.

There is quite a long discussion below and also an area on the Raspberry Pi forum for discussing this solution.

What we are aiming for

A music system with your music stored on a server and played through your Hi-Fi via the Raspberry Pi, all controlled by multiple, synchronised Android phones/tablets. In addition you can play music from the server on your phone either in the house or anywhere else. This is similar to using Apple’s AirPlay system but uses free software and open standards.

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.

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)
  • 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
  • An amplifier with a 3.5mm auxiliary input and speakers (perhaps a TV sound bar?)
  • 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)

Note: these instructions assume you have your music on a linux server, but it’s also possible to get all the necessary software on one Raspberry Pi and just point it at a NAS (or, indeed, plug a USB drive in directly). See comments for some more suggestions.

Instructions

Install Debian Wheezy on the Pi

The Raspberry Pi comes with no operating system (OS). The first thing to do is to download one and put it onto the SD card. These instructions assume you are using the Debian Wheezy image (I have checked these instructions work with 2012-12-16-wheezy-raspbian.zip) from the Raspberry Pi site. There are brief instructions there and detailed instructions at elinux.org.

Once you have the OS on the SD card, put it in the Raspberry Pi, plug in your keyboard and TV (via the HDMI or composite video sockets), plug in the micro-USB power supply and turn it on.

Getting the Pi on the wireless network

You can of course skip this if you’re just going to plug it in with an ethernet cable.

Different wireless dongles use different drivers and different home networks have different security settings. It’s therefore pretty tricky to describe how to do this in a generic way but I can give you some pointers.

The lsusb command shows you what USB devices are plugged in. The 4th one on the list below is the Wi-Fi dongle.

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter

I didn’t have to edit the /etc/network/interfaces file. It was already how I needed it, namely:

auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

Amongst other things, this says that the wireless dongle can be plugged in and out when you like, it is configured with DHCP (so it gets an IP address and hostname automatically from your router) and that the password and other security settings for your Wi-Fi can be found in the /etc/wpa_supplicant/wpa_supplicant.conf file.

By typing the command “sudo vi /etc/wpa_supplicant/wpa_supplicant.conf” you can edit the file (replace “vi” with “nano” if you like your text editors to help you out a bit). For me I needed to add these lines:

network={
  ssid="your_ssid_goes_here"
  scan_ssid=1
  proto=RSN
  key_mgmt=WPA-PSK
  pairwise=TKIP
  psk="this is where your secret passphrase goes"
}

Your configuration depends on what Wi-Fi security settings you have on your router: the above work for “WPA2 personal” with “TKIP+AES” for the WPA algorithm with a WPA shared key. There’s more info to be found by typing “man wpa_supplicant.conf”.

At this point, typing “ifconfig” will show you the configuration of “eth0″ (the ethernet interface with the cable in), “lo” (a dummy interface) and “wlan0″: the new wireless interface.

wlan0     Link encap:Ethernet  HWaddr 00:01:02:03:04:05
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

At this point you should probably also configure your router to provide the Pi with an IP address via DHCP (it may do this automatically). I use DD-WRT on my router which lets me assign it a static IP address and a hostname as well. Again, it’s a bit beyond the scope of this post to explain all that but you may need the Wi-Fi dongle’s MAC address which is called the “HWaddr” in the ifconfig output.

If you then do a “sudo ifdown wlan0″ and a “sudo ifup wlan0″ to take the interface down and bring it up again then with any luck, on executing “ifconfig” again you’ll see an additional line showing that your router has assigned an IP address to the Wi-Fi dongle:

wlan0     Link encap:Ethernet  HWaddr 00:01:02:03:04:05
          inet addr:192.168.1.99  Bcast:192.168.1.255  Mask:255.255.255.0
          etc, etc... (addresses changed to protect the innocent)

Installing software on the Pi

Now the Raspberry Pi is on the wireless network, you can disconnect it from the TV and keyboard and put it next to the Hi-Fi. Connect it to the auxiliary input of the Hi-Fi with a stereo audio cable (3.5mm jack like headphones use) and power it up again.

Log in to the Pi from another computer using SSH (username “pi”, password “raspberry”). I use PuTTY from my Windows laptop which does the job nicely. You can then type in comfort at your laptop rather than sitting on the floor by the TV. Incidentally, with PuTTY you paste by clicking with the right mouse button (and copy just by highlighting with the left). If you’re on a Windows machine therefore you can copy and paste from this blog post using Ctrl-C to copy and right-click in PuTTY to paste.

The first thing to complete the set-up of the Pu and update all the packages already installed on the Pi to the latest versions:

$ sudo raspi-config
$ sudo apt-get update
$ sudo apt-get upgrade

The first command runs a config utility that lets you choose your country, keyboard, etc and also lets you choose to stop the Pi booting straight into a desktop which we don’t want. The next gets the latest list of packages and the third command updates existing packages to the latest versions found on that list. This will take a little while.

We then need to install gmrender-resurrect which is a UPnP “renderer”. That is, it plays (renders) music files when told to via the UPnP protocol. It is not provided as a pre-built package so we also have to compile it and manually install all the prerequisites.

# install all the packages we'll need

$ sudo apt-get install git automake libglib2.0-dev gstreamer0.10-alsa gstreamer0.10-tools libgstreamer0.10-dev libupnp-dev libxml2-dev gstreamer0.10-ffmpeg gstreamer0.10-plugins-base gstreamer0.10-plugins-good gstreamer0.10-fluendo-mp3 gstreamer0.10-pulseaudio pulseaudio

# Now get the latest gmrender-ressurect using git

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

# build and install gmrender

$ ./autogen.sh
$ ./configure LIBS=-lm
$ make
$ sudo make install

gmrender uses GStreamer to play sound and GStreamer uses ALSA. For some reason, the sound quality through GStreamer at this point is really bad. To get it sounding good we need to direct the sound through the PulseAudio system (which then uses ALSA). To make GStreamer use PulseAudio rather than directly using ALSA you need to do the following configuration:

$ gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosink pulsesink
$ gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosrc pulsesrc

Note that these commands are executed as the “pi” user and only apply to the “pi” user. If you later run gmrender (or GStreamer directly) as another user (such as root) then the sound quality will be bad again as PulseAudio won’t be in the stack.

To get PulseAudio to start on boot and to allow the “pi” user to access it, two more changes are required:

  1. Edit /etc/default/pulseaudio and change the first uncommented line to “PULSEAUDIO_SYSTEM_START=1″. This is not recommended but it works in this case.
  2. Execute the command “sudo adduser pi pulse-access” to add the pi user to the pulse-access group so that it is permitted to use PulseAudio.

You’ll also need to turn the volume up on the Pi. To do this, run “alsamixer” and press the up arrow cursor key until the volume display gets to the top (if this isn’t doing anything then it may be muted: press “M”). Then press the Esc key to exit. To then save this configuration for the next time the Pi boots, type “sudo alsactl store” which updates the /var/lib/alsa/asound.state file.

2013-01-91 Edit: I’ve written much more about configuring ALSA on the Raspberry Pi here.

To make gmrender start when the Pi is turned on, create the file /etc/init.d/gmediarenderer (as root) with the following contents (e.g. using vi or nano):

#!/bin/sh

### BEGIN INIT INFO
# Provides: gmediarender
# Required-Start: $remote_fs $syslog $all
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start GMediaRender at boot time
# Description: Start GMediaRender at boot time.
### END INIT INFO

USER=root
HOME=/root
export USER HOME
case "$1" in
start)
echo "Starting GMediaRender"
start-stop-daemon -x /usr/local/bin/gmediarender -c pi:audio -S -- -f "Raspberry" -d
;;
stop)
echo "Stopping GMediaRender"
start-stop-daemon -x /usr/local/bin/gmediarender -K
;;
*)
echo "Usage: /etc/init.d/gmediarender {start|stop}"
exit 1
;;
esac
exit 0

Then do:

$ sudo chmod 755 /etc/init.d/gmediarenderer
$ sudo update-rc.d gmediarenderer defaults

Reboot (either “sudo shutdown -r now” or just turn it off and on again) and you should have a working system.

Installing software on the media server

I have all my CDs ripped as FLAC files along with some MP3s I’ve bought on a small linux box (an Acer Revo Aspire 3700 bought a couple of years ago in the pre-Raspberry era) with 2 USB drives plugged into it. It currently runs some version or other of Ubuntu. There’s no reason that you couldn’t use another Raspberry Pi for this with a USB disc drive attached or even the same Raspberry Pi, perhaps pointed at a NAS box for the media storage.

We need to install:

  • minidlna: this serves up the music files using the DLNA / UPnP protocol;
  • BubbleUPnP server: this provides the OpenHome protocol on top of all the UPnP devices so that all your controllers (phones, tablets) share the same playlist and “playing now” view.

For minidlna you can just use apt-get:

$ 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 BubbleUPnP server is also easy to install, just following the instructions on the web site, which for me (on Ubuntu) was just:

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

To install BubbleUPnP on a Pi, follow the “Other Java Platforms” instructions on the BubbleUPnP server web page (e.g. download the zip file etc).

Then go to the address “http://your.media.server:58050″ and you will see the BubbleUPnP server admin interface. The important page for us is the “Media Renderers” tab where you should find the Raspberry Pi’s gmrender service listed as “Raspberry”. Select it and tick the “Create an OpenHome renderer” box on the right and that’s that sorted.

Installing software on Android devices

If you have an Android phone then go to Google Play and install BubbleUPnP. It is a UPnP renderer and control point and also works with the OpenHome protocol. In other words, it will play music (and videos and pictures) from the media server and can also tell the Pi to play music. As it uses the OpenHome system, playlists and so on are shared between all Android devices connected to the system. The 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.

If you don’t have an Android phone, just go and buy a second-hand one for £50, don’t bother sticking a SIM card in it and just use it as a remote control!

Once installed on the phone, run BubbleUPnP and go to the “Devices” page. You should see under “Renderers” the “Local renderer” (your phone), “Raspberry” and “Raspberry (OpenHome)”. “Raspberry” will work as the renderer but choosing that bypasses the OpenHome goodness already described. So, choose “Raspberry (OpenHome)” and under the “Libraries” select your media server. You will also see “Local Media Server” there (your phone’s files) and perhaps some other computers on your network.

Finally, go to the “Library” page, choose some music and play it: it should come out of the Hi-Fi!

Final thoughts

In this post I have concentrated on the particular steps I have taken to get a working system from my starting point. There are many possible variations on this. For instance, you could have a workable system without a dedicated media server but just using your home PC instead: BubbleUPnP Server runs on Windows as well (if you need it at all), and you could use MediaMonkey for instance on the same machine to be the UPnP server. Or you could do without the media server entirely and just stream music from your phone to the Raspberry Pi.

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

Please see the Raspberry Pi forum for more discussion as well as the comments below.

2013-01-08 Edit: added instructions for getting PulseAudio to start on boot and altered gmediarenderer init script to make it start after PulseAudio.

2013-01-09 Edit: added instructions to save ALSA volume between reboots.

2013-01-10 Edit: clarified how to install BubbleUPnP Server on a Raspberry Pi.

2013-01-14 Edit: added link to Raspberry Pi forum.

2013-01-19 Edit: added better ALSA instructions and linked to my other post.

Making gmediarender start on boot

Now gmediarender is compiled and gstreamer works on the Raspberry Pi we need to get it all to start on boot.

Fairly standard stuff here (copied from Malte’s post in Chris’ blog). Create a file /etc/init.d/gmediarenderer with the following contents:

#!/bin/sh

### BEGIN INIT INFO
# Provides: gmediarender
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start GMediaRender at boot time
# Description: Start GMediaRender at boot time.
### END INIT INFO

USER=root
HOME=/root
export USER HOME
case "$1" in
start)
echo "Starting GMediaRender"
start-stop-daemon -x /usr/local/bin/gmediarender -c pi:audio -S -- -f 'Raspberry' -d
;;
stop)
echo "Stopping GMediaRender"
start-stop-daemon -x /usr/local/bin/gmediarender -K
;;
*)
echo "Usage: /etc/init.d/gmediarender {start|stop}"
exit 1
;;
esac
exit 0

Then do:

$ sudo chmod 755 /etc/init.d/gmediarenderer
$ sudo update-rc.d gmediarenderer defaults

to make the script executable and add in all the symbolic links from the /etc/rc.x directories.

You can then do “sudo service gmediarenderer start” to run gmediarenderer as a daemon there and then or reboot and it will start automatically. Interestingly, I tried it without the “-c pi:audio” so that the daemon ran as root and the sound quality went bad again. Fine running as the “pi” user though.

In summary, we now have:

  1. minidlna running on the media server (a nettop linux box behind the sofa);
  2. gmedia-resurrected running on the Raspberry Pi to play the music through the mini Hi-Fi;
  3. bubbleupnp on multiple Android phones to control the music choice.

This is a pretty good solution but has some problems caused by the playlist being held on the controller (one of the phones). So if one of us sets an album playing and then goes out, the Pi doesn’t receive the instruction to play the next song. If you look at a second controller then you cannot see what is playing (it may think something else is), but on the plus side, the volume controls work on all controllers and the play/pause does as well.

These problems are known of course, and the BubbleUPnP author has another piece of software called BubbleUPnPServer which is an OpenHome renderer. As the site says:

An OpenHome Renderer has the following advantages over a regular UPnP AV renderer:

  • each OpenHome renderer has its own playlist
  • no need to leave the Control Point running for playlist track advance to happen
  • several OpenHome Control Points (BubbleUPnP, Linn Kinsky) can be connected to the same renderer simultaneously, showing the same playlist and playback state
  • create a playing playlist on a device and pick it up later on another device

It looks as though the BubbleUPnPServer basically adds another, persistent and stateful, layer to the system so that an OpenHome controller (such as BubbleUPnP) tells BubbleUPnPServer what to play and it then tells the existing (plain) UPnP renderer what to do. Hopefully I can get this working on the same linux box as minidlna is running on.

Getting gstreamer to work on a Raspberry Pi

Having now got gmrender to compile and run on the Raspberry Pi and use gstreamer as a backend I need to fix the audio quality issues. A bit more googling revealed a post from someone doing much the same as me. One of Chris Baume’s commenters also had problems with the audio qut.ality and suggested that directing the audio via PulseAudio fixed it.

It’s been a long time since I got into the detail of linux audio systems and it all seems to have changed. There’s a great article on how linux audio works which helps explain things a lot.

The following annotated shell transcript shows how I installed PulseAudio and configured gstreamer to use it. I may post have now posted a complete cleaned up installation guide later but personally I find seeing how other people have made mistakes and worked out how to do things instructive as well.

$ sudo apt-get install gstreamer0.10-pulseaudio

# Need to configure gstreamer to use pulseaudio
# Looking here: https://wiki.archlinux.org/index.php/PulseAudio

$ gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosink pulsesink
$ gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosrc pulsesrc

# and another just in case:

$ gconftool-2 -t string --set /system/gstreamer/0.10/default/musicaudiosink pulsesink

# check the keys are there:

$ gconftool-2 -a /system/gstreamer/0.10/default
 musicaudiosink_description = Default
 audiosrc = pulsesrc
 audiosrc_description = Default
 chataudiosink_description = Default
 musicaudiosink = pulsesink
 audiosink_description = Default
 visualization = goom
 videosrc = v4l2src
 audiosink = pulsesink
 chataudiosink = autoaudiosink
 videosink = autovideosink

# Still not working
# Then I realise I don't have pulseaudio itself installed...

$ sudo apt-get install pulseaudio

After doing all of that the sound was just the same. I later realised that I probably didn’t actually have PulseAudio running and would need to start it with the command “pulseaudio –start” but next time I turned the Pi on to try it, PulseAudio was running and the sound from gmedia-resurrected, via gstreamer, to PulseAudio, ALSA and finally to the hardware sounded just great! How strange that adding another layer to the sound stack makes it better, not worse…

One problem I’ve just noticed is that when you skip forwards a track in an album for instance then there are a few pops and clicks.

Next task is to get the gmediarender process to start on boot.

European public holiday leaderboard

I work in a lot of European projects.  This means that we often have weekly teleconferences across several countries which are often scuppered by a partner or partners being on holiday because of a national holiday. In the UK, all our public holidays are put on Mondays (with some Fridays) so that you don’t get the country shutting down in the middle of the week. In other countries the public holidays (e.g. saints’ days) just land on the same date every year with two results:

  1. Sometimes they land on a weekend so most people don’t actually get a holiday.
  2. When they land on a Tuesday or a Thursday lots of people take off the Monday or Friday as well to make a really long weekend and you lose almost half a week.

There is often the feeling expressed that we in the UK don’t get as many holidays as the rest of Europe, but is it true? Euroalert have published an iCalendar format file of all the public holidays for the whole of the European Union. This is very handy as you can import it into Outlook (for instance) and see when a partner is going to be on holiday. As it is in iCalendar format you can also parse it yourself easily and do some investigation:

#!/usr/bin/env python2.7

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

from datetime import date as ddate

class Holiday:
    def __init__(self, date, country):
        d = ddate(int(date[:4]),
                 int(date[4:6]),
                 int(date[6:])
                 )
        self.date = d
        self.country = country

    def __str__(self):
        return self.country + ': ' + str(self.date)

    def _get_day(self):
        # Monday is 0, Sunday is 6
        return self.date.weekday()

    day = property(_get_day)

#http://euroalert.net/dl/docs/open-data/euroalert-Public-Holidays-EU-2012.ics
cal_file = file('c:/tmp/euroalert-Public-Holidays-EU-2012.ics')

holidays = []

ignore_weekends = 1

for line in cal_file:
    line = line[:-1]
    if line.startswith('DTSTART'):
        date = line[-8:]
    if line.startswith('SUMMARY'):
        country = line[8:]
        if '/' in country:
            country = country[:country.index('/')]
        hol = Holiday(date, country)
        if ignore_weekends and hol.day >= 5:
            pass
        else:
            holidays.append(hol)

holidays_by_country = {}
for h in holidays:
    holidays_by_country.setdefault(h.country, [])
    holidays_by_country[h.country].append(h)

countries = holidays_by_country.keys()

countries_by_holidays = {}
for c, h in holidays_by_country.items():
    num = len(h)
    countries_by_holidays.setdefault(num, [])
    countries_by_holidays[num].append(c)

print "*** LEADERBOARD ***"
for n in sorted(countries_by_holidays.keys(), reverse=True):
    print n, ':', countries_by_holidays[n]
print "*******************"

def get_days(countries):
    "Return the number of times not all partners will be on a call for each day of the week."
    holidays_by_date = {}
    for c in countries:
        for h in holidays_by_country1:
            holidays_by_date.setdefault(h.date, [])
            holidays_by_date[h.date].append(h)

    dates = holidays_by_date.keys()
    days = [0,0,0,0,0,0,0]
    for date in dates:
        day = date.weekday()
        #days[day] += len(holidays_by_date[date])  # this would tell you how many partners would be missing in total
        days[day] += 1  # this is how many times not all partners are present
    return days

project_countries = ['Austria', 'Belgium', 'France', 'Greece', 'Spain', 'Sweden', 'Wales and England']
days = get_days(project_countries)
print
print project_countries
print days

That script expects you’ve downloaded the iCalendar file yourself. It parses the file and outputs some info:

*** LEADERBOARD ***
17 : ['Belgium']
14 : ['Hungary']
12 : ['Slovenia']
11 : ['Northern Ireland', 'Austria', 'Cyprus']
10 : ['Malta', 'Slovakia', 'Ireland', 'Scotland']
9 : ['Italy', 'Czech Republic', 'Lithuania', 'Wales and England', 'Poland', 'Greece']
8 : ['France', 'Germany', 'Denmark', 'Spain', 'Finland', 'Sweden', 'Latvia', 'Luxembourg', 'Bulgaria', 'Portugal']
7 : ['Romania', 'Estonia']
6 : ['Netherlands']
*******************

['Austria', 'Belgium', 'France', 'Greece', 'Spain', 'Sweden', 'Wales and England']
[11, 4, 3, 6, 9, 0, 0]

So this is telling us that in 2012, Belgium had 17 days off (and this is weekdays off as the script has been set to ignore the weekends) whereas Wales & England had 9 (Scotland 10) and the poor Dutch only got 6. It also tells us that for the particular set of partners listed, Monday is a terrible day to hold a weekly teleconference (inevitable given the UK being on the list) and Wednesday is good with only 3 days when all partners wouldn’t be there.

Running the script and not ignoring the weekends gives this leaderboard:

*** LEADERBOARD ***
24 : ['Belgium']
17 : ['Hungary']
15 : ['Lithuania', 'Latvia', 'Cyprus']
14 : ['Malta', 'Slovakia', 'Bulgaria']
13 : ['Poland', 'Sweden', 'Portugal', 'Austria']
12 : ['Czech Republic', 'Slovenia', 'Finland', 'Estonia', 'Greece']
11 : ['France', 'Denmark', 'Northern Ireland', 'Romania']
10 : ['Italy', 'Ireland', 'Scotland', 'Luxembourg']
9 : ['Wales and England', 'Germany', 'Spain', 'Netherlands']
*******************

So here, Wales & England trail in last place with 9 days off and Belgium is still unassailable at the top with 24 public holidays. However, as we’ve seen, in other countries many of these “holidays” fall at the weekends so it’s not (quite) as bad as all that. The UK also has a high minimum statutory holiday allowance of 28 days paid annual leave per year. Your employer can choose whether to count the public holidays as part of this allowance though.

If someone can point me at the data for 2013 then that would be great!

A UPnP renderer for the Raspberry Pi

Edit, 2013-07-21: See my complete instructions for setting up the Raspberry Pi here.

Edit, 2013-01-05: See my complete instructions for setting up the Raspberry Pi here.

I want to use a Raspberry Pi to play music through the micro Hi-Fi system in my kitchen/dining room. Up to now I have had a San Francisco Android phone velcroed to the kitchen wall running the Subsonic client and accessing the FLAC files on my media server via the excellent Subsonic server software (which transcodes them on the fly to MP3). This has been a good solution for a couple of years now but one problem is that the headphone output of the San Francisco is not very powerful so we have to turn the (small) amp up to max to get a decent volume and sometimes you want it higher.

I just tested a Raspberry Pi’s audio output and it is more powerful than the phone’s so it would make a good replacement. A couple of years ago when I set up the phone as a media player,  DLNA for sharing/streaming media was not very widespread, but now it’s become quite popular so I’d like to try using that protocol with the Pi. DLNA defines various types of devices, such as “server”, “renderer” and “controller” and they then communicate via Universal Plug and Play (UPnP). I want my media server to be a DLNA server and the Pi to be a “renderer” and all our mobile phones to be the “controllers”.

On the media server I’ve installed minidlna via apt-get and pointed it at my music folder. The server runs as a “minidlna” user and for some reason I had to “chown minidlna.minidlna” the /var/cache/minidlna folder to get it to work but it seems fine now.

To control the system I’ve installed bubbleupnp on my phone and this means I can stream music from the media server to my phone. What I want to do though is use the phone as a UPnP controller and have it instruct the Pi to play (or “render”) the music through the Hi-Fi’s speakers.

Enter gmrender…

There seems to be a shortage of headless UPnP renderers for linux: I just want a server process that sits there and accepts instructions to play music and plays it – nothing more, nothing graphical. XBMC can be a UPnP renderer I believe but that’s way too heavyweight for what I want to do (even though the Raspbmc project makes it easyish). Google found me gmrender but it’s long abandoned. However, a post on Google+ from Henner Zeller sent me on to the gmrender-resurrect project on GitHub where Henner has taken the old code and added some more features.

However, getting it to install on the Raspberry Pi (with standard Debian wheezy OS) was not completely straightforward…

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

# looking at what you get, there is an autogen script so I
# need some more tools...

$ sudo apt-get install automake

# this installs autoconf autotools-dev m4
(load of output snipped...)

$ ./autogen.sh
$ ./configure
$ make
make all-recursive
make[1]: Entering directory `/home/pi/gmrender-resurrect'
Making all in src
make[2]: Entering directory `/home/pi/gmrender-resurrect/src'
gcc -DHAVE_CONFIG_H -I. -I.. -DPKG_DATADIR=\"/usr/local/share/gmediarender\" -Wall -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wwrite-strings -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
main.c:34:18: fatal error: glib.h: No such file or directory
compilation terminated.
make[2]: *** [main.o] Error 1
make[2]: Leaving directory `/home/pi/gmrender-resurrect/src'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/pi/gmrender-resurrect'
make: *** [all] Error 2

# so I am missing glib.h, where do I get that?

$ sudo apt-get install apt-file
$ sudo apt-file update
$ apt-file search /glib.h
libghc-glib-doc: /usr/lib/ghc-doc/haddock/glib-0.12.2/glib.haddock
libgirepository1.0-doc: /usr/share/gtk-doc/html/gi/glib.html
libglib2.0-dev: /usr/include/glib-2.0/glib.h
libglib2.0-doc: /usr/share/doc/libglib2.0-doc/glib/glib.html

# that gives me the answer

$ sudo apt-get install libglib2.0-dev
$ rm config.status config.log
$ ./configure
$ make

(output snipped)
# fails with:

gcc -Wall -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wwrite-strings -o gmediarender main.o upnp.o upnp_control.o upnp_connmgr.o upnp_transport.o upnp_device.o upnp_renderer.o webserver.o output.o output_dummy.o xmldoc.o xmlescape.o -pthread -lgthread-2.0 -lrt -lglib-2.0
upnp_control.o: In function `set_volume_db':
upnp_control.c:(.text+0xc4c): undefined reference to `exp'
upnp_control.o: In function `set_volume':
upnp_control.c:(.text+0xd6c): undefined reference to `exp'
upnp_control.o: In function `upnp_control_init':
upnp_control.c:(.text+0x100c): undefined reference to `log'
collect2: ld returned 1 exit status
make[2]: *** [gmediarender] Error 1

# when it links the code together it can't find the basic maths
# functions, so need to tell it to use the maths lib (why?!)...

$ ./configure LIBS=-lm
$ make
$ sudo make install
$ gmediarenderer --list-outputs
Supported output modules:
  dummy Dummy output module (default)

# so I have installed it but it's no use because
# there is no gstreamer output to play the music

$ sudo apt-get install gstreamer0.10-alsa
$ sudo apt-get install gstreamer0.10-tools
$ sudo apt-get install libgstreamer0.10-dev

# more examination of the config.log reveals that it also
# didn't find the upnp and libxml2 libraries
# why does it just blindly continue?!

$ sudo apt-get install libupnp-dev
$ sudo apt-get install libxml2-dev

$ rm confifg.status config.log
$ ./configure LIBS=-lm
checking for GLIB... yes
checking for GST... yes
checking for LIBUPNP... yes
checking for LIBXML... yes
$ make clean
$ make
$ sudo make install
$ gmediarender --list-outputs
Supported output modules:
  gst   GStreamer multimedia framework (default)
  dummy Dummy output module
$ gmediarender -f Raspberry
Using output module: gst (GStreamer multimedia framework)
Registering support for 'audio/x-raw-int'
Registering support for 'audio/x-iec958'
gmediarender: output_gstreamer.c:482: output_gstreamer_init: Assertion `player_ != ((void *)0)' failed.
Aborted

# what's going on?  More bits of gstreamer needed?

$ sudo apt-get install gstreamer0.10-ffmpeg
$ gmediarender -f Raspberry
Using output module: gst (GStreamer multimedia framework)
...followed by 100 or so media types it can now render...
gmediarender: output_gstreamer.c:482: output_gstreamer_init: Assertion `player_ != ((void *)0)' failed.
Aborted

# more needed?

$ sudo apt-get install gstreamer0.10-plugins-base
$ sudo apt-get install gstreamer0.10-plugins-good
$ gmediarender -f Raspberry

#...and it runs!

At this point, the Pi appears in Bubbleupnp’s “devices” list as a “renderer”. If I select it and then choose a song from the media server and press play all sorts of log messages appear on the Pi’s console. Unfortunately I tried playing a FLAC file and the sound quality is terrible! Playing an MP3 file doesn’t work – it says I have a missing plugin so I had a look (type “sudo apt-get install gstreamer” and press tab) and saw another one that looked to do with MP3s:

$ sudo apt-get install gstreamer0.10-fluendo-mp3

Now I can play an MP3 file and it also sounds terrible…

I copied an MP3 across onto the Pi from the media server (using scp) and tried playing it with mpg123 and it sounds fine. So what is the problem with the gstreamer rendering?

$ gst-launch-0.10 playbin uri=file:///tmp/song.mp3

This command produces the same rubbish output as via gmrender (as expected), so the problem is in gstreamer. I’ll post this and do some more investigation…

Complete on{X} script to control the Where Clock

After a lot of head scratching I’ve finished the on{X} script to control the Where Clock: making it turn  around when I enter or leave places. Here it is:

// add your locations to this list, use as many decimal places as possible, these are fake  :-) 
var locations = [
    {name: "home", lat: 50.9, lon: -1.3, rad: 1},
    {name: "pilates", lat: 51.9, lon: -1.3, rad: 1},
    {name: "pub", lat: 52.9, lon: -1.3, rad: 1}
    ];
var hostname = "your.hostname.here";
var port = "1234";  // your port here

function move(place) {
    console.log('Entered region: ' + place);
    device.ajax(
    {
      url: "http://" + hostname + ":" + port + "/move?l=" + place,
      type: 'GET',
      headers: {}
    },
    function onSuccess(body, textStatus, response) {
        var msg = device.notifications.createNotification('Clock is set to: ' + place);
        msg.show();
        console.log('Success: ' + textStatus);
    },
    function onError(textStatus, response) {
        var msg = device.notifications.createNotification('Failed to set clock to ' + place + '\n' + textStatus);
        msg.show();
        console.log('Error: ' + textStatus);
    });
}

function build_callback(place) {
    console.log("Building callback for " + place);
    return function() {
        move(place);
    };
}

for (i = 0; i < locations.length; i++) {
    var location = locations[i];
    var region = device.regions.createRegion({
        latitude: location.lat,
        longitude: location.lon,
        name: location.name,
        radius: location.rad
    });
    region.on('enter', build_callback(region.name));
    region.on('exit', build_callback("travelling"));
    device.regions.startMonitoring(region);
}
console.log("Script executed");

// test code follows
/*
var regions = device.regions.getAll();
console.log(regions.length);
for (i = 0; i < regions.length; i++) {
    r = regions[i];
    console.log(r.name + ":" + r.latitude + ':' + r.longitude + ':' + r.radius);
}
var locationSignal = { latitude: 50.919675, longitude: -1.377101 };
regions[0].emit('enter', locationSignal);
regions[0].emit('exit', locationSignal);
regions[1].emit('enter', locationSignal);
regions[1].emit('exit', locationSignal);
regions[2].emit('enter', locationSignal);
regions[2].emit('exit', locationSignal);
*/

The hardest part was the callback (line 45). I’m not that good at Javascript and I’m never sure if things are being passed by value or reference and when they are evaluated. You have to provide a function that will be called when a region is entered or exited. The API for regions shows a callback inline with a “signal” parameter passed to it. The tricky thing is, how to do that in a loop? I want to loop through all the locations defined at the top of the script and set all the entry and exit callbacks for them.

You can’t just do

region.on('enter', move(region.name))

because the “move(region.name)” gets evaluated (called) as the callback is defined so it sends instructions to move to all the places at the beginning (and probably not later). So we need some delay to the evaluation.

You also can’t just do

region.on('enter', function () { move(region.name); });

because all those anonymous callback functions get bound to the same instance of “region”: Javascript (unnecessarily) reuses the object each time it goes round the loop. When “region.name” is evaluated it ends up being whatever the last place you defined was. In this example I would always be at the pub…

(To be fair, the surprisingly good Javascript editor in the on{X} web page does warn you against creating functions in loops, presumably for this very reason.)

The solution is in the code above: set the callback to be the result of the “build_callback” function which returns a function that calls the “move” function with the place already evaluated and fixed.

You might have noticed that in the code above, the regions are defined to have a 1m radius.  I originally set them to be 10m which seems to make more sense. However, although this code seems to be correct now it doesn’t actually work very well.  I went to the shops today and it was only once I was about 3 miles away from home that the phone sent the “travelling” signal (because it realised I was outside the home region) and then it did send the “home” signal at some point when I got back but I missed it.

So I think it’s all technically working now but that on{X} just isn’t up to the job.  I might try with tasker instead but I never got on with tasker’s UI.