mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-29 01:31:41 +00:00
fix: voice pipeline hardening — 7 bug fixes with tests
1. Anthropic + ElevenLabs TTS silence: forward full response to TTS callback for non-streaming providers (choices first, then native content blocks fallback). 2. Subprocess timeout kill: play_audio_file now kills the process on TimeoutExpired instead of leaving zombie processes. 3. Discord disconnect cleanup: leave all voice channels before closing the client to prevent leaked state. 4. Audio stream leak: close InputStream if stream.start() fails. 5. Race condition: read/write _on_silence_stop under lock in audio callback thread. 6. _vprint force=True: show API error, retry, and truncation messages even during streaming TTS. 7. _refresh_level lock: read _voice_recording under _voice_lock.
This commit is contained in:
parent
7a24168080
commit
eb34c0b09a
8 changed files with 317 additions and 10 deletions
|
|
@ -310,8 +310,9 @@ class AudioRecorder:
|
|||
should_fire = True
|
||||
|
||||
if should_fire:
|
||||
cb = self._on_silence_stop
|
||||
self._on_silence_stop = None # fire only once
|
||||
with self._lock:
|
||||
cb = self._on_silence_stop
|
||||
self._on_silence_stop = None # fire only once
|
||||
if cb:
|
||||
def _safe_cb():
|
||||
try:
|
||||
|
|
@ -321,6 +322,7 @@ class AudioRecorder:
|
|||
threading.Thread(target=_safe_cb, daemon=True).start()
|
||||
|
||||
# Create stream — may block on CoreAudio (first call only).
|
||||
stream = None
|
||||
try:
|
||||
stream = sd.InputStream(
|
||||
samplerate=SAMPLE_RATE,
|
||||
|
|
@ -330,6 +332,11 @@ class AudioRecorder:
|
|||
)
|
||||
stream.start()
|
||||
except Exception as e:
|
||||
if stream is not None:
|
||||
try:
|
||||
stream.close()
|
||||
except Exception:
|
||||
pass
|
||||
raise RuntimeError(
|
||||
f"Failed to open audio input stream: {e}. "
|
||||
"Check that a microphone is connected and accessible."
|
||||
|
|
@ -670,6 +677,12 @@ def play_audio_file(file_path: str) -> bool:
|
|||
with _playback_lock:
|
||||
_active_playback = None
|
||||
return True
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.warning("System player %s timed out, killing process", cmd[0])
|
||||
proc.kill()
|
||||
proc.wait()
|
||||
with _playback_lock:
|
||||
_active_playback = None
|
||||
except Exception as e:
|
||||
logger.debug("System player %s failed: %s", cmd[0], e)
|
||||
with _playback_lock:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue