I've had a hard time bringing bluetooth to work on a Raspberry Pi 5 with Ubuntu 24.04 using Pipewire as audio backend. Maybe you run into the same situation and find this helpful.
With the common tutorials on how to enable a bluetooth speaker connection on Ubuntu, there were the following problems for my combination of Ubuntu 24.04 on a Raspberry Pi 5 and using PipeWire (as of July 2024):
- either the audio quality was fine but the connection automatically disconnects after a few seconds
- or the connection does not disconnect, but the audio begins to stutter extremely after 60 to 90 seconds of audio played
Since Ubuntu 22.10, PipeWire is the default soundserver on Ubuntu, so trying to use Bluetooth with PulseAudio as soundserver would mean to uninstall the recommended default and reconfigure the system. So PipeWire it is!
After trying a lot of different stuff, the solution contains:
- setup PipeWire correctly
- compiling / installing a current version of bluez
- setting the correct bluetooth parameters
This gist is based on (Debian Wiki)[https://wiki.debian.org/PipeWire#Debian_12] and inspired by this gist for Bluetooth on Ubuntu 22.04
WirePlumber as session manager:
# Install WirePlumber as session manager while removing pipewire-media-sessions as the old session manager
sudo apt install wireplumber pipewire-media-session-
# Enable WirePlumber in "systemd" (running as user, not as root)
systemctl --user --now enable wireplumber.service
Setting up Alsa and PipeWire as substitute for PulseAudio
# Configure PipeWire to activate its PulseAudio replacement daemon
# Configure PipeWire to activate its ALSA Plugin
# Also install pulseaudio and alsa utils
sudo apt install pipewire-pulse pipewire-alsa pulseaudio-utils alsa-utils
# Reboot and check, if pipewire-pulse is working correctly
sudo reboot now
# This should return something like:
# "Server Name: PulseAudio (on PipeWire 1.X.XX)"
LANG=C pactl info | grep '^Server Name'
# Minimum requirement for bluetooth
sudo apt install libspa-0.2-bluetooth
# If still installed, remove pulseaudio-module-bluetooth
sudo apt remove pulseaudio-module-bluetooth
We need to install bluez
either by source or taking the available apt version.
sudo apt install bluez
If this version is working, you're fine! At the time of writing, I had to install a newer version of bluez (upgrading from apt version 5.72 to 5.77)
Installation instructions taken from https://www.makeuseof.com/install-bluez-latest-version-on-ubuntu/
# If you have an old version installed, remove it first
sudo apt autoremove bluez
# Install necessary build packages
sudo apt install build-essential libreadline-dev libical-dev libdbus-1-dev libudev-dev libglib2.0-dev python3-docutils
# Set the current bluez version
# Check https://github.com/bluez/bluez/releases for the most recent version
BLUEZ_VERSION=5.77
wget http://www.kernel.org/pub/linux/bluetooth/bluez-$BLUEZ_VERSION.tar.xz
# Download, unzip, build and install the bluez version
tar -xf bluez-$BLUEZ_VERSION.tar.xz && cd bluez-$BLUEZ_VERSION
./configure
make
sudo make install
For me, this new version of bluez also solved a extremely verbous console output when being inside the bluetoothctl
terminal.
If you have compiled a newer version of bluez, allowing experimental features might help.
# Modify /lib/systemd/system/bluetooth.service, e.g. with nano
sudo nano /lib/systemd/system/bluetooth.service
# Search for the ExecStart line and add a "--experimental" at the end, so that you have the following:
# ExecStart=/usr/local/libexec/bluetooth/bluetoothd --experimental
Set the correct controller mode:
# Modify /etc/bluetooth/main.cfg
sudo nano /etc/bluetooth/main.cfg
# Uncomment / set both lines:
# Name = BlueZ
# ControllerMode = dual
Restart bluetooth / your system
sudo systemctl restart bluetooth
# or sudo reboot now
Sources for the bluetooth config:
These are the common bluetoothctl commands to find and connect to your device:
bluetoothctl power on
bluetoothctl agent on
bluetoothctl discoverable on
bluetoothctl pairable on
bluetoothctl scan on
bluetoothctl trust DEVICE:MAC
bluetoothctl pair DEVICE:MAC
bluetoothctl connect DEVICE:MAC
sudo rfkill list
# If bluetooth is marked as blocked, run:
sudo rfkill unblock all
# Check the status of bluetooth, there should be something like "running" / "active"
systemctl status bluetooth
# If not, start bluetooth with one of the following
systemctl start bluetooth
bluetoothctl power on
# You can also check and unblock again
rfkill unblock all
Based on https://wiki.debian.org/PipeWire
PipeWire's lower latency compared to PulseAudio can lead to choppy audio on systems with high load.
First view the quantum using the pw-top
command and then increase the quantum value using this command, until the audio becomes smoother.
# Call this while playling audio.
# Experiment with different quantum values.
pw-metadata -n settings 0 clock.force-quantum 2048
Once you find the right quantum value for your situation, you can make the value permanent by creating a config file ~/.config/pipewire/pipewire.conf.d/choppy-under-load.conf
with the following content and restart pipewire related daemons.
context.properties = {
default.clock.quantum = 2048
default.clock.min-quantum = 2048
}
Based on this gist for Ubuntu 22.
Find necessary info about the bluetooth device (while it is connected!)
pactl list | grep -Pzo '.*bluez_card(.*\n)*'
The output should be something like
Name: bluez_card.28_11_A5_84_B6_F9
Driver: module-bluez5-device.c
...
Ports:
speaker-output: Speaker (priority: 0, latency offset: 0 usec, available)
Part of profile(s): a2dp_sink, headset_head_unit
speaker-input: Bluetooth Input (priority: 0, latency offset: 0 usec, not available)
Part of profile(s): headset_head_unit
We see that the buffers have currently 0 latency. In the next step, you will need the NAME and PORT of your output. In this example, these are bluez_card.28_11_A5_84_B6_F9 and speaker-output, respectively.
Set the buffer size (latency) of your card to a suitable value with this command pattern:
pactl set-port-latency-offset <NAME> <PORT> <BUFFER_SIZE_MICROSECONDS>
The latency unit of the following command is microseconds, so I'm using a 50 millisecond buffer for my command here:
pactl set-port-latency-offset bluez_card.28_11_A5_84_B6_F9 speaker-output 50000
Restart your bluetooth service to apply your change
sudo service bluetooth restart
As there is usually no documentation about this, you may have to experiment with higher or lower buffer values. Many people people posted their working latencies in the comments to this answer. Check them out for guidance on the latency value.