I recently got active noise-cancelling headphones (Sony WH-1000MX4). They work just fine with my Android phone but on my Linux notebook I had a bit of a fight to get them working. I am running Arch Linux on most of my machines, so this post is written with Arch specific commands, but most of them (and the general idea) should also work on Ubuntu or Debian based distros. Keep in mind that older versions of PulseAudio and/or PipeWire may not have the features described here! So lets get started with the things I tried (if you are not interested in these just jump to [PipeWire]({{< relref "linux-and-bluetooth.md#pipewire" >}} "link to PipeWire")).
Failed experiments
At first we have to install the bluez
and bluez-utils
packages. bluez-utils
will provide bluetoothctl
to interact via CLI with bluez
. As I want to avoid unnecessary sources of error I'm not going for a graphical helper for now.
All of this is (as always) documented in the arch wiki. The following is more or less exactly what can be found there.
- Start the Bluetooth service with
systemctl start bluetooth.service
- Open
bluetoothctl
- Power on the Bluetooth module with
power on
- Scan for devices with
scan on
- Wait for the headphones to show up. In my case they did not, so I got the Bluetooth MAC from my phone.
- Pair the headphones with
pair <MAC>
- Connect the headphones with
connect <MAC>
Until now everything was working as expected, but now the struggling started. As I played some music the sound was just bad. Therefore I checked the configuration in pavucontrol
and saw that the select profile was HSP/HDF
. This is also documented in the Arch wiki. After a bit of research I now know that I want to use the A2DP
profile for crispy audio output, but the internal microphone will only work with HSP/HDF
. As my notebook got a decent internal microphone and I also got an external one this is no problem for my use case. But keep this in mind if you need the internal mic of the Sony WH-1000MX4 or any other Bluetooth headphones.
I tried a few more things mentioned in the troubleshooting guide like:
# /etc/pulse/default.pa
# Let me use l2dp via bluetooth
load-module module-bluetooth-policy auto_switch=false
# /etc/bluetooth/main.conf
[General]
Disable=Headset
MultiProfile=multiple
But none of them worked, and the sound was still just bad. So I did some research about how all of these Bluetooth stuff actually works and discovered that the Sony WH-1000MX4 are using the LDAC
codec which is not supported by vanilla pulseaudio. An alternative is APTx
which may be supported by most other headphones, as LDAC
is a proprietary Sony codec. Also, you want to use a A2DP
sink instead of HSP/HDF
(mind the earlier described disadvantage of not working microphones!). Therefore, it's time to revisit the Arch wiki and search for this specific codec.
Migration to PipeWire
At this point I discovered a pulseaudio module that adds support for APTx
and LDAC
codecs. But it was deprecated in January 2021 with a recommendation to use vanilla PulseAudio or PipeWire. I already tried PulseAudio earlier (and was annoyed) so I decided to give PipeWire a chance. And PipeWire supports LDAC since release 0.3.19
🎉!
- Many bluetooth improvements in LDAC, AptX-HD. AAC was also added. Headsets should work better now. -- https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/NEWS/
There are 3 packages needed to get started:
libldac
,pipewire
andpipewire-pulse
. Install them withpacman -S libldac pipewire pipewire-pulse
.After that reboot your machine and connect the headphones with
bluetoothctl
as described earlier. I had to remove the headphones withremove <MAC>
and pair them again. Now there should be theA2DP
option inpavucontrol
and theLDAC
codec.If you want to learn more about PipeWire (and its history) there is a recently published article on LWN.net.
Getting the touch gestures to work
Thanks to Marcelo for pointing this out!
As always this was already documented in the arch wiki. Simply create a new systemd user unit:
~/.config/systemd/user/mpris-proxy.service [Unit] Description=Forward bluetooth media controls to MPRIS [Service] Type=simple ExecStart=/usr/bin/mpris-proxy [Install] WantedBy=default.target
Reload all units with
systemd --user daemon-reload
and enable the unit withsystemctl --user enable --now mpris-proxy
. Now all touch gestures and thewearing detection
should work!Conclusion
As I thought about getting Bluetooth headphones I have not given a thought that Bluetooth (with modern codecs) could be problematic on Linux. Especially as Sony decided to use their own
LDAC
codec instead of something open (but I'm not even sure if there is an open Bluetooth codec).So far I had no problems with PipeWire, but I am only running it for a few weeks now, so we will see how it holds up. Keep in mind that PipeWire is not stable yet! There might be updates that require configuration changes (like this one).