Skip to content

wasapi: recover when default endpoint polling finds no device - #320

Merged
hajimehoshi merged 2 commits into
ebitengine:mainfrom
kumagi:codex/oto-priority-67-20261014
Oct 15, 2026
Merged

hajimehoshi merged 2 commits into
ebitengine:mainfrom
kumagi:codex/oto-priority-67-20261014

Conversation

@kumagi

@kumagi kumagi commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What issue is this addressing?

None

What type of issue is this addressing?

bug

What this PR does | solves

Treat _E_NOTFOUND during default-endpoint polling as a device-switch condition, entering the existing bounded restart path instead of making the context permanently unusable. Existing HRESULT classification is unchanged: the current wrapper also aliases other Win32 errors to _E_NOTFOUND; fixing that classification is separate.

Validation: An actual-method private harness fails to reach restart on the original code and succeeds after the change under race. It covers wrapped endpoint errors, unchanged and changed IDs, interface release and unrelated fatal errors. COM/native calls are substituted.

Native macOS arm64 internal race tests and build passed. Windows 386/amd64/arm64 builds passed (compile only). Internal vet and other analyzers passed; full vet retains unchanged baseline Darwin unsafe.Pointer and Windows unkeyed GUID diagnostics. Native Windows playback, reconnect and recovery were not run. Independent review found no blocking issue.

Activation recovery follow-up: IMMDevice::Activate preserves audio-client HRESULT identity so invalidation during bounded reacquisition reaches the existing retry classifier. Private actual-wrapper old/fixed tests pass under race after the correction; native Windows device removal remains untested.

@hajimehoshi

Copy link
Copy Markdown
Member

Could you also address the related recovery gap in IMMDevice::Activate?

Microsoft documents AUDCLNT_E_DEVICE_INVALIDATED as a possible result when the endpoint or its adapter has been removed: https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdevice-activate

The wrapper in api_wasapi_windows.go currently formats every activation failure as an untyped HRESULT error. If the endpoint disappears between GetDefaultAudioEndpoint and Activate during restart(), isWASAPIDeviceTransientError cannot recognize the error, so recovery terminates instead of retrying. Please preserve _AUDCLNT_ERR(r) with %w for audio-client HRESULTs, as the other audio-client wrappers do, so the existing bounded retry path handles this case too.

Authored by Codex on behalf of @hajimehoshi.

@kumagi

kumagi commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed in 816fb3fea1ea242520ee16f87989f0e1f77d67cf. IMMDevice::Activate now preserves audio-client HRESULTs as _AUDCLNT_ERR(r) with %w, matching the other wrappers. The existing transient-error classifier can therefore recognize activation invalidation during bounded reacquisition. Success and the fallback for unrelated HRESULTs are unchanged.

A private regression extracts the actual wrapper and recovery classifier and substitutes only the native syscall. DEVICE_INVALIDATED and RESOURCES_INVALIDATED fail recognition before the change and pass afterward under race; success, non-transient activation errors and unrelated HRESULT fallback are also checked. Internal package race tests, the other vet analyzers, and Windows 386/amd64/arm64 builds passed. The known baseline Darwin unsafe.Pointer / Windows unkeyed GUID vet diagnostics are unchanged. These are synthetic wrapper tests and cross-builds; native Windows playback or device removal was not run. All nine exact-head upstream checks passed (https://github.com/ebitengine/oto/actions/runs/38772217608), as did all nine fork checks (https://github.com/kumagi/oto/actions/runs/38772205409).

@hajimehoshi hajimehoshi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@hajimehoshi
hajimehoshi merged commit 4d66e19 into ebitengine:main Oct 15, 2026
9 checks passed
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.

2 participants