| | |
| | | #include "audio_service.h" |
| | | #include <esp_log.h> |
| | | #include <cstring> |
| | | #include <chrono> |
| | | |
| | | #define RATE_CVT_CFG(_src_rate, _dest_rate, _channel) \ |
| | | (esp_ae_rate_cvt_cfg_t) \ |
| | |
| | | return; |
| | | } |
| | | |
| | | const bool running = IsWakeWordRunning(); |
| | | if (enable == running && (!enable || wake_word_initialized_)) { |
| | | return; |
| | | } |
| | | |
| | | ESP_LOGD(TAG, "%s wake word detection", enable ? "Enabling" : "Disabling"); |
| | | if (enable) { |
| | | if (!wake_word_initialized_) { |
| | |
| | | wake_word_->Stop(); |
| | | xEventGroupClearBits(event_group_, AS_EVENT_WAKE_WORD_RUNNING); |
| | | } |
| | | } |
| | | |
| | | void AudioService::EnsureVoiceProcessorReady() { |
| | | if (audio_processor_initialized_ || audio_processor_ == nullptr) { |
| | | return; |
| | | } |
| | | ESP_LOGI(TAG, "Preload voice processor"); |
| | | audio_processor_->Initialize(codec_, OPUS_FRAME_DURATION_MS, models_list_); |
| | | audio_processor_initialized_ = true; |
| | | } |
| | | |
| | | void AudioService::EnableVoiceProcessing(bool enable) { |
| | |
| | | |
| | | void AudioService::WaitForPlaybackQueueEmpty() { |
| | | std::unique_lock<std::mutex> lock(audio_queue_mutex_); |
| | | audio_queue_cv_.wait(lock, [this]() { |
| | | return service_stopped_ || (audio_decode_queue_.empty() && audio_playback_queue_.empty()); |
| | | audio_queue_cv_.wait_for(lock, std::chrono::milliseconds(5000), [this]() { |
| | | return service_stopped_ || (audio_decode_queue_.empty() && audio_playback_queue_.empty()); |
| | | }); |
| | | } |
| | | |
| | | bool AudioService::IsPlaybackQueueEmpty() { |
| | | std::lock_guard<std::mutex> lock(audio_queue_mutex_); |
| | | return audio_decode_queue_.empty() && audio_playback_queue_.empty(); |
| | | } |
| | | |
| | | void AudioService::ResetDecoder() { |
| | |
| | | audio_queue_cv_.notify_all(); |
| | | } |
| | | |
| | | void AudioService::KeepCodecReadyForPlayback() { |
| | | last_output_time_ = std::chrono::steady_clock::now(); |
| | | last_input_time_ = std::chrono::steady_clock::now(); |
| | | if (codec_ == nullptr) { |
| | | return; |
| | | } |
| | | if (!codec_->output_enabled()) { |
| | | esp_timer_stop(audio_power_timer_); |
| | | esp_timer_start_periodic(audio_power_timer_, AUDIO_POWER_CHECK_INTERVAL_MS * 1000); |
| | | codec_->EnableOutput(true); |
| | | } |
| | | } |
| | | |
| | | void AudioService::SetAudioPowerInhibit(bool inhibit) { |
| | | audio_power_inhibit_ = inhibit; |
| | | if (inhibit) { |
| | | KeepCodecReadyForPlayback(); |
| | | } |
| | | } |
| | | |
| | | void AudioService::CheckAndUpdateAudioPowerState() { |
| | | if (audio_power_inhibit_) { |
| | | last_input_time_ = std::chrono::steady_clock::now(); |
| | | last_output_time_ = last_input_time_; |
| | | return; |
| | | } |
| | | auto now = std::chrono::steady_clock::now(); |
| | | auto input_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_input_time_).count(); |
| | | auto output_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_output_time_).count(); |