Skip to content

About

Make Bluetooth headsets sound good on Linux — and keep them that way.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

headset-mode

Make Bluetooth headsets sound good on Linux — and keep them that way.

The problem

Classic Bluetooth cannot do Hi-Fi stereo and microphone at the same time — on any OS. The moment an app opens the mic, the headset silently drops from A2DP stereo to the HFP telephone profile (mono, compressed, "90s phone call" sound). On top of that, many systems negotiate only the baseline SBC codec even when better options exist.

What this does

  • Better playback codec: enables SBC-XQ (and lets headsets that offer AAC/aptX/LDAC use them), plus mSBC wideband speech for calls.
  • No surprise quality drops: disables WirePlumber's automatic switch to the telephone profile when an app grabs the mic.
  • Explicit control instead: a headset-mode command (bind it to a hotkey) toggles between:
    • music — best A2DP stereo codec, internal mic as default input
    • call — headset mic active, playback mono 16 kHz (the unavoidable Bluetooth price for using the headset's mic)

Each switch shows a desktop notification telling you which mode you're in.

Compatibility

Any distro where PipeWire + WirePlumber is the audio stack:

Distro Status
Arch / CachyOS / Manjaro ✅ WirePlumber 0.5+ (.conf config)
Fedora ≥ 34 ✅ WirePlumber 0.5+ (.conf config)
Ubuntu ≥ 24.10, Debian 13 ✅ WirePlumber 0.5+ (.conf config)
Ubuntu 24.04 LTS / 22.10–24.04, Debian 12 ✅ WirePlumber 0.4 — installer auto-detects and uses the Lua config variant
Ubuntu ≤ 22.04 default install ❌ PulseAudio — switch to PipeWire first

Works with any Bluetooth headset (auto-detects the first connected one). Developed with a SteelSeries Arctis Nova 7; also useful for Sony/Bose/… earbuds — headsets offering LDAC or aptX get those codecs automatically in music mode.

Install

git clone https://github.com/YOURNAME/headset-mode
cd headset-mode
./install.sh            # add --hotkey to register Super+Shift+H on GNOME

Then power-cycle the headset once and run headset-mode music.

Installed files:

  • ~/.local/bin/headset-mode
  • ~/.local/bin/le-audio-setup
  • ~/.config/wireplumber/wireplumber.conf.d/50-bluez.conf (WirePlumber ≥ 0.5)
  • or ~/.config/wireplumber/{bluetooth,policy}.lua.d/*.lua (WirePlumber 0.4)

Usage

headset-mode            # toggle music <-> call
headset-mode music      # force Hi-Fi mode
headset-mode call       # force call mode (headset mic)

# multiple headsets? pin one:
HEADSET_CARD=bluez_card.20_AF_1B_21_3F_D8 headset-mode call

On KDE, bind the command under System Settings → Shortcuts → Add Command.

LE Audio (LC3) — the actual fix

Classic Bluetooth's "stereo OR mic" limitation is solved by Bluetooth LE Audio: the LC3 codec runs both directions at once — 48 kHz stereo playback and a 32 kHz mic simultaneously, no telephone-profile fallback. If your headset supports LE Audio (Sony WF-1000XM5, many 2023+ earbuds) and your adapter has ISO channels (BT 5.2+; Intel AX210/BE200 are the known-good ones on Linux):

le-audio-setup          # one command: config + pairing wizard + verify
le-audio-setup verify   # re-run only the radio traffic check

What it automates (each of these is a trap if done by hand):

  • enables Experimental + KernelExperimental in /etc/bluetooth/main.conf (without the second flag BlueZ logs "BAP requires ISO Socket" and LE Audio silently doesn't exist)
  • pairs over an LE-only scan — a normal pairing races against classic Bluetooth, classic wins, and you're stuck on A2DP forever
  • detects coordinated sets (earbuds that are two independent radios) and walks you through pairing both buds — one bud alone is mono; the second bud only advertises while in pairing mode
  • pins the LE bearer so dual-mode devices don't fall back to classic on reconnect, and selects the bap-duplex profile
  • verifies with btmon that ISO audio packets actually leave the radio. Some controllers (Qualcomm WCN6855 / QCNFA765, common in AMD ThinkPads) accept the entire LE Audio setup — transports "active", everything looks perfect — and then transmit nothing. Silence. The verify step catches this in 10 seconds instead of an afternoon.

If the verify step reports a silent controller, your options are an Intel AX210 (works on AMD and Intel machines) or BE200 (Intel-only platforms — it does not work on AMD), or waiting for a Qualcomm firmware fix. Classic Bluetooth keeps working either way.

Optional extras

# Battery/sidetone/EQ for gaming headsets — needs the 2.4 GHz USB dongle:
sudo pacman -S headsetcontrol        # Arch; elsewhere: github.com/Sapd/HeadsetControl

# Battery percentage over Bluetooth (BlueZ experimental flag):
sudo sed -i '/^\[General\]/a Experimental = true' /etc/bluetooth/main.conf
sudo systemctl restart bluetooth

# System-wide parametric EQ (works over Bluetooth):
sudo pacman -S easyeffects           # or: apt/dnf install easyeffects

Honest expectations

SBC-XQ is a real, audible improvement, but Bluetooth stays Bluetooth. If your headset has a 2.4 GHz USB dongle (most gaming headsets do), that is the genuinely better transport: full quality plus mic simultaneously, and on Linux it's a plain USB audio device that needs none of this. The dongle for the Arctis Nova 7 is sold separately as "Arctis Nova 7 USB-C Transmitter" if you've lost yours.

License

MIT

About

Make Bluetooth headsets sound good on Linux — and keep them that way.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages