Skip to content

Commit e9de526

Browse files
authored
Merge pull request #20 from 78/ui
v0.9.2
2 parents 2d7a127 + ff28586 commit e9de526

25 files changed

+244
-115
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# CMakeLists in this exact order for cmake to work correctly
55
cmake_minimum_required(VERSION 3.16)
66

7-
set(PROJECT_VER "0.9.1")
7+
set(PROJECT_VER "0.9.2")
88

99
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
1010
project(xiaozhi)

main/application.cc

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,52 @@ void Application::ToggleChatState() {
123123
Schedule([this]() {
124124
if (chat_state_ == kChatStateIdle) {
125125
SetChatState(kChatStateConnecting);
126-
if (protocol_->OpenAudioChannel()) {
127-
opus_encoder_.ResetState();
128-
SetChatState(kChatStateListening);
129-
} else {
126+
if (!protocol_->OpenAudioChannel()) {
127+
ESP_LOGE(TAG, "Failed to open audio channel");
130128
SetChatState(kChatStateIdle);
129+
return;
131130
}
131+
132+
keep_listening_ = true;
133+
protocol_->SendStartListening(kListeningModeAutoStop);
134+
SetChatState(kChatStateListening);
132135
} else if (chat_state_ == kChatStateSpeaking) {
133-
AbortSpeaking();
136+
AbortSpeaking(kAbortReasonNone);
134137
} else if (chat_state_ == kChatStateListening) {
135138
protocol_->CloseAudioChannel();
136139
}
137140
});
138141
}
139142

143+
void Application::StartListening() {
144+
Schedule([this]() {
145+
keep_listening_ = false;
146+
if (chat_state_ == kChatStateIdle) {
147+
if (!protocol_->IsAudioChannelOpened()) {
148+
SetChatState(kChatStateConnecting);
149+
if (!protocol_->OpenAudioChannel()) {
150+
SetChatState(kChatStateIdle);
151+
ESP_LOGE(TAG, "Failed to open audio channel");
152+
return;
153+
}
154+
}
155+
protocol_->SendStartListening(kListeningModeManualStop);
156+
SetChatState(kChatStateListening);
157+
} else if (chat_state_ == kChatStateSpeaking) {
158+
AbortSpeaking(kAbortReasonNone);
159+
protocol_->SendStartListening(kListeningModeManualStop);
160+
SetChatState(kChatStateListening);
161+
}
162+
});
163+
}
164+
165+
void Application::StopListening() {
166+
Schedule([this]() {
167+
protocol_->SendStopListening();
168+
SetChatState(kChatStateIdle);
169+
});
170+
}
171+
140172
void Application::Start() {
141173
auto& board = Board::GetInstance();
142174
board.Initialize();
@@ -248,26 +280,31 @@ void Application::Start() {
248280
});
249281
});
250282

