Headless Bluetooth Audio Setup over SSH (PipeWire / WirePlumber / BlueZ)
This guide addresses the common br-connection-unknown error and missing PulseAudio/PipeWire cards (pactl list cards short returning empty) when connecting Bluetooth audio devices on modern Arch/Manjaro Linux purely over an SSH session.
Problem Context¶
- Headless SSH Limitations:
systemd-loginddoes not assign a physical PAM seat (seat0) to SSH sessions. - WirePlumber Seat Requirement: By default, WirePlumber's Bluetooth monitor waits for an active graphical desktop seat before initializing A2DP/HFP audio endpoints on D-Bus.
- Connection Handshake Failure: Without WirePlumber registering the Audio Sink endpoint with BlueZ (
org.bluez), BlueZ rejects the Bluetooth handshake, throwingorg.bluez.Error.Failed br-connection-unknown.
Step-by-Step Solution¶
1. Disable WirePlumber Seat Monitoring¶
Force WirePlumber to monitor and register Bluetooth audio devices even in headless, seatless SSH environments.
-
Create the WirePlumber user override directory:
-
Create the override configuration file:
-
Add the following lines:
2. Configure D-Bus Permissions for Unprivileged SSH Users¶
Allow the unprivileged user session to send and receive D-Bus signals to/from org.bluez.
-
Create the system D-Bus directory (if missing):
-
Create the custom D-Bus policy file:
-
Paste the following XML policy (replace
1000with your user's UID viaid -uif different):<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "[http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd](http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd)"> <busconfig> <policy user="1000"> <allow send_destination="org.bluez"/> <allow receive_sender="org.bluez"/> </policy> </busconfig> -
Reload D-Bus and restart the Bluetooth service:
3. Configure Shell Environment & Restart Audio Services¶
Ensure your SSH shell environment is bound to the running systemd user bus and PipeWire PulseAudio socket.
-
Add environment exports to your
~/.bashrcfor persistence: -
Enable systemd user service lingering so daemons persist across SSH logons:
-
Restart the PipeWire and WirePlumber user stack:
4. Pair, Trust, and Connect¶
Once WirePlumber initializes the Bluetooth endpoints on D-Bus without waiting for a seat, complete the Bluetooth connection process.
-
Launch
bluetoothctl: -
Execute the setup sequence:
-
Once your device MAC address appears in the logs:
5. Routing Audio & Verification¶
-
Verify that
pactlnow recognizes PipeWire endpoints: -
Set high-quality audio (A2DP Sink) profile and default output sink: