My latest project was to have wireless audio streaming from my Symbian mobile phone over Bluetooth to a a new set of speakers. I used PulseAudio, Bluez5 and Arch Linux running on a Raspberry Pi. It all works really well. I can connect/disconnect from the phone and everything is automatically started on boot. I’m enjoying it now as I type this.
Thanks to Greg & Helen for the Christmas present! :)
Installing Arch Linux on ARM
I’ve been trying out Arch Linux recently and so far I quite like it. For an experienced Linux user it’s easy to get up and running and to maintain. All the packages are always up to date, which is awesome. Systemd makes managing your own services really simple. Writing custom packages with ABS is a breeze compared to using to my previous experiences with dpkg/apt, RPM or Fink.
So Arch Linux only officially supports the i686 and x86_64 architectures. Fortunately there’s an Arch Linux ARM project which rebuilds all the packages for various ARM architectures. This includes a disk image for Raspberry Pi. Follow the instructions there to get your RasPi up and running with Arch. You can use the excellent Arch Wiki from the main project for the Wifi/Network setup guides.
Make sure your system is up to date. Remember Arch doesn’t support partial upgrades, so always do both the repository update and package upgrade at the same time.
# pacman -Syu
I also chose to use the latest Linux kernel instead of the stable branch with Arch uses by default. If you want this too:
# pacman -S linux-raspberrypi-latest
This is a selection of basic tools that I like to have everywhere.
# pacman -S \ sudo python bash-completion base-devel openssh \ git screen vim mercurial openbsd-netcat rsync unzip
There are two bugs that I had to work around to make this setup functional.
Kernel OOPS with bluetooth & audio at the same time
Firstly using the builtin audio at the same time as the Bluetooth adapter caused a kernel panic! See the GitHub issues RasPi #465, RasPi #482, RasPi #491 and RasPi #499. I worked around this by using a USB audio adapter and blacklisting the internal audio.
$ cat /etc/modprobe.d/use-usb-audio.conf blacklist snd_bcm2835 options snd-usb-audio nrpacks=1
There is a reported work-around to use the builtin audio. Try adding this to /boot/cmdline.txt
PulseAudio too picky when decoding SBC
Secondly PulseAudio seems to be very picky about the SBC data it receives from the phone. After 5-10 mins of playing I’ll see “SBC Decoding Error (-3)”, after which PulseAudio will terminate playback & clean up the Bluetooth connection. I wrote a quick patch to fix this, see commit 4a5f48e7a42f997793db76e2001b7c252f8d93fe. If you want this you can download my custom pulseaudio package and install it with pacman -U instead of using the version from the repository. If you want to build this yourself using ABS then you can download the PKGBUILD and other files.
I’ve submitted this patch to the PulseAudio maintainers, it was merged and will be in the next release.
I’m using a USB audio adapter because of the bug mentioned above, and also the builtin analogue audio is not great quality anyway.
$ lsusb|grep Audio Bus 001 Device 006: ID 0d8c:000e C-Media Electronics, Inc. \ Audio Adapter (Planet UP-100, Genius G-Talk)
I bought it from Adelong computers for $6.50. It sounds great! Make sure you use a powered hub though, the Raspberry Pi is not able to supply too much energy through its USB ports.
Next lets get the audio software set up:
# pacman -S alsa-utils alsa-firmware alsa-lib alsa-plugins # gpasswd -a <your-username> audio $ alsamixer # set the volume to max $ speaker-test # You should hear sound!
# pacman -S pulseaudio pulseaudio-alsa # Or install from the custom build I used above # useradd pulse # gpasswd -a pulse lp # this is needed later # gpasswd -a pulse audio
Now try switching to the newly created pulse and running pulseaudio -v. You can ignore the DBUS warnings. The error about bluez4 also doesn’t matter because we’re using bluez5. Try playing some wav file audio with paplay as a test.
# cp pulseaudio.service /etc/systemd/system/pulseaudio.service # systemctl enable pulseaudio # systemctl start pulseaudio # systemctl status pulseaudio # it should be running
Now install and set up Bluetooth. Check that your Bluetooth adapter shows up in the output from lsusb before proceeding. I had better luck plugging the Bluetooth directly into the RasPi rather than through a hub, so try that.
# pacman -S bluez bluez-libs bluez-utils # gpasswd -a <your-username> lp # gives access to bluetooth  # systemctl enable bluetooth # systemctl start bluetooth # hciconfig hci0 up # hciconfig hci0 class 0x200420 # Pretend to be a car sound system 
 See the policy in /etc/dbus-1/system.d/bluetooth.conf
 Bluetooth Class of Device/Service (CoD) Generator
Make it persistent
We want to enable the bluetooth device on boot as well as set the class persistently even if the bluetooth adapter changes.
# echo > /etc/udev/rules.d/10-bluetooth.rules \ 'ACTION=="add", KERNEL=="hci0", RUN+="/usr/bin/hciconfig hci0 up"'
Also edit /etc/bluetooth/main.conf. You should uncomment “Class” and set it to the same value as above, ‘0x200420‘. I also like to uncomment “Name” and just set it to ‘%h‘.
Pair your device
Follow this process whenever you want to pair a new device with your RasPi.
$ bluetoothctl [bluetooth]# agent KeyboardOnly [bluetooth]# default-agent [bluetooth]# discoverable on [bluetooth]# pairable on
Now scan for the RasPi from your phone or other device and pair with it. You should be able to connect from your phone and stream audio! To allow the device to connect in the future you must use the trust command.
I should simplify this last step, but since I don’t do it often I have not bothered :)
Things to check
The Raspberry Pi uses an SD card for the root file system, this means that your /var/log is quite likely very slow. I would recommend changing /etc/systemd/journald.conf to store log output in memory rather than on the slow flash disk, set Storage=volatile. This means your logs will instead be written to /run/log.
By default pulseaudio will have permission to start threads with realtime priority scheduling. This is needed for glitch-free playback, especially on low-powered hardware like the Raspberry Pi. If you use the systemd unit file I provided above then the LimitRTPRIO and LimitNICE options will be set to allow this. You can use top to make sure pulseaudio is running with these priorities.
Sample rate conversion is CPU-intensive and significantly decreases the audio quality. Most music is distributed in 44.1kHz, so make sure your audio hardware supports this. While playing audio you can inspect /proc/asound/card0/pcm0p/sub0/hw_params to see what sample rate your hardware is using. Pulseaudio will try to configure your hardware to match the sample rate of the incoming audio. If they do not match then something went wrong, or you have cheap USB audio hardware that perhaps only supports 48kHz. In this case you should get better hardware.
I found that if I tried to use my phone too much while playing audio then it would glitch badly. This didn’t happen with my car’s bluetooth setup so I figured it must be something to do with bluez and/or pulseaudio. I fixed it by editing /etc/pulse/daemon.conf and setting:
default-fragments = 10