Skip to content

feat(audeze): implement the real Maxwell protocol and add custom EQ - #591

Open
ModoloDev wants to merge 2 commits into
Sapd:masterfrom
ModoloDev:master
Open

ModoloDev wants to merge 2 commits into
Sapd:masterfrom
ModoloDev:master

Conversation

@ModoloDev

Copy link
Copy Markdown
Contributor

Changes made

  • implement the real Maxwell protocol
  • add custom EQ
  • fix sidetone being toggled on every call instead of set
  • report the current sidetone level
  • round inactive time up to the nearest value the headset supports
  • add protocol tests, including EQ coefficient reference vectors

Replace the fixed, captured packets with an implementation of the protocol the headset actually speaks: requests are built from command, key and value, split into HID reports, and matched against the reply the headset sends back. Errors reported by the headset now reach the user instead of being ignored.

Maxwell and Maxwell 2 share this code through a new AudezeMaxwellDevice base class, so each device file only holds what differs between them.

Add custom equalizer support for the original Maxwell. The ten band gains (-12 to 12 dB, whole steps) are written to the selected custom preset, applied immediately and stored on the headset.

Checklist

  • I adjusted the README (if needed)
  • For new features in HeadsetControl: I discussed it beforehand in Issues or Discussions and adhered to the wiki

Related to #460

Replace the fixed, captured packets with an implementation of the
protocol the headset actually speaks: requests are built from command,
key and value, split into HID reports, and matched against the reply
the headset sends back. Errors reported by the headset now reach the
user instead of being ignored.

Maxwell and Maxwell 2 share this code through a new AudezeMaxwellDevice
base class, so each device file only holds what differs between them.

Add custom equalizer support for the original Maxwell. The ten band
gains (-12 to 12 dB, whole steps) are written to the selected custom
preset, applied immediately and stored on the headset.

Also:
- fix sidetone being toggled on every call instead of set
- report the current sidetone level
- round inactive time up to the nearest value the headset supports
- add protocol tests, including EQ coefficient reference vectors
@ModoloDev

Copy link
Copy Markdown
Contributor Author

With the help of AI, I reverse-engineered the protocol used by the Audeze app and reimplemented it here, replacing the previous captured packets.

I could only test on my own original Maxwell, so I'd appreciate help validating:

@MonsterBagels, could you please check that nothing broke on the Maxwell 2? It now shares the protocol code with the original Maxwell, and I have no Maxwell 2 to test on.

@Nallebeorn, could you please test on your Maxwell as a second confirmation?

What to try:

  • headsetcontrol -b (battery)
  • headsetcontrol -s (read sidetone), then -s 64 and -s 0, checking that sidetone really turns on and off and that repeating the same command doesn't flip it
  • chatmix, inactive time, voice prompts, EQ preset and noise filter
  • original Maxwell only: volume limiter and the custom equalizer on a custom preset

Removed information about original Audeze Maxwell EQ edits.
@MonsterBagels

MonsterBagels commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

I can't help unfortunately, as I've sold my Maxwell 2 but good luck!

@ModoloDev

Copy link
Copy Markdown
Contributor Author

@AdrianKuriata could you please check that nothing broke on the Maxwell 2?

@Nallebeorn

Nallebeorn commented Oct 10, 2026 •

Copy link
Copy Markdown

Tested with my own (original) Maxwell (I don't have the 2 either), seems good!

-s flag can read sidetone, and set it in the 0..128 range (unlike before, when -s 0 toggled it on and off and no other value worked). It triggers the "Sidetone off" voice alert when setting it to 0, but never plays the "Sidetone on" alert. headsetcontrol -b also seems to work well, but in the past I've seen it apparently work well at first only to turn out to be unreliable over time, so let's see if this version holds up!

I did have to unplug and reinsert my dongle after installing this commit before any command worked (otherwise every operation timed out).

@Sapd Sapd left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the #577 packet: gone. The whole init sequence is removed and nothing writes key 0x25, so the imbalance can't come back. Setter bodies are byte-identical to master.

On Maxwell 2 - master's two device files differ by exactly one command, the volume limiter (0x28, 0x88/0x8e), which the 2 doesn't advertise anyway. The old file was a copy, so keeping it isn't the safety it looks like. Also worth knowing: master's battery read only worked because hid_get_input_report picked up the reply to the previous request. That was timing luck. Sharing the base is the right call, just say in the description that the 2 is untested.

Two things before merge:

  1. request() doesn't drain the input queue. If a state read times out and is retried, both replies land and the stale one gets consumed by the next read - setSidetoneEnabled then toggles twice and still reports success, leaving sidetone off. Needs a >400 ms reply so it's unlikely, but it's silently wrong. Read until len 0 before sending.

  2. The writeKey ack predicate checks the family byte and key but not byte 4, so a queued read-key reply passes as the write ack. The comment says Audeze.exe is equally loose - do you have evidence that's needed, or can we tighten it?

Cosmetic, and it explains @Nallebeorn's report: the level write silently enables sidetone, so setSidetoneEnabled(true) reads back "on" and never sends the toggle that plays the prompt. Enable before writing the level and "sidetone on" fires. The replug he needed isn't explained by anything in the driver.

Pre-existing: -s 1 maps to device level 0 and switches sidetone off.

Build, tests, clang-format 18 and the README generator are all clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants