diff --git a/main/application.cc b/main/application.cc index a8c30aa5..06ea456c 100644 --- a/main/application.cc +++ b/main/application.cc @@ -823,6 +823,12 @@ void Application::HandleStateChangedEvent() { // Make sure the audio processor is running if (!audio_service_.IsAudioProcessorRunning()) { + // For auto mode, wait for playback queue to be empty before enabling voice processing + // This prevents audio truncation when STOP arrives late due to network jitter + if (listening_mode_ == kListeningModeAutoStop) { + audio_service_.WaitForPlaybackQueueEmpty(); + } + // Send the start listening command protocol_->SendStartListening(listening_mode_); audio_service_.EnableVoiceProcessing(true); diff --git a/main/audio/audio_service.cc b/main/audio/audio_service.cc index 408eb839..0cb1c345 100644 --- a/main/audio/audio_service.cc +++ b/main/audio/audio_service.cc @@ -740,6 +740,13 @@ bool AudioService::IsIdle() { return audio_encode_queue_.empty() && audio_decode_queue_.empty() && audio_playback_queue_.empty() && audio_testing_queue_.empty(); } +void AudioService::WaitForPlaybackQueueEmpty() { + std::unique_lock lock(audio_queue_mutex_); + audio_queue_cv_.wait(lock, [this]() { + return service_stopped_ || (audio_decode_queue_.empty() && audio_playback_queue_.empty()); + }); +} + void AudioService::ResetDecoder() { std::lock_guard lock(audio_queue_mutex_); std::unique_lock decoder_lock(decoder_mutex_); diff --git a/main/audio/audio_service.h b/main/audio/audio_service.h index a2af18e8..79783b0e 100644 --- a/main/audio/audio_service.h +++ b/main/audio/audio_service.h @@ -115,6 +115,7 @@ public: const std::string& GetLastWakeWord() const; bool IsVoiceDetected() const { return voice_detected_; } bool IsIdle(); + void WaitForPlaybackQueueEmpty(); bool IsWakeWordRunning() const { return xEventGroupGetBits(event_group_) & AS_EVENT_WAKE_WORD_RUNNING; } bool IsAudioProcessorRunning() const { return xEventGroupGetBits(event_group_) & AS_EVENT_AUDIO_PROCESSOR_RUNNING; } bool IsAfeWakeWord();