Automatically disabling noise cancelling on Bose QC35 headphones
I have had a pair of Bose QC35 headphones since 2017.
One thing annoys me is that when bluetooth is turned on, noise cancellation is automatically set to 'high'.
Newer Bose models have a physical button to disable noise cancellation, but mine does not.
The Bose mobile app seems to be the official solution, but it takes a few seconds to start, enough for me to feel mildly offended and look for an alternate solution.
Read the "A Linux solution" sectionA Linux solution
Here's what I wanted: every time my headphones connect to my computer, noise cancellation is set to 'off'.
To achieve that, we need to:
- Know that the headphones just connected over bluetooth.
- Tell them to set noise-cancelling to 'off'.
Part 2 is basically 'reverse-engineering' the Bose mobile app and build software that works on Linux. Fortunately, someone already did that 🙏🙏.
I installed their software and verified that I could disable noise-cancelling by running /usr/local/bin/based-connect --noise-cancelling=off [MAC address of headphones]
.
The MAC address can be obtained from bluetoothctl info
when the device is connected.
Now we need to know when the headphones connect, and run the script automatically. This can be done with a combination of udev rules and a systemd service on Linux.
Read the "Listening to bluetooth connection events with udev" sectionListening to bluetooth connection events with udev
udev is a device manager for Linux. From the man page, I got that it is a layer on top of the kernel, it gives usable names to devices, and lets us subscribe to device events.
Writing the actual udev rule was a bit tricky.
I got some semblance of a feedback loop using the following workflow (requires a live device):
-
Run
udevadm monitor --property
in one terminal to see udev events as they occur. -
Test the rule matching with:
udevadm test --action=add /devices/virtual/input/input71
The path to the device comes from watching udevadm monitor --property
when the headphones connect.
-
A helpful debugging rule (credits to someone on some internet forum).
# A lot can go wrong and cause a rule to not match/script to silently not run. Starting with something that works is helpful. ACTION=="add", SUBSYSTEM=="input", RUN+="/bin/sh -c 'echo == >> /tmp/udev-env.txt; env >> /tmp/udev-env.txt'"
Initially, I tried to make the udev rule run the script setting noise-cancelling with RUN+="path-to-my-script"
. It did not work because, for security reasons that I am not familiar with, udev scripts run inside a sandbox and cannot access the network.
A workaround is to create a systemd service to run the script. The udev rule triggers the service.
Read the "Putting things together" sectionPutting things together
Here's the complete setup:
/etc/systemd/system/custom-bose-noise-canceling-off.service
# this is meant to be triggered by a udev rule (on bluetooth connection)
[Unit]
Description=Set noise canceling to 'off' on Bose QC35
[Service]
Type=simple
ExecStart=/home/laurent/programming/scripts/bose/nc_off
User=laurent
/usr/lib/udev/rules.d/99-custom-bose-bluetooth.rules
ACTION=="add", SUBSYSTEM=="input", ENV{PRODUCT}=="1/1e/111c/111", TAG+="systemd", ENV{SYSTEMD_WANTS}="custom-bose-noise-canceling-off.service"
The ENV{PRODUCT}
value can be obtained by looking at the output of udevadm monitor --property
.
/home/laurent/programming/scripts/bose/nc_off
#!/bin/bash
# sleeping because bluetooth might not be ready just yet when this runs
# there is probably a better way !
# the systemd service could probably be made to wait on some other event.
sleep 5
/usr/local/bin/based-connect --noise-cancelling=off <device mac address>
Exploring udev
was interesting, and now I don't have to open the Bose app.
Also, it is a small daily reward to hear noise-cancelling turn off automatically 🥳.
Read the "On Android" sectionOn Android
If you know of a good solution please let me know!
At the moment I use a third-party 'Serial Bluetooth Terminal' app (that I had been using for other purposes) to send 0x0106020100
to the headphones, turning noise-cancelling off.
It's faster than the Bose app but I'm still required to go and click it.
Read the "Some resources I used" sectionSome resources I used
- https://unix.stackexchange.com/questions/476094/run-a-script-when-bluetooth-device-is-connected
- https://reactivated.net/writing_udev_rules.html. A bit outdated -
udevadm
replaced many of the commands listed there - but still useful. - The bytes required to set noise-cancelling to "off" can be found in the codebase of the Linux tool.