Skip to content

Instantly share code, notes, and snippets.

@Tobiaqs
Last active January 21, 2021 11:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tobiaqs/0ef7bd2e56160650264f9b77de2db50f to your computer and use it in GitHub Desktop.
Save Tobiaqs/0ef7bd2e56160650264f9b77de2db50f to your computer and use it in GitHub Desktop.
Turning your Raspberry Pi into a Bluetooth audio receiver (Nov 2020)

Turning your Raspberry Pi system into a Bluetooth audio receiver

with the "latest" versions of pulseaudio 12.2 and bluez/bluetoothd 5.50 in Nov 2020 in Raspbian repos

guide updated on Nov 23, 2020

There are tons of guides online that show you how to use your Raspberry Pi as a Bluetooth audio receiver. Unfortunately, at time of writing, none of them seem to work, and contain unnecessary (unexplained) steps or settings that don't really add anything useful.

If you haven't followed any guides yet, skip to the TRUTHS part. If you have, the LIES part may clarify some things for you.

LIES

Before doing some deep diving myself, I tried using these guides to get the result I wanted.

I found them to be so confusing. They may have been written for older versions of pulseaudio and/or bluez, but anyway, they contain a lot of information that is incorrect with current versions.

You need a script that creates a pulseaudio sink for all of your bluetooth connections and removes them afterwards

I don't use any script and it works just fine. The modules for pulseaudio that talk to bluez deal with this stuff. I don't need my Pi to be discoverable, I just want to pair my phone and be done with it.

You need to set a Class in /etc/bluetooth/main.conf

The Class is set automatically when pulseaudio connects to bluetoothd over dbus, no need to set it

You need to enable some services in /etc/bluetooth/audio.conf

This file is completely ignored by bluetoothd as you can check with strace

You need to change the resample-method in /etc/pulse/daemon.conf to trivial

I don't see why. It works fine without changing the resampling method

lp is the pulseaudio group

The lp group is for printer services. So that's nonsense. In older versions of bluez' dbus policy file bluetooth.conf, the lp group would have permission to talk to bluez out of the box, so I guess that's why they wanted you to add the pi user to it (bluetoothctl access without sudo)

You need a specific bluetooth alsa package

Not true. I didn't install anything and all worked fine

TRUTHS

Here are some things that are true. From top to bottom you can also read this as a step-by-step guide. Assuming you already have bluez and pulseaudio installed and working.

  1. You need to install the pulseaudio bluetooth module

You need the pulseaudio-module-bluetooth package that comes with module-bluetooth-policy and module-bluetooth-discover. Find it in your distro's package manager.

  1. Pulseaudio needs permission to talk to bluez over dbus

These permissions are handled in /etc/dbus-1/system.d/bluetooth.conf. It ships with bluez by default. Without a policy file pulseaudio will not be allowed to talk to bluez over dbus. My bluez package came shipped with a bluetooth.conf file that is not equal to the one currently in the bluez git repository, and did not work. I took the most recent file from the bluez git repository - which is also the file that will be shipped with new versions of dbus. It worked without any modifications. Be sure to do a reboot after changing this file cuz just restarting dbus can cause some programs to crash.

https://git.kernel.org/pub/scm/bluetooth/bluez.git/plain/src/bluetooth.conf?id=35a2c50437cca4d26ac6537ce3a964bb509c9b62

  1. You need to create a systemd service file for pulseaudio

Pulseaudio is not meant to be run as a service (but we're gonna do it anyway) so create a file over at /etc/systemd/system/pulseaudio.service and add this:

[Unit]
Description=PulseAudio Daemon
After=bluetooth.service

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit --disable-shm

I found this template somewhere online and works well. I did add After=bluetooth.service to make sure pulseaudio and bluez start in order to prevent potential conflicts.

  1. You need to configure pulseaudio

In /etc/pulse/system.pa, add the following to the bottom.

load-module module-bluetooth-policy
load-module module-bluetooth-discover headset=native

PulseAudio supports HFP which allows mobile telephony devices to be represented as a modem. We don't want this functionality to be enabled as it can cause some issues and we simply don't need it. Hence we disable it using the headset=native option on the module-bluetooth-discover module.

Assuming your bluetooth service is already enabled and started, we now enable and start our pulseaudio service.

# systemctl enable pulseaudio
# systemctl start pulseaudio

Now we run bluetoothctl and check whether everything looks good.

# bluetoothctl
  show
> ...
> UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
> ...

Now pair and trust the devices you want to stream from using bluetoothctl. Upon connection the audio streaming will work straight away.

TIPS & TRICKS

Segmentation fault on armv6 or DBUS related error

If you are - like me - using the native-protocol-tcp pulseaudio module to allow for streaming from linux pcs in conjunction with the zeroconf-publish module, and you're getting segfaults when starting pulseaudio: change your .pa to first load the native-protocol-tcp module, then load the bluetooth modules, and finally load the zeroconf-publish module. First loading the network related modules and then the bluetooth modules may result in a pulseaudio segfault on armv6 processors like the rpi b.

Another problem you may encounter is this error:

Assertion 'pa_shared_set(c, name, pconn) >= 0' failed at pulsecore/dbus-shared.c:48, function dbus_connection_new(). Aborting.

Again, solve this by loading the zeroconf-publish module at the bottom of your .pa.

Volume control on phone not working properly

There is a bluez plugin that seems to mess this up from time to time. The solution: open up /lib/systemd/system/bluetooth.service and add --noplugin=avrcp to the ExecStart command. Then run systemctl daemon-reload followed by systemctl restart bluetooth. That should fix it. Source: https://unix.stackexchange.com/a/515348

Script

I wrote a script that does a lot of the things discussed here automatically, assuming a mint raspbian install:

https://gist.github.com/Tobiaqs/62cbb28cf64836ba7681da35b1fe50ef

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment