| | |
| | | #include "audio_service.h" |
| | | #include "processors/audio_debugger.h" |
| | | #include <esp_log.h> |
| | | #include <cstring> |
| | | #include <chrono> |
| | |
| | | if (audio_input_need_warmup_) { |
| | | audio_input_need_warmup_ = false; |
| | | vTaskDelay(pdMS_TO_TICKS(120)); |
| | | if (xEventGroupGetBits(event_group_) & AS_EVENT_AUDIO_PROCESSOR_RUNNING) { |
| | | audio_processor_->Start(); |
| | | } |
| | | continue; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | void AudioService::AbortWakeWordEncode() { |
| | | if (wake_word_) { |
| | | wake_word_->AbortWakeWordEncode(); |
| | | } |
| | | } |
| | | |
| | | const std::string& AudioService::GetLastWakeWord() const { |
| | | return wake_word_->GetLastDetectedWakeWord(); |
| | | } |
| | |
| | | return; |
| | | } |
| | | wake_word_initialized_ = true; |
| | | } else if (!wake_word_->EnsureRuntime()) { |
| | | ESP_LOGE(TAG, "Failed to restore wake word runtime"); |
| | | return; |
| | | } |
| | | // Reset input resampler to clear cached data from previous mode (e.g. AudioProcessor) |
| | | // This prevents buffer overflow when switching between different feed sizes |
| | |
| | | } |
| | | } |
| | | |
| | | void AudioService::ClearWakeWordBuffers() { |
| | | if (wake_word_) { |
| | | wake_word_->ClearWakeBuffers(); |
| | | } |
| | | } |
| | | |
| | | void AudioService::ReleaseAfeRuntime() { |
| | | EnableVoiceProcessing(false); |
| | | EnableWakeWordDetection(false); |
| | | if (wake_word_) { |
| | | wake_word_->ReleaseRuntime(); |
| | | } |
| | | ReleaseVoiceProcessorRuntime(); |
| | | } |
| | | |
| | | void AudioService::ReleaseVoiceProcessorRuntime() { |
| | | EnableVoiceProcessing(false); |
| | | if (audio_processor_initialized_ && audio_processor_) { |
| | | audio_processor_->ReleaseRuntime(); |
| | | } |
| | | } |
| | | |
| | | void AudioService::EnsureVoiceProcessorReady() { |
| | | if (audio_processor_initialized_ || audio_processor_ == nullptr) { |
| | | if (audio_processor_ == nullptr) { |
| | | return; |
| | | } |
| | | ESP_LOGI(TAG, "Preload voice processor"); |
| | | audio_processor_->Initialize(codec_, OPUS_FRAME_DURATION_MS, models_list_); |
| | | audio_processor_initialized_ = true; |
| | | if (!audio_processor_initialized_) { |
| | | ESP_LOGI(TAG, "Preload voice processor"); |
| | | audio_processor_->Initialize(codec_, OPUS_FRAME_DURATION_MS, models_list_); |
| | | audio_processor_initialized_ = true; |
| | | } else if (!audio_processor_->EnsureRuntime()) { |
| | | ESP_LOGE(TAG, "Failed to restore voice processor runtime"); |
| | | } |
| | | } |
| | | |
| | | void AudioService::EnableVoiceProcessing(bool enable) { |
| | |
| | | if (!audio_processor_initialized_) { |
| | | audio_processor_->Initialize(codec_, OPUS_FRAME_DURATION_MS, models_list_); |
| | | audio_processor_initialized_ = true; |
| | | } else if (!audio_processor_->EnsureRuntime()) { |
| | | ESP_LOGE(TAG, "Failed to restore voice processor runtime"); |
| | | return; |
| | | } |
| | | |
| | | /* We should make sure no audio is playing */ |
| | |
| | | esp_ae_rate_cvt_reset(input_resampler_); |
| | | } |
| | | } |
| | | audio_processor_->Start(); |
| | | xEventGroupSetBits(event_group_, AS_EVENT_AUDIO_PROCESSOR_RUNNING); |
| | | // fetch 等 input warmup 后再 Start,避免刚进聆听就 AFE empty / Error -1 |
| | | } else { |
| | | audio_processor_->Stop(); |
| | | xEventGroupClearBits(event_group_, AS_EVENT_AUDIO_PROCESSOR_RUNNING); |