PipeWire is a multimedia server, best known for it’s video support in Wayland. It also provides an audio server which can replace PulseAudio. The appeal, for me at least, to switch over from PulseAudio to PipeWire stems from PipeWire’s better support of bluetooth audio, and especially support for modern A2DP codecs such as AptX, AptX HD and LDAC.
Starting with PipeWire 0.3.20 introduced native mSBC support. This profile support mSBC codec versus CSVD supported by the older HSP/HFP profiles. The difference is significant, as the CSVD only supported narrow band speech (NBS, 8kHz) compared with mSBC support for wide band speech (WBS, 16kHz). That is the difference between 90’s era call quality sound and modern call quality sound.
Update: PipeWire-0.3.30 made the replacement process simpler. See my updated post.
Installing PipeWire 0.3.23
As of writing this post, Debian Unstable only has PipeWire 0.3.19. We are going to install PipeWire from the experimental repo so we get the PipeWire 0.3.23 with the support for mSBC.
We start by enabling the experimental repo
$ sudo apt-add-repository "deb http://deb.debian.org/debian experimental main
$ sudo apt update
Install PipeWire from experimental:
$ sudo apt install -t experimental pipewire-audio-client-libraries libspa-0.2-bluetooth
(pipewire-audio-client-libraries
will pull pipewire
itself as a dependency)
Substituting PipeWire for PulseAudio
These instructions are based on the ones from Debian Wiki, Arch Wiki and Gentoo Wiki.
Create the file
$ sudo touch /etc/pipewire/media-session.d/with-pulseaudio
It will instruct PipeWire to handle Bluetooth audio devices.
Copy the pipewire-pulse
systemd service:
$ sudo cp /usr/share/doc/pipewire/examples/systemd/user/pipewire-pulse.{service,socket} /etc/systemd/user
Disable PulseAudio services and enable the PipeWire ones
$ systemctl --user disable pulseaudio.socket pulseaudio.service
$ systemctl --user stop pulseaudio.socket pulseaudio.service
$ systemctl --user enable pipewire pipewire-pulse
$ systemctl --user start pipewire pipewire-pulse
If everything worked well pactl info
should report Server Name: PulseAudio (on PipeWire 0.3.23)
:
$ pactl info | grep "Server Name"
Server Name: PulseAudio (on PipeWire 0.3.23)
If not, you might need to restart (PulseAudio tends to be rather persistent). In case PulseAudio still doesn’t play nicely, you should mask it:
$ systemctl --user mask pulseaudio.service pulseaudio.socket
$ systemctl --user stop pulseaudio.service pulseaudio.socket
Removing PulseAudio completely is not a good move at this point in time. Some packages depend on it, although they could work with PipeWire just as well. For example, when I remvoed PipeWire libcanberra-pulse
got removed as well which caused system notification sounds to break. Alternatively you could try to replace the PulseAudio package with a dummy using equivs
but that seems like more effort than keeping the package.
Enabling mSBC and SBC XQ
Edit /etc/pipewire/media-session.d/bluez-monitor.conf
and uncomment the following lines:
bluez5.msbc-support = true
bluez5.sbc-xq-support = true
This will enable both mSBC and SBC XQ.
You can test that you’re headset is connected via mSBC using pw-cli info
:
$ guyru@gdebian3:~$ pw-cli info all | grep bluez
info: unsupported type PipeWire:Interface:Profiler
info: unsupported type PipeWire:Interface:Metadata
info: unsupported type PipeWire:Interface:Metadata
* device.api = "bluez5"
* device.name = "bluez_card.94_DB_56_AC_36_52"
* api.bluez5.path = "/org/bluez/hci0/dev_94_DB_56_AC_36_52"
* api.bluez5.address = "94:DB:56:AC:36:52"
* api.bluez5.device = ""
* api.bluez5.class = "0x240404"
* api.bluez5.transport = ""
* api.bluez5.profile = "headset-head-unit"
* api.bluez5.codec = "mSBC"
* api.bluez5.address = "94:DB:56:AC:36:52"
* node.name = "bluez_input.94_DB_56_AC_36_52.headset-head-unit"
* factory.name = "api.bluez5.sco.source"
* device.api = "bluez5"
* api.bluez5.transport = ""
* api.bluez5.profile = "headset-head-unit"
* api.bluez5.codec = "mSBC"
* api.bluez5.address = "94:DB:56:AC:36:52"
* node.name = "bluez_output.94_DB_56_AC_36_52.headset-head-unit"
* factory.name = "api.bluez5.sco.sink"
* device.api = "bluez5"
In case mSBC is not supported you’ll see api.bluez5.codec = "CSVD"
(and you’lll probably hear the difference).
Errors
Problem: Connecting to bluetooth headset fails, and the following error appears in journalctl
:
bluetoothd[41893]: src/service.c:btd_service_connect() a2dp-sink profile connect failed for 94:DB:56:AC:36:52: Protocol not available
Solution: You’re missing the libspa-0.2-bluetooth
package. Install it and restart PipeWire:
$ sudo apt install -t experimental libspa-0.2-bluetooth
$ systemctl --user restart pipewire pipewire-pulse
Problem: ALSA programs fail with the following error:
ALSA lib pcm_dmix.c:1075:(snd_pcm_dmix_open) unable to open slave
aplay: main:830: audio open error: Device or resource busy
Solution: You need to enable the ALSA backend for PipeWire:
$ sudo touch /etc/pipewire/media-session.d/with-alsa
$ systemctl --user restart pipewire pipewire-pulse