audio: release the cached output stream when idle — HDMI output blocks macOS sleep - #23
Conversation
|
Thank you — this is a good catch, and the write-up made it reviewable in one pass. I checked the two things that could have gone wrong and both hold up:
One nit, not a blocker: the worker now wakes every 30 s for the life of the process, including when there is no stream to release. For a tray app that runs all day that's ~2880 no-op wakeups a day — pennies, but trivially removed by waiting with |
Addressing review on Just-Code-NET#23: waiting with recv_timeout unconditionally woke the worker every 30 s for the life of the process even when no stream was cached — ~2880 no-op wakeups a day for a tray app. Block with recv() while state.stream is None and only poll on a timeout while a stream is cached.
Addressing review on Just-Code-NET#23: waiting with recv_timeout unconditionally woke the worker every 30 s for the life of the process even when no stream was cached — ~2880 no-op wakeups a day for a tray app. Block with recv() while state.stream is None and only poll on a timeout while a stream is cached.
|
Good point — taken in this PR rather than as a follow-up. The loop now blocks with plain |
…S sleep The worker cached its OutputStream for the life of the process once a sound had played: the 'stale refresh' in handle() only dropped it when another play arrived after the idle window, and with no further plays the stream stayed open forever. On macOS an open CoreAudio output on an HDMI / DisplayPort device keeps coreaudiod's power assertion alive, so the system would neither turn the display off nor sleep. The worker loop now waits with recv_timeout(STREAM_IDLE_REFRESH) and releases the cached stream on timeout; the next play reopens it lazily (~20-50 ms, hidden under the synth lead silence).
Addressing review on Just-Code-NET#23: waiting with recv_timeout unconditionally woke the worker every 30 s for the life of the process even when no stream was cached — ~2880 no-op wakeups a day for a tray app. Block with recv() while state.stream is None and only poll on a timeout while a stream is cached.
3d0b474 to
3592ac6
Compare
|
Checked in on this because we were about to merge — then noticed you moved it to draft right after the comment, so I am asking rather than assuming. For what it is worth, I reviewed the current head (
So: is the draft flag there because something else is still in flight — something that does not show up in the diff, hardware behaviour on a real HDMI output, say — or did it just get flipped by habit? No rush from our side, and I would rather wait than merge something you consider unfinished. Context so you can judge the timing: this is the last thing between us and cutting a release. Nothing else is waiting on you, and if you would rather it soak, that is a fine answer — the release can wait. Just mark it ready for review when you are happy with it and we will merge. |
Problem
On macOS, with audio routed to an HDMI / DisplayPort display, PolterType prevents the display from turning off and the system from sleeping:
pmset -g assertionsshows acom.apple.audio.*power assertion held for the process indefinitely.Root cause
The audio worker caches its rodio
OutputStreamonce a sound has played, and the 'stale refresh' inWorkerState::handle()only drops it when another play arrives afterSTREAM_IDLE_REFRESH. With no further plays the stream stays open for the life of the process. An open CoreAudio output stream on an HDMI device keeps coreaudiod's power assertion alive, so macOS behaves as if audio were playing forever.Fix
The worker loop now waits with
recv_timeout(STREAM_IDLE_REFRESH)(30 s) and releases the cached stream on timeout. The next play reopens it lazily — the ~20–50 ms reopen cost was the reason the stream was cached in the first place, and it is hidden under the synth tone's lead silence (and is imperceptible for theme files, which were already opened fresh per play).The existing stale-refresh and error-invalidation paths are unchanged, so default-device tracking (BT headphones, HDMI plug/unplug) behaves as before.
Validation
cargo test -p poltertype-corepasses.