251-
wake_word_detect_.OnWakeWordDetected([this]() {
252-
Schedule([this]() {
283+
wake_word_detect_.OnWakeWordDetected([this](const std::string& wake_word) {
284+
Schedule([this, &wake_word]() {
253285
if (chat_state_ == kChatStateIdle) {
254286
SetChatState(kChatStateConnecting);
255287
wake_word_detect_.EncodeWakeWordData();
256288

257-
if (protocol_->OpenAudioChannel()) {
258-
std::string opus;
259-
// Encode and send the wake word data to the server
260-
while (wake_word_detect_.GetWakeWordOpus(opus)) {
261-
protocol_->SendAudio(opus);
262-
}
263-
opus_encoder_.ResetState();
264-
// Send a ready message to indicate the server that the wake word data is sent
265-
SetChatState(kChatStateWakeWordDetected);
266-
} else {
289+
if (!protocol_->OpenAudioChannel()) {
290+
ESP_LOGE(TAG, "Failed to open audio channel");
267291
SetChatState(kChatStateIdle);
292+
wake_word_detect_.StartDetection();
293+
return;
268294
}
295+
296+
std::string opus;
297+
// Encode and send the wake word data to the server
298+
while (wake_word_detect_.GetWakeWordOpus(opus)) {
299+
protocol_->SendAudio(opus);
300+
}
301+
// Set the chat state to wake word detected
302+
protocol_->SendWakeWordDetected(wake_word);
303+
ESP_LOGI(TAG, "Wake word detected: %s", wake_word.c_str());
304+
keep_listening_ = true;
305+
SetChatState(kChatStateListening);
269306
} else if (chat_state_ == kChatStateSpeaking) {
270-
AbortSpeaking();
307+
AbortSpeaking(kAbortReasonWakeWordDetected);
271308
}
272309

273310
// Resume detection
@@ -313,15 +350,23 @@ void Application::Start() {
313350
auto state = cJSON_GetObjectItem(root, "state");
314351
if (strcmp(state->valuestring, "start") == 0) {
315352
Schedule([this]() {
316-
skip_to_end_ = false;
317-
SetChatState(kChatStateSpeaking);
353+
if (chat_state_ == kChatStateIdle || chat_state_ == kChatStateListening) {
354+
skip_to_end_ = false;
355+
opus_decoder_ctl(opus_decoder_, OPUS_RESET_STATE);
356+
SetChatState(kChatStateSpeaking);
357+
}
318358
});
319359
} else if (strcmp(state->valuestring, "stop") == 0) {
320360
Schedule([this]() {
321361
auto codec = Board::GetInstance().GetAudioCodec();
322362
codec->WaitForOutputDone();
323363
if (chat_state_ == kChatStateSpeaking) {
324-
SetChatState(kChatStateListening);
364+
if (keep_listening_) {
365+
protocol_->SendStartListening(kListeningModeAutoStop);
366+
SetChatState(kChatStateListening);
367+
} else {
368+
SetChatState(kChatStateIdle);
369+
}
325370
}
326371
});
327372
} else if (strcmp(state->valuestring, "sentence_start") == 0) {
@@ -375,9 +420,9 @@ void Application::MainLoop() {
375420
}
376421
}
377422

378-
void Application::AbortSpeaking() {
423+
void Application::AbortSpeaking(AbortReason reason) {
379424
ESP_LOGI(TAG, "Abort speaking");
380-
protocol_->SendAbort();
425+
protocol_->SendAbortSpeaking(reason);
381426

382427
skip_to_end_ = true;
383428
auto codec = Board::GetInstance().GetAudioCodec();
@@ -391,20 +436,17 @@ void Application::SetChatState(ChatState state) {
391436
"connecting",
392437
"listening",
393438
"speaking",
394-
"wake_word_detected",
395439
"upgrading",
396440
"invalid_state"
397441
};
398442
if (chat_state_ == state) {
399443
// No need to update the state
400444
return;
401445
}
402-
chat_state_ = state;
403-
ESP_LOGI(TAG, "STATE: %s", state_str[chat_state_]);
404446

405447
auto display = Board::GetInstance().GetDisplay();
406448
auto builtin_led = Board::GetInstance().GetBuiltinLed();
407-
switch (chat_state_) {
449+
switch (state) {
408450
case kChatStateUnknown:
409451
case kChatStateIdle:
410452
builtin_led->TurnOff();
@@ -424,6 +466,7 @@ void Application::SetChatState(ChatState state) {
424466
builtin_led->TurnOn();
425467
display->SetStatus("聆听中...");
426468
display->SetEmotion("neutral");
469+
opus_encoder_.ResetState();
427470
#ifdef CONFIG_USE_AFE_SR
428471
audio_processor_.Start();
429472
#endif
@@ -436,17 +479,17 @@ void Application::SetChatState(ChatState state) {
436479
audio_processor_.Stop();
437480
#endif
438481
break;
439-
case kChatStateWakeWordDetected:
440-
builtin_led->SetBlue();
441-
builtin_led->TurnOn();
442-
break;
443482
case kChatStateUpgrading:
444483
builtin_led->SetGreen();
445484
builtin_led->StartContinuousBlink(100);
446485
break;
486+
default:
487+
ESP_LOGE(TAG, "Invalid chat state: %d", chat_state_);
488+
return;
447489
}
448490

449-
protocol_->SendState(state_str[chat_state_]);
491+
chat_state_ = state;
492+
ESP_LOGI(TAG, "STATE: %s", state_str[chat_state_]);
450493
}
451494

452495
void Application::AudioEncodeTask() {

main/application.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ enum ChatState {
2929
kChatStateConnecting,
3030
kChatStateListening,
3131
kChatStateSpeaking,
32-
kChatStateWakeWordDetected,
3332
kChatStateUpgrading
3433
};
3534

@@ -41,17 +40,19 @@ class Application {
4140
static Application instance;
4241
return instance;
4342
}
43+
// 删除拷贝构造函数和赋值运算符
44+
Application(const Application&) = delete;
45+
Application& operator=(const Application&) = delete;
4446

4547
void Start();
4648
ChatState GetChatState() const { return chat_state_; }
4749
void Schedule(std::function<void()> callback);
4850
void SetChatState(ChatState state);
4951
void Alert(const std::string&& title, const std::string&& message);
50-
void AbortSpeaking();
52+
void AbortSpeaking(AbortReason reason);
5153
void ToggleChatState();
52-
// 删除拷贝构造函数和赋值运算符
53-
Application(const Application&) = delete;
54-
Application& operator=(const Application&) = delete;
54+
void StartListening();
55+
void StopListening();
5556

5657
private:
5758
Application();
@@ -68,6 +69,7 @@ class Application {
6869
Protocol* protocol_ = nullptr;
6970
EventGroupHandle_t event_group_;
7071
volatile ChatState chat_state_ = kChatStateUnknown;
72+
bool keep_listening_ = false;
7173
bool skip_to_end_ = false;
7274

7375
// Audio encode / decode

main/audio_codecs/no_audio_codec.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ NoAudioCodec::NoAudioCodec(int input_sample_rate, int output_sample_rate, gpio_n
6565
};
6666
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
6767
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
68-
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
69-
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
7068
ESP_LOGI(TAG, "Duplex channels created");
7169
}
7270

main/boards/bread-compact-wifi/compact_wifi_board.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "led.h"
88
#include "config.h"
99

10+
#include <wifi_station.h>
1011
#include <esp_log.h>
1112
#include <driver/i2c_master.h>
1213

@@ -38,7 +39,11 @@ class CompactWifiBoard : public WifiBoard {
3839

3940
void InitializeButtons() {
4041
boot_button_.OnClick([this]() {
41-
Application::GetInstance().ToggleChatState();
42+
auto& app = Application::GetInstance();
43+
if (app.GetChatState() == kChatStateUnknown && !WifiStation::GetInstance().IsConnected()) {
44+
ResetWifiConfiguration();
45+
}
46+
app.ToggleChatState();
4247
});
4348

4449
volume_up_button_.OnClick([this]() {

main/boards/common/button.cc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,28 @@ Button::~Button() {
3030
}
3131
}
3232

33-
void Button::OnPress(std::function<void()> callback) {
33+
void Button::OnPressDown(std::function<void()> callback) {
3434
if (button_handle_ == nullptr) {
3535
return;
3636
}
37-
on_press_ = callback;
37+
on_press_down_ = callback;
3838
iot_button_register_cb(button_handle_, BUTTON_PRESS_DOWN, [](void* handle, void* usr_data) {
3939
Button* button = static_cast<Button*>(usr_data);
40-
if (button->on_press_) {
41-
button->on_press_();
40+
if (button->on_press_down_) {
41+
button->on_press_down_();
42+
}
43+
}, this);
44+
}
45+
46+
void Button::OnPressUp(std::function<void()> callback) {
47+
if (button_handle_ == nullptr) {
48+
return;
49+
}
50+
on_press_up_ = callback;
51+
iot_button_register_cb(button_handle_, BUTTON_PRESS_UP, [](void* handle, void* usr_data) {
52+
Button* button = static_cast<Button*>(usr_data);
53+
if (button->on_press_up_) {
54+
button->on_press_up_();
4255
}
4356
}, this);
4457
}

main/boards/common/button.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ class Button {
1010
Button(gpio_num_t gpio_num);
1111
~Button();
1212

13-
void OnPress(std::function<void()> callback);
13+
void OnPressDown(std::function<void()> callback);
14+
void OnPressUp(std::function<void()> callback);
1415
void OnLongPress(std::function<void()> callback);
1516
void OnClick(std::function<void()> callback);
1617
void OnDoubleClick(std::function<void()> callback);
@@ -19,7 +20,8 @@ class Button {
1920
button_handle_t button_handle_;
2021

2122

22-
std::function<void()> on_press_;
23+
std::function<void()> on_press_down_;
24+
std::function<void()> on_press_up_;
2325
std::function<void()> on_long_press_;
2426
std::function<void()> on_click_;
2527
std::function<void()> on_double_click_;

main/boards/common/wifi_board.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "application.h"
33
#include "system_info.h"
44
#include "font_awesome_symbols.h"
5+
#include "settings.h"
56

67
#include <freertos/FreeRTOS.h>
78
#include <freertos/task.h>
@@ -149,3 +150,15 @@ void WifiBoard::SetPowerSaveMode(bool enabled) {
149150
auto& wifi_station = WifiStation::GetInstance();
150151
wifi_station.SetPowerSaveMode(enabled);
151152
}
153+
154+
void WifiBoard::ResetWifiConfiguration() {
155+
// Reset the wifi station
156+
{
157+
Settings settings("wifi", true);
158+
settings.EraseAll();
159+
}
160+
GetDisplay()->ShowNotification("已重置 WiFi...");
161+
vTaskDelay(pdMS_TO_TICKS(1000));
162+
// Reboot the device
163+
esp_restart();
164+
}

main/boards/common/wifi_board.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class WifiBoard : public Board {
1919
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
2020
virtual const char* GetNetworkStateIcon() override;
2121
virtual void SetPowerSaveMode(bool enabled) override;
22+
virtual void ResetWifiConfiguration();
2223
};
2324

2425
#endif // WIFI_BOARD_H

main/boards/kevin-box-2/axp2101.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Axp2101::Axp2101(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_
2020
WriteReg(0x64, 0x03); // CV charger voltage setting to 4.2V
2121

2222
WriteReg(0x61, 0x05); // set Main battery precharge current to 125mA
23-
WriteReg(0x62, 0x10); // set Main battery charger current to 1000mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
23+
WriteReg(0x62, 0x0A); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
2424
WriteReg(0x63, 0x15); // set Main battery term charge current to 125mA
2525

2626
WriteReg(0x14, 0x00); // set minimum system voltage to 4.1V (default 4.7V), for poor USB cables

0 commit comments

Comments
 (0)