Desmond-Dong commited on
Commit
0598343
·
1 Parent(s): b03d17a

fix: wait for RUN_END before starting new conversation

Browse files

The previous code started a new conversation in _tts_finished() callback,
which could happen before HA finished the pipeline. This caused:
- APIConnectionError: connection not ready
- CancelledError in audio stream

Now:
- _tts_finished() only sends AnnounceFinished, doesn't start new conversation
- _handle_run_end() is called on RUN_END event (safe point)
- New conversation only starts after HA confirms pipeline ended

Files changed (1) hide show
  1. reachy_mini_ha_voice/satellite.py +21 -8
reachy_mini_ha_voice/satellite.py CHANGED
@@ -165,12 +165,12 @@ class VoiceSatelliteProtocol(APIServer):
165
  self.play_tts()
166
 
167
  elif event_type == VoiceAssistantEventType.VOICE_ASSISTANT_RUN_END:
168
- # Note: Don't set _is_streaming_audio = False here
169
- # _tts_finished() will handle it based on whether we continue conversation
170
- if not self._tts_played:
171
- self._tts_finished()
172
  self._tts_played = False
173
- # Note: _reachy_on_idle() is called inside _tts_finished() if not continuing
 
 
 
174
 
175
  def handle_timer_event(
176
  self,
@@ -421,6 +421,7 @@ class VoiceSatelliteProtocol(APIServer):
421
  return self._tap_conversation_mode
422
 
423
  def stop(self) -> None:
 
424
  self.state.active_wake_words.discard(self.state.stop_word.id)
425
  self.state.tts_player.stop()
426
 
@@ -430,7 +431,9 @@ class VoiceSatelliteProtocol(APIServer):
430
  else:
431
  _LOGGER.debug("TTS response stopped manually")
432
 
433
- self._tts_finished()
 
 
434
 
435
  def play_tts(self) -> None:
436
  if (not self._tts_url) or self._tts_played:
@@ -455,9 +458,20 @@ class VoiceSatelliteProtocol(APIServer):
455
  self.state.music_player.resume_sendspin()
456
 
457
  def _tts_finished(self) -> None:
 
 
 
 
 
458
  self.state.active_wake_words.discard(self.state.stop_word.id)
459
  self.send_messages([VoiceAssistantAnnounceFinished()])
 
460
 
 
 
 
 
 
461
  # Check if should continue conversation
462
  # 1. HA requested continue (continue_conversation=1 in INTENT_END)
463
  # 2. Tap conversation mode is active (user tapped to start continuous mode)
@@ -484,9 +498,8 @@ class VoiceSatelliteProtocol(APIServer):
484
  else:
485
  # Conversation ended, clear state
486
  self._clear_conversation()
487
- self._is_streaming_audio = False
488
  self.unduck()
489
- _LOGGER.debug("TTS response finished, conversation ended")
490
  # Reachy Mini: Return to idle
491
  self._reachy_on_idle()
492
 
 
165
  self.play_tts()
166
 
167
  elif event_type == VoiceAssistantEventType.VOICE_ASSISTANT_RUN_END:
168
+ # Pipeline run ended - this is the safe point to start a new conversation
 
 
 
169
  self._tts_played = False
170
+ self._is_streaming_audio = False
171
+
172
+ # Check if should continue conversation (after RUN_END is safe)
173
+ self._handle_run_end()
174
 
175
  def handle_timer_event(
176
  self,
 
421
  return self._tap_conversation_mode
422
 
423
  def stop(self) -> None:
424
+ """Stop current TTS playback (e.g., user said stop word)."""
425
  self.state.active_wake_words.discard(self.state.stop_word.id)
426
  self.state.tts_player.stop()
427
 
 
431
  else:
432
  _LOGGER.debug("TTS response stopped manually")
433
 
434
+ # Send announce finished to HA
435
+ self.send_messages([VoiceAssistantAnnounceFinished()])
436
+ # Note: RUN_END event will handle the rest
437
 
438
  def play_tts(self) -> None:
439
  if (not self._tts_url) or self._tts_played:
 
458
  self.state.music_player.resume_sendspin()
459
 
460
  def _tts_finished(self) -> None:
461
+ """Called when TTS audio playback finishes.
462
+
463
+ Note: This is called from the audio player callback, NOT from HA events.
464
+ We should NOT start a new conversation here - wait for RUN_END event.
465
+ """
466
  self.state.active_wake_words.discard(self.state.stop_word.id)
467
  self.send_messages([VoiceAssistantAnnounceFinished()])
468
+ _LOGGER.debug("TTS playback finished, waiting for RUN_END event")
469
 
470
+ def _handle_run_end(self) -> None:
471
+ """Handle pipeline RUN_END event - safe point to continue conversation.
472
+
473
+ This is called after HA has fully completed the pipeline run.
474
+ """
475
  # Check if should continue conversation
476
  # 1. HA requested continue (continue_conversation=1 in INTENT_END)
477
  # 2. Tap conversation mode is active (user tapped to start continuous mode)
 
498
  else:
499
  # Conversation ended, clear state
500
  self._clear_conversation()
 
501
  self.unduck()
502
+ _LOGGER.debug("Pipeline ended, conversation finished")
503
  # Reachy Mini: Return to idle
504
  self._reachy_on_idle()
505