fix: persistent audio stream and silence detection improvements

- Keep InputStream alive across recordings to avoid CoreAudio hang on
  repeated open/close cycles on macOS.  New _ensure_stream() creates the
  stream once; start()/stop()/cancel() only toggle frame collection.
- Add _close_stream_with_timeout() with daemon thread to prevent
  stream.stop()/close() from blocking indefinitely.
- Add generation counter to detect stale stream-open completions after
  cancel or restart.
- Run recorder.cancel() in background thread from Ctrl+C handler to
  keep the event loop responsive.
- Add shutdown() method called on /voice off to release audio resources.
- Fix silence timer reset during active speech: use dip tolerance for
  _resume_start tracker so natural speech pauses (< 0.3s) don't prevent
  the silence timer from being reset.
- Update tests to match persistent stream behavior.
This commit is contained in:
0xbyt4 2026-03-10 20:37:17 +03:00
parent eec04d180a
commit eb79dda04b
4 changed files with 221 additions and 132 deletions

View file

@ -603,28 +603,14 @@ class TestDisableVoiceModeStopsTTS:
def test_disable_voice_mode_calls_stop_playback(self):
"""Source check: _disable_voice_mode must call stop_playback()."""
with open("cli.py") as f:
source = f.read()
import inspect
from cli import HermesCLI
# Extract _disable_voice_mode method body
lines = source.split("\n")
in_method = False
method_lines = []
for line in lines:
if "def _disable_voice_mode" in line:
in_method = True
elif in_method:
if line.strip() and not line.startswith(" ") and not line.startswith("\t"):
break
if line.strip().startswith("def "):
break
method_lines.append(line)
method_body = "\n".join(method_lines)
assert "stop_playback" in method_body, (
source = inspect.getsource(HermesCLI._disable_voice_mode)
assert "stop_playback" in source, (
"_disable_voice_mode must call stop_playback()"
)
assert "_voice_tts_done.set()" in method_body, (
assert "_voice_tts_done.set()" in source, (
"_disable_voice_mode must set _voice_tts_done"
)