Skip to content

rikkichy/openwave

Repository files navigation

OpenWave

Linux control application for the Elgato Wave XLR microphone interface. A reverse-engineered replacement for Elgato Wave Link, built with GTK4 + Adwaita.

Features

  • Microphone controls — Gain, mute (syncs with hardware button)
  • Headphone controls — Volume (syncs with hardware knob), low impedance mode
  • Hardware sync — 10 Hz polling keeps the app in sync with physical controls
  • System integration — Mute and HP volume sync bidirectionally with PipeWire/ALSA
  • Audio capture fix — Background daemon (systemd or runit) prevents the firmware race condition where mic goes silent
  • System tray — Runs in background with tray icon, mute from tray menu
  • First-run setup — Configures udev permissions and audio service automatically

How it works

The Wave XLR uses USB Class control transfers on endpoint 0 for device configuration. On Linux, snd-usb-audio normally blocks these transfers because wIndex=0x3300 routes through interface 0 (owned by the audio driver). OpenWave uses wIndex=0x3303 instead — the firmware only checks the 0x33 prefix, while the kernel sees interface 3 (unclaimed) and lets the transfer through. No driver detach needed, audio is never interrupted.

Install

One-liner — detects Arch, Debian/Ubuntu, Fedora, openSUSE, or Void; installs deps and OpenWave:

curl -fsSL https://raw.githubusercontent.com/rikkichy/openwave/main/install.sh | sh

Or from a checkout:

git clone https://github.com/rikkichy/openwave.git
cd openwave
./install.sh                  # default PREFIX=/usr/local
PREFIX=/usr ./install.sh      # for packaging-style layout

Uninstall:

sudo make -C /path/to/openwave uninstall PREFIX=/usr/local

Requirements

  • Python 3.10+
  • GTK4, libadwaita
  • PipeWire (for audio capture fix)
  • libusb 1.0

Usage

openwave            # if installed via install.sh / PKGBUILD
python3 -m wavexlr  # from a checkout, no install needed

On first launch, OpenWave will prompt to set up USB permissions (via polkit) and install the audio service.

Init systems

OpenWave detects your init system at runtime:

  • systemd — the GUI installs a user unit at ~/.config/systemd/user/openwave.service and enables it. No root needed for install or status checks.

  • runit (Artix, Void, Devuan-runit) — the GUI cannot install the system service itself (writing to /etc/sv requires root). Create a wavexlr-audio service directory at /etc/sv/wavexlr-audio/ whose run script execs python3 -m wavexlr.daemon as your user (typically via chpst -u), then enable it with ln -s /etc/sv/wavexlr-audio /var/service/.

    Status detection from the non-root GUI uses sv check; on stock Void the supervise FIFO is mode 0700, so OpenWave falls back to scanning /proc for the daemon process.

  • other (macOS, Windows, no init detected) — the capture-fix section is disabled.

Start hidden in tray

python3 -m wavexlr -- --hide

Desktop entry

Copy wavexlr.desktop to ~/.local/share/applications/ for app launcher integration.

Architecture

wavexlr/
  device.py   — USB backend (raw libusb via ctypes, wIndex=0x3303 trick)
  app.py      — GTK4/Adwaita UI with 10Hz polling
  tray.py     — StatusNotifierItem tray icon via D-Bus
  audio.py    — PipeWire capture keepalive (fixes firmware race condition)
  daemon.py   — Systemd service entry point
  setup.py    — First-run udev + systemd setup

Credits

USB protocol reverse-engineered from the macOS Wave Link application using Frida. Inspired by GoXLR-on-Linux/goxlr-utility.

License

MIT

About

Linux control application for the Elgato Wave XLR interface

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors