Disable Sony noise-cancellation on Linux

3 minute read

I really like my Sony 1000XM3 headphones. They are super comfortable to wear and pack away compactly when I’m travelling.

I have always hated one feature though: the headphones always start with noise-cancelling (NC) enabled. This default setting irritates me because it means I have to charge my headphones more often. In addition, I’ve also had ear fatigue when I use NC for too long. [0]

Sony provides no way to change this default (they would rather add gamification to their mobile app). After a late evening session with lots of tea for company, I finally figured out a setup to disable NC that works on Linux. It uses a combination of a Python script, udev and systemd to send a magic payload over bluetooth right after the headset is connected.

Step 1: Setup the Python script

The magic payload is sent using a Python script, using the pybluez module. There’s an issue though: newer versions of Python do not work with the old release of pybluez on PyPI. I ended up installing the Python package from Github:

mkdir /home/gagan/projects/disable-nc-sony/
cd /home/gagan/projects/disable-nc-sony/
mkvirtualenv disable-nc-sony
pip install git+https://github.com/pybluez/pybluez

Next, create the Python script (disable-nc-sony.py) to send the payload. Change the

  • shebang, point it to the correct Python executable
  • the MAC address for the bluetooth headset.
"""Toggle noise cancellation on Sony 1000xm3 headphones"""

import sys
import bluetooth

addr = "AA:AA:AA:AA:AA:AA"  # Change me

# Values pulled from this project
# https://github.com/Plutoberth/SonyHeadphonesClient
data = bytearray([62, 12, 0, 0, 0, 0, 8, 104, 2, 0, 1, 0, 1, 0, 255, 127, 60])  # disable NC payload
# data = bytearray([62, 12, 1, 0, 0, 0, 8, 104, 2, 17, 1, 2, 1, 0, 0, 148, 60])  # enable NC payload

uuid = "96CC203E-5068-46ad-B32D-E316F5E069BA"
#print("Searching for service on {}...".format(addr))

service_matches = bluetooth.find_service(uuid=uuid, address=addr)

if len(service_matches) == 0:
    print("Couldn't find the service.")

first_match = service_matches[0]
port, name, host = first_match["port"], first_match["name"], first_match["host"]

# print('Connecting to "{}" on {}'.format(name, host))

sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((host, port))

Make sure the make this script executable (this is important in the following steps):

chmod +x disable-nc-sony.py

If things were done correctly, running this script will disable NC on a connected headset.

Step 2: Setup systemd service

The next step is to trigger this script automatically when the headset is connected. This is where I ran into trouble. Normally, udev is sufficient to trigger commands. This didn’t work for me which I later pinned down to the sandbox udev runs in, and the sandbox blocks network communication. The solution is to trigger a systemd service from udev, which is not restricted.

Create a file /etc/systemd/system/sony-bluetooth-nc.service


Step 3: Setup udev rule

Create a file /etc/udev/rules.d/90-sony-bluetooth-headphones.rules

ACTION=="add", SUBSYSTEM=="input",ATTRS{id/vendor}=="054c",ATTRS{id/product}=="0cd3",TAG+="systemd", ENV{SYSTEMD_WANTS}+="sony-bluetooth-nc.service"

Run sudo systemctl daemon-reload and sudo udevadm control --reload to reload configuration.

That’s it. When I connect my headphones, NC is disabled right away within a couple of seconds.


Some useful commands for debugging:

  • Listen and monitor devices, useful for configuring udev rules udevadm monitor --property
  • Set udev to debug logging mode sudo udevadm control --log-priority=debug (Use journalctl -f to view logs).
  • Print device params (device path is from udevadm monitor) udevadm info --attribute-walk --path=PATH
  • systemctl service status sudo systemctl status sony-bluetooth-nc

[0] From my limited online research, there are no long term effects of using headphones with active NC for long periods. But I had some and they went away when I stopped using NC.