@@ -48,6 +48,7 @@ Application::Application() {
4848 .skip_unhandled_events = true
4949 };
5050 esp_timer_create (&clock_timer_args, &clock_timer_handle_);
51+ esp_timer_start_periodic (clock_timer_handle_, 1000000 );
5152}
5253
5354Application::~Application () {
@@ -81,58 +82,49 @@ void Application::CheckNewVersion() {
8182
8283 if (ota_.HasNewVersion ()) {
8384 Alert (Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, " happy" , Lang::Sounds::P3_UPGRADE);
84- // Wait for the chat state to be idle
85- do {
86- vTaskDelay (pdMS_TO_TICKS (3000 ));
87- } while (GetDeviceState () != kDeviceStateIdle );
88-
89- // Use main task to do the upgrade, not cancelable
90- Schedule ([this , display]() {
91- SetDeviceState (kDeviceStateUpgrading );
92-
93- display->SetIcon (FONT_AWESOME_DOWNLOAD);
94- std::string message = std::string (Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion ();
95- display->SetChatMessage (" system" , message.c_str ());
9685
97- auto & board = Board::GetInstance ();
98- board.SetPowerSaveMode (false );
99- #if CONFIG_USE_WAKE_WORD_DETECT
100- wake_word_detect_.StopDetection ();
101- #endif
102- // 预先关闭音频输出,避免升级过程有音频操作
103- auto codec = board.GetAudioCodec ();
104- codec->EnableInput (false );
105- codec->EnableOutput (false );
106- {
107- std::lock_guard<std::mutex> lock (mutex_);
108- audio_decode_queue_.clear ();
109- }
110- background_task_->WaitForCompletion ();
111- delete background_task_;
112- background_task_ = nullptr ;
113- vTaskDelay (pdMS_TO_TICKS (1000 ));
86+ vTaskDelay (pdMS_TO_TICKS (3000 ));
11487
115- ota_. StartUpgrade ([display]( int progress, size_t speed) {
116- char buffer[ 64 ];
117- snprintf (buffer, sizeof (buffer), " %d%% %zuKB/s " , progress, speed / 1024 );
118- display-> SetChatMessage ( " system " , buffer );
119- } );
88+ SetDeviceState ( kDeviceStateUpgrading );
89+
90+ display-> SetIcon (FONT_AWESOME_DOWNLOAD );
91+ std::string message = std::string (Lang::Strings::NEW_VERSION) + ota_. GetFirmwareVersion ( );
92+ display-> SetChatMessage ( " system " , message. c_str () );
12093
121- // If upgrade success, the device will reboot and never reach here
122- display->SetStatus (Lang::Strings::UPGRADE_FAILED);
123- ESP_LOGI (TAG, " Firmware upgrade failed..." );
124- vTaskDelay (pdMS_TO_TICKS (3000 ));
125- Reboot ();
94+ auto & board = Board::GetInstance ();
95+ board.SetPowerSaveMode (false );
96+ #if CONFIG_USE_WAKE_WORD_DETECT
97+ wake_word_detect_.StopDetection ();
98+ #endif
99+ // 预先关闭音频输出,避免升级过程有音频操作
100+ auto codec = board.GetAudioCodec ();
101+ codec->EnableInput (false );
102+ codec->EnableOutput (false );
103+ {
104+ std::lock_guard<std::mutex> lock (mutex_);
105+ audio_decode_queue_.clear ();
106+ }
107+ background_task_->WaitForCompletion ();
108+ delete background_task_;
109+ background_task_ = nullptr ;
110+ vTaskDelay (pdMS_TO_TICKS (1000 ));
111+
112+ ota_.StartUpgrade ([display](int progress, size_t speed) {
113+ char buffer[64 ];
114+ snprintf (buffer, sizeof (buffer), " %d%% %zuKB/s" , progress, speed / 1024 );
115+ display->SetChatMessage (" system" , buffer);
126116 });
127117
118+ // If upgrade success, the device will reboot and never reach here
119+ display->SetStatus (Lang::Strings::UPGRADE_FAILED);
120+ ESP_LOGI (TAG, " Firmware upgrade failed..." );
121+ vTaskDelay (pdMS_TO_TICKS (3000 ));
122+ Reboot ();
128123 return ;
129124 }
130125
131126 // No new version, mark the current version as valid
132127 ota_.MarkCurrentVersionValid ();
133- std::string message = std::string (Lang::Strings::VERSION) + ota_.GetCurrentVersion ();
134- display->ShowNotification (message.c_str ());
135-
136128 if (ota_.HasActivationCode ()) {
137129 // Activation code is valid
138130 SetDeviceState (kDeviceStateActivating );
@@ -148,11 +140,8 @@ void Application::CheckNewVersion() {
148140 continue ;
149141 }
150142
151- SetDeviceState (kDeviceStateIdle );
152- display->SetChatMessage (" system" , " " );
153- ResetDecoder ();
154- PlaySound (Lang::Sounds::P3_SUCCESS);
155- // Exit the loop if upgrade or idle
143+ xEventGroupSetBits (event_group_, CHECK_NEW_VERSION_DONE_EVENT);
144+ // Exit the loop if done checking new version
156145 break ;
157146 }
158147}
@@ -180,8 +169,6 @@ void Application::ShowActivationCode() {
180169
181170 // This sentence uses 9KB of SRAM, so we need to wait for it to finish
182171 Alert (Lang::Strings::ACTIVATION, message.c_str (), " happy" , Lang::Sounds::P3_ACTIVATION);
183- vTaskDelay (pdMS_TO_TICKS (1000 ));
184- background_task_->WaitForCompletion ();
185172
186173 for (const auto & digit : code) {
187174 auto it = std::find_if (digit_sounds.begin (), digit_sounds.end (),
@@ -214,6 +201,15 @@ void Application::DismissAlert() {
214201}
215202
216203void Application::PlaySound (const std::string_view& sound) {
204+ // Wait for the previous sound to finish
205+ {
206+ std::unique_lock<std::mutex> lock (mutex_);
207+ audio_decode_cv_.wait (lock, [this ]() {
208+ return audio_decode_queue_.empty ();
209+ });
210+ }
211+ background_task_->WaitForCompletion ();
212+
217213 // The assets are encoded at 16000Hz, 60ms frame duration
218214 SetDecodeSampleRate (16000 , 60 );
219215 const char * data = sound.data ();
@@ -295,6 +291,16 @@ void Application::StartListening() {
295291}
296292
297293void Application::StopListening () {
294+ const std::array<int , 3 > valid_states = {
295+ kDeviceStateListening ,
296+ kDeviceStateSpeaking ,
297+ kDeviceStateIdle ,
298+ };
299+ // If not valid, do nothing
300+ if (std::find (valid_states.begin (), valid_states.end (), device_state_) == valid_states.end ()) {
301+ return ;
302+ }
303+
298304 Schedule ([this ]() {
299305 if (device_state_ == kDeviceStateListening ) {
300306 protocol_->SendStopListening ();
@@ -337,16 +343,13 @@ void Application::Start() {
337343 vTaskDelete (NULL );
338344 }, " audio_loop" , 4096 * 2 , this , 8 , &audio_loop_task_handle_, realtime_chat_enabled_ ? 1 : 0 );
339345
340- /* Start the main loop */
341- xTaskCreatePinnedToCore ([](void * arg) {
342- Application* app = (Application*)arg;
343- app->MainLoop ();
344- vTaskDelete (NULL );
345- }, " main_loop" , 4096 * 2 , this , 4 , &main_loop_task_handle_, 0 );
346-
347346 /* Wait for the network to be ready */
348347 board.StartNetwork ();
349348
349+ // Check for new firmware version or get the MQTT broker address
350+ display->SetStatus (Lang::Strings::CHECKING_NEW_VERSION);
351+ CheckNewVersion ();
352+
350353 // Initialize the protocol
351354 display->SetStatus (Lang::Strings::LOADING_PROTOCOL);
352355#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
@@ -444,13 +447,6 @@ void Application::Start() {
444447 });
445448 protocol_->Start ();
446449
447- // Check for new firmware version or get the MQTT broker address
448- xTaskCreate ([](void * arg) {
449- Application* app = (Application*)arg;
450- app->CheckNewVersion ();
451- vTaskDelete (NULL );
452- }, " check_new_version" , 4096 * 2 , this , 2 , nullptr );
453-
454450#if CONFIG_USE_AUDIO_PROCESSOR
455451 audio_processor_.Initialize (codec, realtime_chat_enabled_);
456452 audio_processor_.OnOutput ([this ](std::vector<int16_t >&& data) {
@@ -509,15 +505,18 @@ void Application::Start() {
509505 wake_word_detect_.StartDetection ();
510506#endif
511507
508+ // Wait for the new version check to finish
509+ xEventGroupWaitBits (event_group_, CHECK_NEW_VERSION_DONE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
512510 SetDeviceState (kDeviceStateIdle );
513- esp_timer_start_periodic (clock_timer_handle_, 1000000 );
514-
515- #if 0
516- while (true) {
517- SystemInfo::PrintRealTimeStats(pdMS_TO_TICKS(1000));
518- vTaskDelay(pdMS_TO_TICKS(10000));
519- }
520- #endif
511+ std::string message = std::string (Lang::Strings::VERSION) + ota_.GetCurrentVersion ();
512+ display->ShowNotification (message.c_str ());
513+ display->SetChatMessage (" system" , " " );
514+ // Play the success sound to indicate the device is ready
515+ ResetDecoder ();
516+ PlaySound (Lang::Sounds::P3_SUCCESS);
517+
518+ // Enter the main event loop
519+ MainEventLoop ();
521520}
522521
523522void Application::OnClockTimer () {
@@ -553,10 +552,10 @@ void Application::Schedule(std::function<void()> callback) {
553552 xEventGroupSetBits (event_group_, SCHEDULE_EVENT);
554553}
555554
556- // The Main Loop controls the chat state and websocket connection
555+ // The Main Event Loop controls the chat state and websocket connection
557556// If other tasks need to access the websocket or chat state,
558557// they should use Schedule to call this function
559- void Application::MainLoop () {
558+ void Application::MainEventLoop () {
560559 while (true ) {
561560 auto bits = xEventGroupWaitBits (event_group_, SCHEDULE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
562561
@@ -601,12 +600,14 @@ void Application::OnAudioOutput() {
601600
602601 if (device_state_ == kDeviceStateListening ) {
603602 audio_decode_queue_.clear ();
603+ audio_decode_cv_.notify_all ();
604604 return ;
605605 }
606606
607607 auto opus = std::move (audio_decode_queue_.front ());
608608 audio_decode_queue_.pop_front ();
609609 lock.unlock ();
610+ audio_decode_cv_.notify_all ();
610611
611612 background_task_->Schedule ([this , codec, opus = std::move (opus)]() mutable {
612613 if (aborted_) {
@@ -630,23 +631,24 @@ void Application::OnAudioOutput() {
630631}
631632
632633void Application::OnAudioInput () {
633- std::vector<int16_t > data;
634-
635634#if CONFIG_USE_WAKE_WORD_DETECT
636635 if (wake_word_detect_.IsDetectionRunning ()) {
636+ std::vector<int16_t > data;
637637 ReadAudio (data, 16000 , wake_word_detect_.GetFeedSize ());
638638 wake_word_detect_.Feed (data);
639639 return ;
640640 }
641641#endif
642642#if CONFIG_USE_AUDIO_PROCESSOR
643643 if (audio_processor_.IsRunning ()) {
644+ std::vector<int16_t > data;
644645 ReadAudio (data, 16000 , audio_processor_.GetFeedSize ());
645646 audio_processor_.Feed (data);
646647 return ;
647648 }
648649#else
649650 if (device_state_ == kDeviceStateListening ) {
651+ std::vector<int16_t > data;
650652 ReadAudio (data, 16000 , 30 * 16000 / 1000 );
651653 background_task_->Schedule ([this , data = std::move (data)]() mutable {
652654 opus_encoder_->Encode (std::move (data), [this ](std::vector<uint8_t >&& opus) {
@@ -792,6 +794,7 @@ void Application::ResetDecoder() {
792794 std::lock_guard<std::mutex> lock (mutex_);
793795 opus_decoder_->ResetState ();
794796 audio_decode_queue_.clear ();
797+ audio_decode_cv_.notify_all ();
795798 last_output_time_ = std::chrono::steady_clock::now ();
796799
797800 auto codec = Board::GetInstance ().GetAudioCodec ();
0 commit comments