-
Notifications
You must be signed in to change notification settings - Fork 4
Protocol
Note: On Linux, OpenWave uses
wIndex=0x3303instead of0x3300to bypasssnd-usb-audio's interface ownership check. The firmware accepts both — see How it works for details.
-
Vendor ID:
0x0FD9(Elgato) -
Product ID:
0x007D(Wave XLR),0x007E(DFU mode) -
Control Interface: Interface 3 — Class
0xFF, SubClass0xF0, 0 endpoints - Audio Interfaces: 0-2 — standard USB Audio Class 1.0
- DFU Interface: 4
All control communication uses USB Class requests on EP0:
-
Read:
bmRequestType=0xA1(IN, Class, Interface) -
Write:
bmRequestType=0x21(OUT, Class, Interface) -
bRequest:
0x85(read),0x05(write) -
wIndex:
0x3300(protocol standard) /0x3303(Linux workaround)
NOT Vendor requests — the type bits are Class (01), not Vendor (10).
| bmRequestType | bRequest | wValue | wLength | Description |
|---|---|---|---|---|
0xA1 |
0x85 |
0x0000 |
34 | Read config (all settings) |
0xA1 |
0x85 |
0x0001 |
10 | Read metering (input levels) |
0xA1 |
0x85 |
0x000A |
2 | Read API version |
0xA1 |
0x85 |
0x000A |
51 | Read device info (FW version, serial) |
0x21 |
0x05 |
0x0000 |
34 | Write config (read-modify-write) |
| Offset | Size | Type | Field | Encoding |
|---|---|---|---|---|
| 0-1 | 2 | uint16 LE | input_gain | Internal scale, ~linear with dB. 0x0000=0dB, 0x2200≈31dB |
| 2 | 1 | uint8 | unknown | 0x00 |
| 3 | 1 | uint8 | unknown | 0xEC |
| 4 | 1 | uint8 | input_mute | 0=unmuted, 1=muted |
| 5-8 | 4 | — | reserved | all 0x00
|
| 9-10 | 2 | int16 LE | headphone_volume | Signed Q8.8 dB. Divide by 256 for dB. Range: -30.5 to 0 dB |
| 11-13 | 3 | — | reserved | all 0x00
|
| 14 | 1 | uint8 | volume_select | 1=knob→gain, 2=knob→HP volume |
| 15 | 1 | uint8 | unknown |
0xFF (likely clipguard or lowcut) |
| 16-17 | 2 | — | unknown | 0x00 0x00 |
| 18-26 | 9 | — | unknown | all 0xFF (likely DSP enable flags) |
| 27 | 1 | uint8 | unknown | 0x01 |
| 28 | 1 | uint8 | unknown | 0x01 |
| 29 | 1 | uint8 | unknown | 0xFF |
| 30 | 1 | uint8 | unknown |
0x37 (55) |
| 31 | 1 | uint8 | unknown | 0x00 |
| 32 | 1 | uint8 | unknown | 0x01 |
| 33 | 1 | uint8 | low_impedance | 0=disabled, 1=enabled |
Little-endian uint16, internal scale (not direct dB).
| USB Value (LE) | Approx dB |
|---|---|
0x0000 |
0 |
0x2200 |
~31 |
0x2980 |
~39 |
0x48C0 |
~73 |
WebSocket API reports range 0-75 dB.
Little-endian signed int16, Q8.8 fixed-point dB.
| USB Value (LE) | dB |
|---|---|
0xE180 |
-30.5 |
0xF100 |
-15.0 |
0xFE33 |
-1.8 |
0x0000 |
0.0 |
| Offset | Size | Type | Field |
|---|---|---|---|
| 0-3 | 4 | uint32 LE | input_level_left |
| 4-7 | 4 | uint32 LE | input_level_right |
| 8-9 | 2 | uint16 LE | flag (always 0x0001) |
Both levels are identical (mono mic). Range: ~0x00-0xFF.
Short read (2 bytes): returns API version, e.g. 01 03 = v1.3.
Full read (51 bytes):
Offset Meaning
0-1 API version (01 03)
6-8 Firmware version (03 07 03 = v3.7.3?)
27-46 Device UID + serial number (ASCII)
47-50 Hardware info
Wave Link polls at 10 Hz (100ms interval):
- Read config (wValue=0x0, 34 bytes)
- Read meters (wValue=0x1, 10 bytes)
- Sleep ~100ms
- Repeat
No device-push notifications — purely host-polled.
- Read API version (wValue=0xA, 2 bytes)
- Read config (wValue=0x0, 34 bytes)
- Read meters (wValue=0x1, 10 bytes)
- Read full device info (wValue=0xA, 51 bytes)
- Read config again
- Write config (wValue=0x0, 34 bytes) — restores saved settings
- Begin steady-state 10 Hz polling
Read-modify-write — always read the full 34-byte config first, modify desired bytes, write back the entire struct.
From binary analysis of Wave Link, these exist but byte offsets are unknown:
- Clipguard enable, Low-cut enable
- Headphone mute, Direct monitor level
- Phantom power (48V), Gain lock
- LED brightness/colors
- DSP effects (compressor, EQ, expander) — likely use additional wValue addresses