Paradium the second

13 May 2014

Well, after I got my fabulous Raspberry Pi internet radio working I wanted it to be able to play via A2DP bluetooth from my iPhone as well. How hard can it be? There's plenty of tutorials and tiny little USB bluetooth things out there. Unfortunately, that was wrong. Almost all the tutorials out there have copy and pasted from each other but left important things out. It turned out to be a big hassle. The good thing is, now it does work. Here's few notes about it. I'm not going to copy and paste yet another tutorial but instead focus on the things left out or the ones that didn't work.

Hardware

Of course you're gonna need a bluetooth adapter. There's a list of hardware that supposedly works with Raspberry Pi. There's not that many chips out there and a lot of those dongles are actually the same thing underneath. I have tried the CSL (Cambridge Silicon Radio) and the ASUS. The ASUS worked briefly but then stopped all of a sudden and refused to even show up in the devices list. The CSL almost worked but caused a lot of kernel crashes until I updated the firmware to the "NEXT" branch.

sudo BRANCH=next rpi-update

With that it seemed more stable.

Audio Layer

The biggest buzzkill of the whole thing turned out to be pulseaudio. Basically, you need a piece of software that allows connections from your bluetooth device and outputs the audio data to your Pi's HDMI. To my great dismay, pulse audio appears to be the only thing in the open source world that can do this. Here is a tutorial explaining this in detail. So what's wrong with pulseaudio? Let's just say I won't go into detail. But I sure learned to hate it in just a little time. It's poorly documented, causes a lot of trouble and what's worst in my opinion is the two ways it can operate. It can be in "system mode", which means there's one running pulseaudio daemon for everybody to use. Of course with usual hassle of right restrictions that must be configured somewhere undocumented or, equally bad, you have root do it all. Sounds good? Sort of. However, pulseaudio itself strongly suggests not to do this. Instead, they want to run in "user mode" which will spawn a pulse audio instance for everything that wants to access the audio layer. After trying both extensively I settled for the "user mode". Mostly because the pulseaudio project says they won't answer any bug reports for the other. Think that's unnecessarily complicated? Well, it gets worse.

Apparently, to communicate with its support and config tools, pulse audio needs DBUS. DBUS however is mostly for communication means between X based applications. Do I have that on my headless Pi radio? Of course not. So pulseaudio was spamming fatal errors all over my logs because it didn't have DBUS and I couldn't start DBUS because I didn't even have X.

There's a little "fake" X Server for similar purposes. Xvfb. It can be run with very little overhead, just to allow DBUS to start and so pulseaudio will shut up with it's error messages.

And so on and so forth.... As I said, pulseaudio is quite something.

Instructions here about setting pulse to play A2DP are indeed accurate.

But since we are aiming for optimum audio quality we're changin the entry in /etc/pulse/daemon.conf. Instead of

resample-method = trivial

We are using

resample-method = speex-fixed-3

It yields better quality while still being reasonable on the Pi's CPU.

Also, for consistency's sake, we are setting up MPD, our daemon that plays the radio, to output to pulse as well. This goes in /etc/mpd.conf, replacing the original ALSA output.

audio_output {
  type  "pulse"
  name  "MPD PulseAudio Output"
}

Bluez

Setup of the actual bluetooth system is not as hard and didn't cause a lot of hassle. This should get you right to the point that you can connect with your device.

Loopback

After your device is connected and playing, you need to tell pulseaudio to take that input and loop it right back into the default sink. This is called a loopback module and it needs to be loaded after the connection is established.

pactl load-module module-loopback source=bluez_source.xx_xx_xx_xx_xx_xx rate=44100 adjust_time=0

The xxxx things are the MAC of your actual bluetooth input.

pactl list short

will show you the input once the connection is done. After loading the module, output should play. This is where I ran into the next problem. Once the music plays (Hooray!!) it will stop after a while (Oooohhh...). Took me ages to figure out why. Thanks to gwenbeth who posted here I learned that the loopback device is default set to stop and unload after it has been idle for 20 seconds. But it isn't idle! Well, I refer to my pulseaudio rant for that. You can adjust the behavior in /etc/pulse/daemon.conf with

exit-idle-time = -1

Automatic play

To be useful in standalone usage, you need to autoload the loopback module after your device connects. I have put scripts and udev rules for that on my repository Look at the scripts in udev and scripts and see what deploy.sh does to them. Once you copy them to the appropriate locations you're all set with your bluetooth receiver. It works fine here.

So what's next?

Well, just recently I made another one of those radios and gave it to a friend for his birthday. Seeing people respond to it is interesting. Certainly, usability is not exactly great. Especially when it comes to setup. You need to manually edit a file on the SD card in order to enter your wifi credentials. Another painpoint is the fact that right now it requires to power sources that can't be switched together. Also, sometimes it has quirks and things don't work as expected. It won't boot or not shutdown and whatever. And the user doesn't even see something is wrong. So all in all, it needs to be more stable.

About distributing this, at some point it will be a SD image. But is that really such a great idea? Wouldn't it be better to have some sort of a package system that allows you to install on a regular Raspbian and that does all the modifications for you? Will people bother? Lots of questions that needs answering. See you next time!