forked from xiaozhi/xiaozhi-esp32
将项目版本更新至1.5.9,优化内存使用,增加主任务栈大小至8192,优化固件升级流程,重构主循环为MainEventLoop,添加新版本检查功能,更新音频编解码器的DMA配置常量。
This commit is contained in:
@@ -48,6 +48,7 @@ Application::Application() {
|
||||
.skip_unhandled_events = true
|
||||
};
|
||||
esp_timer_create(&clock_timer_args, &clock_timer_handle_);
|
||||
esp_timer_start_periodic(clock_timer_handle_, 1000000);
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
@@ -81,58 +82,49 @@ void Application::CheckNewVersion() {
|
||||
|
||||
if (ota_.HasNewVersion()) {
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
|
||||
// Wait for the chat state to be idle
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
} while (GetDeviceState() != kDeviceStateIdle);
|
||||
|
||||
// Use main task to do the upgrade, not cancelable
|
||||
Schedule([this, display]() {
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion();
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
|
||||
auto& board = Board::GetInstance();
|
||||
board.SetPowerSaveMode(false);
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion();
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
|
||||
auto& board = Board::GetInstance();
|
||||
board.SetPowerSaveMode(false);
|
||||
#if CONFIG_USE_WAKE_WORD_DETECT
|
||||
wake_word_detect_.StopDetection();
|
||||
wake_word_detect_.StopDetection();
|
||||
#endif
|
||||
// 预先关闭音频输出,避免升级过程有音频操作
|
||||
auto codec = board.GetAudioCodec();
|
||||
codec->EnableInput(false);
|
||||
codec->EnableOutput(false);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
audio_decode_queue_.clear();
|
||||
}
|
||||
background_task_->WaitForCompletion();
|
||||
delete background_task_;
|
||||
background_task_ = nullptr;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
// 预先关闭音频输出,避免升级过程有音频操作
|
||||
auto codec = board.GetAudioCodec();
|
||||
codec->EnableInput(false);
|
||||
codec->EnableOutput(false);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
audio_decode_queue_.clear();
|
||||
}
|
||||
background_task_->WaitForCompletion();
|
||||
delete background_task_;
|
||||
background_task_ = nullptr;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
ota_.StartUpgrade([display](int progress, size_t speed) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
|
||||
display->SetChatMessage("system", buffer);
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
display->SetStatus(Lang::Strings::UPGRADE_FAILED);
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
Reboot();
|
||||
ota_.StartUpgrade([display](int progress, size_t speed) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
|
||||
display->SetChatMessage("system", buffer);
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
display->SetStatus(Lang::Strings::UPGRADE_FAILED);
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
Reboot();
|
||||
return;
|
||||
}
|
||||
|
||||
// No new version, mark the current version as valid
|
||||
ota_.MarkCurrentVersionValid();
|
||||
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion();
|
||||
display->ShowNotification(message.c_str());
|
||||
|
||||
if (ota_.HasActivationCode()) {
|
||||
// Activation code is valid
|
||||
SetDeviceState(kDeviceStateActivating);
|
||||
@@ -148,11 +140,8 @@ void Application::CheckNewVersion() {
|
||||
continue;
|
||||
}
|
||||
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
display->SetChatMessage("system", "");
|
||||
ResetDecoder();
|
||||
PlaySound(Lang::Sounds::P3_SUCCESS);
|
||||
// Exit the loop if upgrade or idle
|
||||
xEventGroupSetBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT);
|
||||
// Exit the loop if done checking new version
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -180,8 +169,6 @@ void Application::ShowActivationCode() {
|
||||
|
||||
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
|
||||
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::P3_ACTIVATION);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
background_task_->WaitForCompletion();
|
||||
|
||||
for (const auto& digit : code) {
|
||||
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
|
||||
@@ -214,6 +201,15 @@ void Application::DismissAlert() {
|
||||
}
|
||||
|
||||
void Application::PlaySound(const std::string_view& sound) {
|
||||
// Wait for the previous sound to finish
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
audio_decode_cv_.wait(lock, [this]() {
|
||||
return audio_decode_queue_.empty();
|
||||
});
|
||||
}
|
||||
background_task_->WaitForCompletion();
|
||||
|
||||
// The assets are encoded at 16000Hz, 60ms frame duration
|
||||
SetDecodeSampleRate(16000, 60);
|
||||
const char* data = sound.data();
|
||||
@@ -295,6 +291,16 @@ void Application::StartListening() {
|
||||
}
|
||||
|
||||
void Application::StopListening() {
|
||||
const std::array<int, 3> valid_states = {
|
||||
kDeviceStateListening,
|
||||
kDeviceStateSpeaking,
|
||||
kDeviceStateIdle,
|
||||
};
|
||||
// If not valid, do nothing
|
||||
if (std::find(valid_states.begin(), valid_states.end(), device_state_) == valid_states.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule([this]() {
|
||||
if (device_state_ == kDeviceStateListening) {
|
||||
protocol_->SendStopListening();
|
||||
@@ -337,16 +343,13 @@ void Application::Start() {
|
||||
vTaskDelete(NULL);
|
||||
}, "audio_loop", 4096 * 2, this, 8, &audio_loop_task_handle_, realtime_chat_enabled_ ? 1 : 0);
|
||||
|
||||
/* Start the main loop */
|
||||
xTaskCreatePinnedToCore([](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
app->MainLoop();
|
||||
vTaskDelete(NULL);
|
||||
}, "main_loop", 4096 * 2, this, 4, &main_loop_task_handle_, 0);
|
||||
|
||||
/* Wait for the network to be ready */
|
||||
board.StartNetwork();
|
||||
|
||||
// Check for new firmware version or get the MQTT broker address
|
||||
display->SetStatus(Lang::Strings::CHECKING_NEW_VERSION);
|
||||
CheckNewVersion();
|
||||
|
||||
// Initialize the protocol
|
||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
||||
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
|
||||
@@ -444,13 +447,6 @@ void Application::Start() {
|
||||
});
|
||||
protocol_->Start();
|
||||
|
||||
// Check for new firmware version or get the MQTT broker address
|
||||
xTaskCreate([](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
app->CheckNewVersion();
|
||||
vTaskDelete(NULL);
|
||||
}, "check_new_version", 4096 * 2, this, 2, nullptr);
|
||||
|
||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||
audio_processor_.Initialize(codec, realtime_chat_enabled_);
|
||||
audio_processor_.OnOutput([this](std::vector<int16_t>&& data) {
|
||||
@@ -509,15 +505,18 @@ void Application::Start() {
|
||||
wake_word_detect_.StartDetection();
|
||||
#endif
|
||||
|
||||
// Wait for the new version check to finish
|
||||
xEventGroupWaitBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
esp_timer_start_periodic(clock_timer_handle_, 1000000);
|
||||
|
||||
#if 0
|
||||
while (true) {
|
||||
SystemInfo::PrintRealTimeStats(pdMS_TO_TICKS(1000));
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
}
|
||||
#endif
|
||||
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion();
|
||||
display->ShowNotification(message.c_str());
|
||||
display->SetChatMessage("system", "");
|
||||
// Play the success sound to indicate the device is ready
|
||||
ResetDecoder();
|
||||
PlaySound(Lang::Sounds::P3_SUCCESS);
|
||||
|
||||
// Enter the main event loop
|
||||
MainEventLoop();
|
||||
}
|
||||
|
||||
void Application::OnClockTimer() {
|
||||
@@ -553,10 +552,10 @@ void Application::Schedule(std::function<void()> callback) {
|
||||
xEventGroupSetBits(event_group_, SCHEDULE_EVENT);
|
||||
}
|
||||
|
||||
// The Main Loop controls the chat state and websocket connection
|
||||
// The Main Event Loop controls the chat state and websocket connection
|
||||
// If other tasks need to access the websocket or chat state,
|
||||
// they should use Schedule to call this function
|
||||
void Application::MainLoop() {
|
||||
void Application::MainEventLoop() {
|
||||
while (true) {
|
||||
auto bits = xEventGroupWaitBits(event_group_, SCHEDULE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
@@ -601,12 +600,14 @@ void Application::OnAudioOutput() {
|
||||
|
||||
if (device_state_ == kDeviceStateListening) {
|
||||
audio_decode_queue_.clear();
|
||||
audio_decode_cv_.notify_all();
|
||||
return;
|
||||
}
|
||||
|
||||
auto opus = std::move(audio_decode_queue_.front());
|
||||
audio_decode_queue_.pop_front();
|
||||
lock.unlock();
|
||||
audio_decode_cv_.notify_all();
|
||||
|
||||
background_task_->Schedule([this, codec, opus = std::move(opus)]() mutable {
|
||||
if (aborted_) {
|
||||
@@ -630,10 +631,9 @@ void Application::OnAudioOutput() {
|
||||
}
|
||||
|
||||
void Application::OnAudioInput() {
|
||||
std::vector<int16_t> data;
|
||||
|
||||
#if CONFIG_USE_WAKE_WORD_DETECT
|
||||
if (wake_word_detect_.IsDetectionRunning()) {
|
||||
std::vector<int16_t> data;
|
||||
ReadAudio(data, 16000, wake_word_detect_.GetFeedSize());
|
||||
wake_word_detect_.Feed(data);
|
||||
return;
|
||||
@@ -641,12 +641,14 @@ void Application::OnAudioInput() {
|
||||
#endif
|
||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||
if (audio_processor_.IsRunning()) {
|
||||
std::vector<int16_t> data;
|
||||
ReadAudio(data, 16000, audio_processor_.GetFeedSize());
|
||||
audio_processor_.Feed(data);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (device_state_ == kDeviceStateListening) {
|
||||
std::vector<int16_t> data;
|
||||
ReadAudio(data, 16000, 30 * 16000 / 1000);
|
||||
background_task_->Schedule([this, data = std::move(data)]() mutable {
|
||||
opus_encoder_->Encode(std::move(data), [this](std::vector<uint8_t>&& opus) {
|
||||
@@ -792,6 +794,7 @@ void Application::ResetDecoder() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
opus_decoder_->ResetState();
|
||||
audio_decode_queue_.clear();
|
||||
audio_decode_cv_.notify_all();
|
||||
last_output_time_ = std::chrono::steady_clock::now();
|
||||
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
|
||||
Reference in New Issue
Block a user