Bluetooth earbud play-pause fix
Bluetooth earbud play/pause fix (Bose QC Ultra II)
Ubuntu (GNOME, X11, PipeWire + BlueZ). Tapping the earbud to play/pause didn't work, while next/prev did. Refined symptom: pause works, resume (play) never does. Works fine on phone/other OSes.
1 Root cause
On every tap the earbuds emit AVRCP PAUSE — they never send PLAY. They decide PLAY vs PAUSE from the playback status the source reports back to them; this PC never reports "paused," so the earbuds assume "playing" forever and always send PAUSE. Phone reports state correctly, so the toggle works there.
Confirmed at the key level: the AVRCP input device "Escape Pods (AVRCP)" emits
KEY_PAUSECD (code 201) on every tap, never KEY_PLAYPAUSE. gsd-media-keys
turns that into an MPRIS Pause call — so pause works, resume can't.
2 Fix
Remap that one key (KEY_PAUSECD → KEY_PLAYPAUSE), scoped to only the earbud
device, using xremap. gsd then issues a proper PlayPause toggle against
the player's real state, which the desktop knows correctly.
(Note: mpris-proxy — /usr/lib/bluetooth/mpris-proxy as a user service — was
an earlier partial fix and is still installed; it gets "pause" working but not
resume. The xremap remap below is what actually fixes resume.)
2.1 Install xremap
# 1. Download the prebuilt X11 binary (check for newer release)
cd /tmp
curl -fsSL -o xremap-x11.zip \
https://github.com/xremap/xremap/releases/latest/download/xremap-linux-x86_64-x11.zip
unzip -o xremap-x11.zip
chmod +x xremap
# 2. Config: /etc/xremap/config.yml
sudo mkdir -p /etc/xremap
sudo tee /etc/xremap/config.yml >/dev/null <<'EOF'
modmap:
- name: earbuds-playpause
device:
only: ["Escape Pods (AVRCP)"]
remap:
KEY_PAUSECD: KEY_PLAYPAUSE
EOF
# 3. Install binary + root systemd service
sudo install -m755 /tmp/xremap /usr/local/bin/xremap
sudo tee /etc/systemd/system/xremap.service >/dev/null <<'EOF'
[Unit]
Description=xremap - remap Bose earbud play/pause key to a real toggle
After=bluetooth.target
[Service]
Type=simple
# --device scopes the grab to ONLY the earbuds (leaves the keyboard alone).
# --watch=device re-grabs automatically when the earbuds reconnect.
ExecStart=/usr/local/bin/xremap --watch=device --device "Escape Pods (AVRCP)" /etc/xremap/config.yml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now xremap.service
sudo systemctl status xremap.service --no-pager
Then play something in Spotify and tap the earbud — it should toggle.
1 Notes / gotchas
- Must run privileged:
/dev/input/event*isroot:inputand xremap also needs/dev/uinput. Running as a root system service is simplest. - Always pass
--device "Escape Pods (AVRCP)"— without it xremap grabs all keyboards (it grabbed the Keychron in testing). - If the earbud device name ever changes, update it in both the service
--deviceflag and the configdevice.only.
2 How the diagnosis was done (reusable)
Find the AVRCP input device:
grep -iA5 "AVRCP" /proc/bus/input/devices # -> Name + event number
See what key a tap actually emits (no extra packages needed; needs sudo because
the device is root:input). Save as /tmp/readkey.py:
#!/usr/bin/env python3
import struct, select, time
FMT="llHHi"; SZ=struct.calcsize(FMT)
NAMES={119:"KEY_PAUSE",163:"KEY_NEXTSONG",164:"KEY_PLAYPAUSE",165:"KEY_PREVIOUSSONG",
201:"KEY_PAUSECD",200:"KEY_PLAYCD",207:"KEY_PLAY"}
dev="/dev/input/event25" # adjust to the AVRCP event number
with open(dev,"rb") as f:
end=time.time()+8
while time.time()<end:
r,_,_=select.select([f],[],[],0.5)
if not r: continue
t,c,v=struct.unpack(FMT,f.read(SZ))[2:]
if t==4 and c==4: print(f" scancode: 0x{v&0xffffffff:x}")
if t==1 and v==1: print(f" pressed: code={c} {NAMES.get(c,'???')}")
Run sudo python3 /tmp/readkey.py and tap. (No MSC_SCAN scancode line means a
native udev hwdb remap won't work — hence xremap.)
See what reaches MPRIS while tapping:
dbus-monitor --session "interface='org.mpris.MediaPlayer2.Player'"
