RPiRadio

Been working from home has some advantages like having a radio playing in the background. Unfortunately, I no longer have a classic FM radio, so in the beginning I used my phone or tablet to listen to the online radio, but I didn’t really find it practical. So, during one of the lockdown weekends I decided to do a small project creating a RPi internet radio receiver, thinking it would be quick and easy. Turns out I was a little of on the easy and quick part and it took much more time then I would like to admit to get it working. Apparently running a Music Daemon completely headless using a Bluetooth speaker on a RPi Zero is a little more challenging than one might think.

Before starting the project, I was in the assumption that I just needed a music player (daemon) and a Bluetooth connection. 1+1=2 Right? No not really as Linux comes in layers. Between the Bluetooth daemon and the player is also some an audio server called PulseAudio that acts as a middleware between the Software (MPD) and the hardware (Bluetooth) side. Technically PulseAudio communicates with ASLA and the Bluetooth device is connected to ASLA as a sound card, but we can ignore this as all communication is handled by our audio server.

Normally adding a middleware solution makes things easier, but here is the issue:

The PulseAudio Server runs by default as a per-user daemon and requires some sort user session (SSH, X11, …) to start. While not recommended by the developers of PulseAudio, it is ALSO possible to run it System-wide, but here were it fails. Because it is kind off uncommon to run it system-wide the documentation for it is either outdated or non-existing. The documentation of the developers is a good start but is missing allot of detailed information. So, after the required troubleshooting on my own, I was finally able to make it working.

Requirements

  • RPi Zero with Bluetooth and Wifi (RPi 3/4 will also work I think) 
  • A Bluetooth speaker

Prerequisites

I assume the most basic stuff is already done an you have an RPi Zero running the latest version of Raspbian and some basic tools like e.g. Vim

Installation of the software

Here is the easy part, just a couple of extra packages are required, but it does fill more then 175MB of the storage:

sudo apt --yes install mpd mpc pulseaudio-module-bluetooth

Configuration

Note: all configuration files can be found on my GitHub Repository: https://github.com/BlackC0ffee/RPiRadio

PulseAudio

So as mentioned, we need to configure PulseAdio to run System-wide instead of as per-user . Once done it will run under the user account pulse and we need to get access by adding pi and the root user to the group pulse-access:

sudo gpasswd -a pi pulse-access
sudo gpasswd -a root pulse-access

Next, we need to make sure that pulse audio doesn’t automatic start. We do this by changing the config file /etc/pulse/client.conf and setting the variable autospawn to no:

autospawn = no

Note: see the config file here

Now here is the tricky part where I had some trouble getting it to working. When running PulseAudio in the user space, the file /etc/pulse/default.pa is loaded, when running it system wide, the file /etc/pulse/system.pa is loaded. And this file contains much less modules, including the one used for Bluetooth. So to be able to communicate with Bluetooth the following lines needs to be added to /etc/pulse/system.pa

.ifexists module-bluetooth-policy.so
load-module module-bluetooth-policy
.endif

.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover
.endif

At the same time we need to remove the module load-module module-suspend-on-idle, if not the daemon wil stop itself as soon it has nothing to do.

Note: the complete /etc/pulse/system.pa can be found here.

Next, we need to configure the services. Prior to creating a new service, we first need to disable it:s

sudo systemctl --global disable pulseaudio.service pulseaudio.socket

Then create a new service by creating the file /etc/systemd/system/pulseaudio.service and by adding following information:

# systemd service for pulseaudio running in system mode
# start with: systemctl start pulseaudio.service
# enable on boot: systemctl enable pulseaudio.service
[Unit]
Description=Pulseaudio sound server
After=avahi-daemon.service network.target
 
[Service]
Type=forking
ExecStart=/usr/bin/pulseaudio --realtime --no-cpu-limit --system --disallow-exit --daemonize --log-level=4
KillMode=process
ExecReload=/bin/pkill pulseaudio
Restart=always
 
[Install]
WantedBy=multi-user.target

Note: you can find the full file here

Enable the new service:

systemctl --system enable pulseaudio.service

And at this point I suggest restarting the RPi to make sure that everything starts as expected. Once done, you should see an active pulseaudio service by running the command:

systemctl --system enable pulseaudio.service
It’s alive!!!

A couple of things about this. As you see in the above picture the Active status is “inactive”. This is expected as the main proces is been stopped as soon as it finished. The sub proces (425) needs to be kept alive and this is done with KillMode=process in the pulseaudio.service-file

Bluetooth

Now that we have the pulseaudio.service up and running as a system-wide service, it’s time to connect our Bluetooth speaker to the RPi.

First turn on the Bluetooth speaker and make sure it can be found by other devices. On our RPiRadio, run the command:

sudo bluetoothctl

Then perform a scan using the command:

scan on 

And wait until you see the speaker passing by. In my example I’m using the EU BOOM speaker

Once found, disable the can with the command:

scan off

Next we need to Pair, Trust and Connect to the device using the MAC address:

pair <MAC-Address>
trust <MAC-Address>
connect <MAC-Address>

And that’s it. Next up, the MPD

Music Player Daemon

Before we can play some song, we need to make some small changes to the configuration. The Music Player Daemon (MPD) runs under the user the system user mpd and requires access to the PulseAudio server. To gain access, add the mpd user to the pulse-access group:

sudo gpasswd -a mpd pulse-access

Modify the /etc/mpd.conf file and place the audio_output of the type alsa in comment…

#audio_output {
#	type		"alsa"
#	name		"My ALSA Device"
#	device		"hw:0,0"	# optional
#	mixer_type      "hardware"      # optional
#	mixer_device	"default"	# optional
#	mixer_control	"PCM"		# optional
#	mixer_index	"0"		# optional
#}

… and enable the audio_output of the type pulse

audio_output {
	type		"pulse"
	name		"My Pulse Output"
#	server		"remote_server"		# optional
#	sink		"remote_server_sink"	# optional
}

Note: the final /etc/mpd.conf file can be found here.

Once done, I again advice to restart the RPi to be certain that everything has been loaded as needed.

Now Music Player Daemon, is a music player server, that requires a client to be controlled. There are allot of clients, but for now, let us use the basic one MPC.

First add mp3 song(s) or radio stream(s) to a playlist, then load the play list and finally run play:

mpc add <mp3-stream>
mpc save RadioPlaylist
mpc load RadioPlaylist
mpc play

Once entering the play command, the music should start to play from the Bluetooth speaker if it is connected. Optional you can also use a simple MP3 file to be certain there aren’t any connection issues.

DONE!

Next steps

I’m currently running this setup for a couple of days and it is quite stable. For daily use, I use the android application M.A.L.P.

The only issue I sometimes have, is that the speaker doesn’t connect. In that case I need to open a ssh terminal and connect it using bluetoothctl.

And the idea is also to add an LCD-screen and some controles to have a working radio that doesn’t require any ssh or external clients like M.A.L.P

Part 2…

Troubleshoot tips

PulseAudio verbose

For verbose output from the pulseAudio you can modify the /etc/systemd/system/pulseaudio.service and add -vvvvv to the ExecStart

Check if PulseAudio is detecting and using the correct profile

Sometimes PulseAudio used the incorrect sound profile and this could reduce sound quality. You can check this with the command pacmd, but because PulseAudio is running under a system user, you need to use the following command to access pacmd:

sudo PULSE_RUNTIME_PATH=/var/run/pulse -u pulse pacmd

You can get some details with the command list-cards and select the correct profile with set-card-profile and set-default-sink. More info can be found here. Important: to exit pacmd, push the keyboard-shortcut Ctrl+d. Using the command exit or quit, shutdown the process.

Resources

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.