From 41162e0acaec36cf579ba76b04b3d976f5ca6369 Mon Sep 17 00:00:00 2001 From: 0xbyt4 <35742124+0xbyt4@users.noreply.github.com> Date: Fri, 13 Mar 2026 23:55:12 +0300 Subject: [PATCH] fix: prevent shutdown deadlock and unblockable Ctrl+C on exit Move stream close outside the lock in shutdown() to prevent deadlock when audio callback tries to acquire the same lock. Replace single t.join(timeout) with a polling loop (0.1s intervals) so KeyboardInterrupt is not blocked during stream cleanup. --- tools/voice_mode.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/voice_mode.py b/tools/voice_mode.py index 93e044eb..d5ae94f6 100644 --- a/tools/voice_mode.py +++ b/tools/voice_mode.py @@ -400,7 +400,10 @@ class AudioRecorder: t = threading.Thread(target=_do_close, daemon=True) t.start() - t.join(timeout=timeout) + # Poll in short intervals so Ctrl+C is not blocked + deadline = __import__("time").monotonic() + timeout + while t.is_alive() and __import__("time").monotonic() < deadline: + t.join(timeout=0.1) if t.is_alive(): logger.warning("Audio stream close timed out after %.1fs — forcing ahead", timeout) @@ -465,7 +468,8 @@ class AudioRecorder: self._recording = False self._frames = [] self._on_silence_stop = None - self._close_stream_with_timeout() + # Close stream OUTSIDE the lock to avoid deadlock with audio callback + self._close_stream_with_timeout() logger.info("AudioRecorder shut down") # -- private helpers -----------------------------------------------------