Field report (2026-08-12): a user's PC stopped sleeping after installing Punktfunk; powercfg -requests showed the Steam Streaming Microphone holding "An audio stream is currently in use."
Root cause
The host-lifetime mic pump (deliberately eager, so the virtual mic exists before games bind their capture device) kept a WASAPI render stream RUNNING on the virtual-mic device for the whole host lifetime, writing silence 24/7 — client connected or not. Any running stream makes the Windows audio stack hold a kernel power request attributed to that device, which vetoes system sleep indefinitely.
Fix
wasapi_mic.rs's render loop now idle-stops the stream after 10 s of silence-only output:
IAudioClient::Stop only — the client stays initialized and the microphone endpoint keeps existing for host apps to bind; just the power request is released.
The render thread parks on a condvar the producer notifies on the queue's empty→non-empty edge, so the next mic frame resumes (Start) within one device period — below the jitter buffer's prime depth, nothing audible changes.
The idle window keys on the queue length staying unchanged, not emptiness: it also covers a stale sub-prime tail a vanished client left behind, while a fresh burst landing exactly at the boundary moves the length and resets the window instead of being dropped.
A resume failure (endpoint died while parked) propagates as a thread death → the pump's existing reopen-with-backoff self-healing takes over; no new failure mode.
Streaming sessions keep the box awake via their session-scoped DisplayWakeRequest (pf-frame), unchanged.
Escape hatch: PUNKTFUNK_MIC_ALWAYS_ON=1 restores the always-running stream in case a third-party virtual audio driver misbehaves while its render side is paused.
Investigated and refuted en route: the desktop-audio loopback capturer does not persist between sessions on Windows (park_audio_capture drops it, restoring the default playback device) — the mic stream was the only no-client sleep blocker.
Verification
cargo clippy -p punktfunk-host --all-targets -- -D warnings green on the windows-amd64 runner (.133), after cargo clean -p punktfunk-host and confirming the shipped tree contained the change.
rustfmt gates via the repo hooks.
Owed (hardware): observe powercfg /requests clear ~10 s after idle on a real box, and confirm recording from the Steam Streaming Microphone yields silence (not a stall) while the render side is stopped — the reason the escape hatch exists.
Field report (2026-08-12): a user's PC stopped sleeping after installing Punktfunk; `powercfg -requests` showed the **Steam Streaming Microphone** holding "An audio stream is currently in use."
## Root cause
The host-lifetime mic pump (deliberately eager, so the virtual mic exists before games bind their capture device) kept a WASAPI **render stream RUNNING** on the virtual-mic device for the whole host lifetime, writing silence 24/7 — client connected or not. Any running stream makes the Windows audio stack hold a kernel power request attributed to that device, which vetoes system sleep indefinitely.
## Fix
`wasapi_mic.rs`'s render loop now **idle-stops the stream** after 10 s of silence-only output:
- `IAudioClient::Stop` only — the client stays initialized and the microphone **endpoint keeps existing** for host apps to bind; just the power request is released.
- The render thread parks on a condvar the producer notifies on the queue's empty→non-empty edge, so the next mic frame resumes (`Start`) within one device period — below the jitter buffer's prime depth, nothing audible changes.
- The idle window keys on the queue **length staying unchanged**, not emptiness: it also covers a stale sub-prime tail a vanished client left behind, while a fresh burst landing exactly at the boundary moves the length and resets the window instead of being dropped.
- A resume failure (endpoint died while parked) propagates as a thread death → the pump's existing reopen-with-backoff self-healing takes over; no new failure mode.
- Streaming sessions keep the box awake via their session-scoped `DisplayWakeRequest` (pf-frame), unchanged.
- Escape hatch: `PUNKTFUNK_MIC_ALWAYS_ON=1` restores the always-running stream in case a third-party virtual audio driver misbehaves while its render side is paused.
Investigated and refuted en route: the desktop-audio loopback capturer does **not** persist between sessions on Windows (`park_audio_capture` drops it, restoring the default playback device) — the mic stream was the only no-client sleep blocker.
## Verification
- `cargo clippy -p punktfunk-host --all-targets -- -D warnings` green on the windows-amd64 runner (.133), after `cargo clean -p punktfunk-host` and confirming the shipped tree contained the change.
- rustfmt gates via the repo hooks.
- Owed (hardware): observe `powercfg /requests` clear ~10 s after idle on a real box, and confirm recording from the Steam Streaming Microphone yields silence (not a stall) while the render side is stopped — the reason the escape hatch exists.
The mic pump's WASAPI backend rendered silence into the virtual mic's
render endpoint (typically the Steam Streaming Microphone) for the whole
host lifetime. A RUNNING stream makes the Windows audio stack hold a
kernel power request ("An audio stream is currently in use", visible in
powercfg /requests), so every idle Punktfunk host blocked system sleep
forever — field-reported 2026-08-12 ("doesn't go to sleep anymore since
installing punktfunk; powercfg shows the Steam Streaming Microphone").
Stop the render stream (IAudioClient::Stop — client stays initialized,
the mic endpoint keeps existing) after 10 s of silence-only output at an
unchanged queue length, and park the render thread on a condvar the
producer notifies on the empty->non-empty edge, so the next mic frame
resumes the stream within one device period — well under the jitter
buffer's prime depth, so nothing audible changes. Keying the idle window
on the queue LENGTH (not emptiness) also covers a sub-prime tail a
vanished client left behind, while any fresh burst moves the length and
resets the window instead of being dropped.
During a session the box stays awake through the session's own
DisplayWakeRequest (pf-frame), never through this silence.
PUNKTFUNK_MIC_ALWAYS_ON=1 restores the old always-running stream in case
a virtual audio driver misbehaves while its render side is paused.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Field report (2026-08-12): a user's PC stopped sleeping after installing Punktfunk;
powercfg -requestsshowed the Steam Streaming Microphone holding "An audio stream is currently in use."Root cause
The host-lifetime mic pump (deliberately eager, so the virtual mic exists before games bind their capture device) kept a WASAPI render stream RUNNING on the virtual-mic device for the whole host lifetime, writing silence 24/7 — client connected or not. Any running stream makes the Windows audio stack hold a kernel power request attributed to that device, which vetoes system sleep indefinitely.
Fix
wasapi_mic.rs's render loop now idle-stops the stream after 10 s of silence-only output:IAudioClient::Stoponly — the client stays initialized and the microphone endpoint keeps existing for host apps to bind; just the power request is released.Start) within one device period — below the jitter buffer's prime depth, nothing audible changes.DisplayWakeRequest(pf-frame), unchanged.PUNKTFUNK_MIC_ALWAYS_ON=1restores the always-running stream in case a third-party virtual audio driver misbehaves while its render side is paused.Investigated and refuted en route: the desktop-audio loopback capturer does not persist between sessions on Windows (
park_audio_capturedrops it, restoring the default playback device) — the mic stream was the only no-client sleep blocker.Verification
cargo clippy -p punktfunk-host --all-targets -- -D warningsgreen on the windows-amd64 runner (.133), aftercargo clean -p punktfunk-hostand confirming the shipped tree contained the change.powercfg /requestsclear ~10 s after idle on a real box, and confirm recording from the Steam Streaming Microphone yields silence (not a stall) while the render side is stopped — the reason the escape hatch exists.The mic pump's WASAPI backend rendered silence into the virtual mic's render endpoint (typically the Steam Streaming Microphone) for the whole host lifetime. A RUNNING stream makes the Windows audio stack hold a kernel power request ("An audio stream is currently in use", visible in powercfg /requests), so every idle Punktfunk host blocked system sleep forever — field-reported 2026-08-12 ("doesn't go to sleep anymore since installing punktfunk; powercfg shows the Steam Streaming Microphone"). Stop the render stream (IAudioClient::Stop — client stays initialized, the mic endpoint keeps existing) after 10 s of silence-only output at an unchanged queue length, and park the render thread on a condvar the producer notifies on the empty->non-empty edge, so the next mic frame resumes the stream within one device period — well under the jitter buffer's prime depth, so nothing audible changes. Keying the idle window on the queue LENGTH (not emptiness) also covers a sub-prime tail a vanished client left behind, while any fresh burst moves the length and resets the window instead of being dropped. During a session the box stays awake through the session's own DisplayWakeRequest (pf-frame), never through this silence. PUNKTFUNK_MIC_ALWAYS_ON=1 restores the old always-running stream in case a virtual audio driver misbehaves while its render side is paused.