fix(audio): keep the audio-feedback output stream open instead of reopening it per chime (cross-platform) - #1740
Conversation
Opening a WASAPI output stream (or enumerating output devices for an explicit selection) on every chime races concurrent audio session state on Windows; when it stalls it can take the whole audio stack down with it. Move playback to a dedicated long-lived worker that opens the output stream once (pre-warmed at startup) and reuses it, recreating only on device change, on a default-device switch, or on a playback stall. Dispose of a scrapped stream on the worker thread itself: cpal::Stream is !Send on CoreAudio and ALSA, so it must not be moved to another thread to be dropped (this is what failed to compile on macOS in the first pass). The transcription pipeline is protected independently by the recorder-side bounded waits, so a slow teardown here can at worst drop a chime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
I need to take a look at this but my concern is keeping devices awake can affect sleep states on some systems and also conflict with other audio apps, which is mainly the reason why we open and close. If we don't already we probably should open once at the start of transcription and only close at the end of it. At least this would be better, but mostly I don't think we should keep the device warm all the time unless we add a setting to disable this (and actually should be disabled by default) |
|
Fair point — I hadn't thought about sleep states and conflicts with other audio apps holding the device open. That one's on me, and I agree it shouldn't stay warm forever. Before I rework it: what about reusing the pattern you already have for the mic stream?
That gives you the "setting, disabled by default" behaviour you asked for without adding a new setting, and it's the same semantics the mic stream already has, so it should read as familiar rather than as a new mechanism. Happy to rework the PR that way. If you'd rather keep it dead simple — open at start of transcription, close at the end, no setting involved — I'll do that instead. Your call, just tell me which and I'll push it. |
Manually adapted open upstream PR cjpais#1740 head e9934a6. Retained AIVO's independent result-ready feedback cue.
|
I don't think that I'm going to be able to merge this right now. Largely that I don't think we should be keeping output streams active, and this kind of changes a lot of core stuff. If you want to submit a more targeted fix, let's do that |
Before Submitting This PR
Human Written Description
This is the audio-feedback side of the hang, redone so it builds everywhere. In my first PR (#1713) I only compiled on Windows and it broke your macOS build — sorry about that. The real problem on my machine: a fresh WASAPI output stream gets opened for every start/stop chime, and when one stalls it drags the whole audio stack down with it. This opens the stream once and reuses it. Kept it minimal, and this time it never moves the stream across threads — that was the
!Sendcompile error last time (cpal's stream isSendon WASAPI but not on CoreAudio/ALSA).Related Issues/Discussions
Relates to #1712. Complements #1713 (the recorder-side bounded-waits fix for the same hang — that PR stays focused on the recorder change; this one is the audio-feedback half).
Fixes #1712
Community Feedback
You asked for a patch in #1712 ("If you have a patch would love to see it and pull it in"). #1213 / #1228 / #1349 are independent reports of the same symptom.
Testing
test.yml): green on my fork — this is the platform that actually catches the bug, since cpal'sStreamis!Sendon ALSA just like on CoreAudio.Built application at .../aarch64-apple-darwin/release/handy); the job only fails at codesign because my fork has no Apple certificate. That was the exact step that failed to compile before, so this confirms the!Sendfix.cargo clippyclean on the touched file,cargo fmtapplied.Behaviour notes: the stream is pre-warmed once at startup, recreated only on device change, on a "Default"→OS-default switch, or on a playback stall (bounded, so a wedged device can at worst drop a chime — the pipeline is protected separately by the recorder-side change in #1713).
AI Assistance
AI was used
Tools used: Claude Code
How extensively: root-cause analysis and the patch were written with Claude Code under my direction and review; I built it and field-tested it on my machine over a week of daily use, and drove the cross-platform CI verification. Commits carry a
Co-Authored-By: Claudetrailer.