What is the acoustic echo cancellation path on Windows? #54
Labels
No labels
needs-info
needs-triage
ready-for-agent
ready-for-human
v2
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wayfinder:ticket
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Reference
aiko/denpa#54
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Question
#43decided that barge-in — talking over her while she speaks — is supported and togglable. That requires acoustic echo cancellation, or her own output feeds straight back into the voice-activity detector.Android is answered: Kotlin
AudioRecordwithMediaRecorder.AudioSource.VOICE_COMMUNICATION, which gives the platform AEC.Windows is not.
#44established only the negative:cpalexposes noinput_preset, so it cannot ask for an echo-cancelled stream (PR #995, open since 2025-07-31). What Windows offers instead was never investigated.Answer from primary sources — Microsoft Learn, the Windows SDK, crate docs, upstream issue trackers. Cite everything; mark anything unsourced as unverified.
What is the supported AEC path on Windows today? Cover the Voice Capture DSP (
IMediaObject/ the media object for audio capture), theAUDIO_EFFECT_TYPE_ACOUSTIC_ECHO_CANCELLATIONaudio effects API, and Communications-category capture streams. Which of these still work on Windows 11, and which need the app to opt in at stream creation?Can any of it be reached alongside
cpal, or does an AEC-enabled capture stream have to be opened by WASAPI directly, bypassingcpalon Windows? If bypassing, what does that cost — a second capture implementation, or a thin WASAPI path withcpalretained for enumeration?Are there maintained Rust crates for this — WASAPI bindings exposing the Communications category or the Voice Capture DSP, or a portable AEC (
webrtc-audio-processingbindings,speexdsp)? Report maintenance state and licence, not just existence.What does a software AEC need from us if the platform path is unavailable — a reference stream of what is being played, sample-clock alignment, latency bounds? Denpa plays TTS through Web Audio in the renderer (ADR-0002 calls playback "the open edge"), so the reference signal may not be reachable from Rust without moving playback too. Say plainly whether software AEC forces playback into Rust.
Related
#43— the boundary decision this serves#35— the capture work it unblocks on Windows#44— the research that established the gapdenpa/docs/adr/0002-hardware-goes-through-rust.md— playback is explicitly the open edgeEcho cancellation is needed on exactly the surfaces that have it natively. Operator account, 2026-07-30:
AudioRecord'sMediaRecorder.AudioSource.VOICE_COMMUNICATION, which is what #43 already chose.So the platform that cannot echo-cancel is the one that does not need to, and the one that needs it gets it from the API already selected. That is a happier position than the research implied.
Consequence for the Windows work. #54 found the supported Windows AEC path (
eCommunicationsrole +SetClientProperties(AudioCategory_Communications)+IAudioEffectsManager/IAcousticEchoCancellationControl), and that reaching it means abandoningcpalforwasapi— cpal hardcodeseConsoleand exposes noSetClientProperties. That swap is deferred, not cancelled. It becomes necessary only if the desktop is ever driven on speakers.What this changes in the implementation:
set_barge_inno longer refuses when the backend cannot echo-cancel. Refusing would have blocked the case that actually works — headphones — while the case that does not (desktop speakers) is what theecho_cancellationcapability flag exists to let the UI describe. Capability informs; it does not forbid.This is recorded because it is not derivable from the code: a future reader finds a capture path with no echo cancellation and a barge-in toggle that permits itself anyway, and the reason is a fact about hardware rather than about software.
Resolution
Research delivered:
.denpa-work/research/windows-aec.md, primary sources only, every claim carrying a URL.Windows has a supported, non-deprecated AEC path. Capture endpoint under the
eCommunicationsrole,SetClientPropertieswithAudioCategory_CommunicationsbetweenActivateandInitialize, thenIAudioEffectsManagerto verify andIAcousticEchoCancellationControl::SetEchoCancellationRenderEndpointto aim it. Microsoft's own sample and Chromium both do exactly this.IAudioEffectsManagerneeds build 22000,IAcousticEchoCancellationControl22621 — both current on 24H2.cpal cannot reach it. No
SetClientPropertiesanywhere in its WASAPI backend,eConsolehardcoded, no publicIMMDeviceaccessor. Reaching AEC on Windows means leaving cpal forwasapi0.23.0 (MIT), which already ships the entire recipe including an in-treeexamples/aec.rs.Software AEC does not force playback out of the webview. WASAPI loopback supplies the reference signal on the same sample clock, and can reference the WebView2 process tree alone. ADR-0002's "playback is the open edge" survives; the trigger to move playback into Rust would be wanting a non-default output device, not echo cancellation.
Why the work it was blocking is deferred rather than done
#43established that the desktop runs on headphones, which removes the echo path rather than cancelling it, while the tablet and phone run on speakers and get AEC natively from Android'sVOICE_COMMUNICATION. So the platform that cannot echo-cancel is the one that does not need to.The
wasapiswap therefore becomes necessary only if the desktop is ever driven on speakers. Recorded on#35, which no longer blocks on this.