English | 简体中文
An unofficial multi-brand wireless headset control center for the Linux desktop (ported from EncoDeck), built with Rust and GTK4 / Libadwaita. It currently supports OPPO, OnePlus, realme, and EarFun wireless headsets, with a decoupled multi-brand architecture ready for expanding to additional brands in the future.
This project is not affiliated with or endorsed by any headset vendor. See
docs/api/OPPO_BLUETOOTH_API.mdanddocs/api/EARFUN_BLUETOOTH_API.mdfor private Bluetooth protocol details and hardware verification notes.
- Status Monitoring & 3D Preview: Real-time battery levels, charging status where reported by the protocol, in-ear wear and case-lid state where available, firmware version display, device artwork, and interactive 3D model preview.
- Noise Control: Switch between Active Noise Cancellation (with multi-level intensity), Transparency mode (including Vocal Enhancement), and Adaptive noise control. Availability follows model capabilities; a wear-state gate is applied only when the protocol reports physical wear state. EarFun GAIA reports the in-ear detection setting but not physical wear or charging state.
- Sound & Audio Effects: Built-in sound presets, custom multi-band Equalizer (EQ), Spatial Audio (Fixed / Head Tracking), and low-latency Game Mode.
- Controls & Utilities: Customize left/right touch and call gestures, long-press noise-control cycling, dual-device connection and paired-host switching, in-ear auto-pause, sleep detection, earbud fit test, Find My Earbuds, prompt volume adjustment, and microphone selection on compatible EarFun profiles. Choose the target from a compact popover and use the find/stop action in the controls card. EarFun features are enabled according to each registered model's compatibility profile and implemented controls; hardware validation is recorded separately and is not an additional enablement requirement.
- Desktop Integration: Native GTK4 / Libadwaita UI with English/Chinese localization, selectable app icon styles, background mode with a StatusNotifierItem system tray, silent login autostart, plus a companion GNOME Shell Quick Settings extension (GNOME 45–51).
Users on Arch Linux and its derivatives can install wavetune-git from the AUR:
paru -S wavetune-git
# or with yay
yay -S wavetune-gitOr clone and build manually:
git clone https://aur.archlinux.org/wavetune-git.git
cd wavetune-git
makepkg -siBefore launching WaveTune, make sure the system bluetooth service is running and pair/connect your headset via your desktop's Bluetooth settings first (WaveTune attaches to already-connected headsets rather than handling OS-level pairing):
sudo systemctl enable --now bluetoothA companion extension for GNOME 45–51 is included at gnome-shell/wavetune@onlymash.github.com (automatically installed to the system extensions directory by distribution packages).
For local installation from source:
./gnome-shell/install-local.sh
gnome-extensions enable wavetune@onlymash.github.comIn a Wayland session, if
gnome-extensionsdoes not recognize the UUID on first install, log out and back into your desktop session once before running the enable command.
When a supported headset is connected, a headset tile appears in the GNOME Quick Settings panel for toggling noise cancellation, checking live battery levels, switching noise-control sub-modes, or opening the main window. "Keep Running in Background" is enabled by default (closing the window hides it to the background; choose "Quit" from the main menu or press Ctrl+Q to exit completely), and "Start in Background on Login" can be toggled in Preferences.
While WaveTune is running it exports a StatusNotifierItem and DBusMenu on the session bus, so the app remains reachable after its window is hidden to the background. The tray uses the monochrome io.github.onlymash.WaveTune-symbolic icon and offers opening the main window, live device/battery information, noise-mode switching (when the headset is worn and controls are available), and quitting.
GNOME does not provide a system tray by default; install the AppIndicator and KStatusNotifierItem Support extension. KDE Plasma, XFCE, Waybar (Sway/Hyprland/Niri), COSMIC, and other StatusNotifierItem hosts consume the same protocol without additional software. The implementation reuses the existing gio::DBusConnection, so it adds no runtime or build dependencies.
Requires bluez, gtk4, libadwaita (>= 1.9), pkgconf, and the Rust stable toolchain. On Arch Linux:
sudo pacman -S --needed bluez gtk4 libadwaita pkgconf rustup
rustup default stableBuild and run:
cargo build --release # Release binary at target/release/wavetune
cargo test
cargo runCLI options:
--background/-b: Start silently in the background without opening the main window.--probe: Run a one-shot read-only diagnostic query against a connected headset and print a summary.
Packaging scripts and templates live under packaging/:
packaging/package.sh # Build Arch package if makepkg is available, otherwise deb
packaging/package.sh arch # Build Arch package from working tree snapshot
packaging/package.sh git # Build wavetune-git from local committed HEAD
packaging/package.sh deb # Build Debian/Ubuntu .deb package (requires dpkg-deb and libadwaita >= 1.9)Built packages are written to target/dist/. For AUR repository generation and publishing workflows, see packaging/arch/README.md.
The built-in compatibility catalog covers 130+ OPPO, OnePlus, and realme headset models, as well as EarFun Air Pro 4, Free Pro 3, Air S, Air Pro 4+/4+AI, Air Pro 5, Air Pro 3 variants, Free 2S, ATVEL Tune S5 ProX, Wave Pro X, and 11 EF-profile IDs. EarFun models without a known numeric Product ID use a strict model prefix in the firmware response when available; Bluetooth names are never used as model identifiers. For registered profiles, declared and implemented features are enabled without requiring prior real-device validation. EF support currently covers a subset of status, noise, game, prompt-volume, find, and spatial-audio controls; EF profile identification from firmware remains source-derived and unverified, so unmatched devices stay read-only. See the EarFun protocol notes for per-model scope and limitations.
GPL-3.0-only