Skip to content

fix(audio): find devices again when Windows replaces their endpoint ids - #8

Merged
hotdogee merged 1 commit into
mainfrom
fix/stable-endpoint-ids
Nov 1, 2026
Merged

hotdogee merged 1 commit into
mainfrom
fix/stable-endpoint-ids

Conversation

@hotdogee

@hotdogee hotdogee commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Problem

A Windows update (2026-10-31, build 26300) replaced the endpoint ids of four of the five active playback devices on the reference machine. The configuration stored only that id, so every hotkey press failed with:

nothing to switch to: neither "PG42UQ (NVIDIA High Definition Audio)" nor "喇叭 (FiiO BTA30 PRO)" is connected and enabled

Both devices were connected and working. Microsoft documents this: the id from IMMDevice::GetId "is not stable. An operating system update or an audio driver update can cause the same physical peripheral to be assigned a different endpoint ID." docs/research/core-audio-api.md A.7 already recommended storing PKEY_AudioEndpoint_StableId, but it was never implemented, and the README promised a stable id.

All five StableIds recorded in a property dump on 2026-10-04 are unchanged today, including the four whose ordinary id changed.

Fix

Each configured device is located in steps, and each step runs only when the one before it failed:

  1. Saved id. The hot path, with no additional calls.
  2. Saved stable_id. Also tried for a known but inactive endpoint, because an update can leave the old endpoint behind as not present.
  3. Exact friendly name, only when Windows knows neither id, and only when exactly one active endpoint has it and it is not the other configured device. Microsoft calls the stable id best effort, and configurations saved by 0.1.0 have none. An unplugged device is known to Windows and never reaches this step, so it cannot be silently replaced by an identical one.

After the switch, a new id and a missing stable id are recorded, so the next press is back on the hot path. Neither can delay or fail the switch: a failed read or write is retried on the next toggle. stable_id is optional and older builds ignore it, so the config version stays 1.

Also fixed:

  • A device that really cannot be found is no longer called disconnected. The message says Windows no longer has it and to choose a replacement in Settings.
  • The settings dialog opens with a moved device selected at its new endpoint, and reads stable ids on Save.

PKEY_AudioEndpoint_StableId comes from mmdeviceapi.h in SDK 10.0.26100 ({1da5d803-d492-4edd-8c23-e0c0ffee7f0e},12). windows 0.62.2 does not define it.

This pull request also releases 0.1.1 (version bump, changelog section, notices).

Latency

Real toggles, old and new build from the same compiler and flags, same config file, same directory, 4 alternating rounds of 60 runs through hyperfine -N:

Build Median p10 p90 Mean
Before (dcd470a) 40.66 ms 38.69 44.59 41.25
After 40.73 ms 38.95 45.70 41.56

The 0.08 ms difference is inside the spread between rounds (medians of 39.97 to 41.78 ms). The normal path adds two Option checks and no COM call.

One-time paths, medians of 6 runs with --timing:

Case Switch done Process end
Normal press 36.7 ms 38.6 ms
First press, no stable ids yet 34.4 ms 41.3 ms
Ids dead, stable ids saved 37.0 ms 44.1 ms
Ids dead, names only (a 0.1.0 configuration) 37.7 ms 44.8 ms

Testing

On Windows 11 build 26300:

  • cargo fmt --check, clippy -D warnings, cargo test --locked (118 unit, 6 CLI, 1 doc), third-party-notices.ps1 -Check, cargo +1.85 check.
  • cargo test -- --ignored with TOGGLE_AUDIO_TEST_DEVICES: 13 passed, including 2 new tests that resolve stable ids and relocate dead ids.
  • scripts/e2e.ps1: 59 checks passed. It has a new section that saves ids that no longer exist, and checks that the devices are found by name and by stable id, that the configuration is repaired, and that nothing is changed when nothing can be found.

The location logic is pure and unit-tested with a fake Windows, including that an active saved id costs exactly one lookup and that a name match never guesses.

The settings dialog was driven through Win32 messages against a scratch configuration holding the dead ids that caused the report: it opened with both devices selected and no "(not connected)" entries, and Save wrote the current ids and both stable ids. The Test toggle button was not exercised.

🤖 Generated with Claude Code

A Windows or audio driver update can give a device a new endpoint id. The
configuration stored only that id, so the toggle reported "neither ... is
connected and enabled" although both devices were connected, which is what
the 2026-10-31 update did on the reference machine.

Locate each configured device in steps, each one running only when the one
before it failed:

1. The saved id. This is the hot path and it makes no additional calls.
2. The saved PKEY_AudioEndpoint_StableId, which Windows tries to preserve
   across these updates.
3. Only when Windows knows neither id: the exact friendly name, when exactly
   one active endpoint has it and it is not the other configured device.
   Microsoft calls the stable id best effort, and configurations saved by
   0.1.0 have none. An unplugged device is known to Windows and never gets
   here, so it cannot be silently replaced by an identical one.

After the switch, record a new id and a missing stable id, so the next press
is back on the hot path. Neither can delay or fail the switch. A device that
cannot be found is now reported as such instead of as disconnected, and the
settings dialog opens with moved devices selected at their new endpoint.

Release 0.1.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hotdogee
hotdogee merged commit 94aaf0f into main Nov 1, 2026
5 checks passed
@hotdogee
hotdogee deleted the fix/stable-endpoint-ids branch November 1, 2026 10:47
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.

1 participant