forked from xiaozhi/xiaozhi-esp32
add abort command
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
# CMakeLists in this exact order for cmake to work correctly
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(PROJECT_VER "0.6.0")
|
set(PROJECT_VER "0.6.1")
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(xiaozhi)
|
project(xiaozhi)
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ void Application::Start() {
|
|||||||
SetChatState(kChatStateIdle);
|
SetChatState(kChatStateIdle);
|
||||||
}
|
}
|
||||||
} else if (chat_state_ == kChatStateSpeaking) {
|
} else if (chat_state_ == kChatStateSpeaking) {
|
||||||
break_speaking_ = true;
|
AbortSpeaking();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resume detection
|
// Resume detection
|
||||||
@@ -272,7 +272,7 @@ void Application::Start() {
|
|||||||
SetChatState(kChatStateIdle);
|
SetChatState(kChatStateIdle);
|
||||||
}
|
}
|
||||||
} else if (chat_state_ == kChatStateSpeaking) {
|
} else if (chat_state_ == kChatStateSpeaking) {
|
||||||
break_speaking_ = true;
|
AbortSpeaking();
|
||||||
} else if (chat_state_ == kChatStateListening) {
|
} else if (chat_state_ == kChatStateListening) {
|
||||||
if (ws_client_ && ws_client_->IsConnected()) {
|
if (ws_client_ && ws_client_->IsConnected()) {
|
||||||
ws_client_->Close();
|
ws_client_->Close();
|
||||||
@@ -356,6 +356,22 @@ void Application::MainLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::AbortSpeaking() {
|
||||||
|
ESP_LOGI(TAG, "Abort speaking");
|
||||||
|
skip_to_end_ = true;
|
||||||
|
|
||||||
|
if (ws_client_ && ws_client_->IsConnected()) {
|
||||||
|
cJSON* root = cJSON_CreateObject();
|
||||||
|
cJSON_AddStringToObject(root, "type", "abort");
|
||||||
|
char* json = cJSON_PrintUnformatted(root);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
ws_client_->Send(json);
|
||||||
|
cJSON_Delete(root);
|
||||||
|
free(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::SetChatState(ChatState state) {
|
void Application::SetChatState(ChatState state) {
|
||||||
const char* state_str[] = {
|
const char* state_str[] = {
|
||||||
"unknown",
|
"unknown",
|
||||||
@@ -368,6 +384,10 @@ void Application::SetChatState(ChatState state) {
|
|||||||
"upgrading",
|
"upgrading",
|
||||||
"invalid_state"
|
"invalid_state"
|
||||||
};
|
};
|
||||||
|
if (chat_state_ == state) {
|
||||||
|
// No need to update the state
|
||||||
|
return;
|
||||||
|
}
|
||||||
chat_state_ = state;
|
chat_state_ = state;
|
||||||
ESP_LOGI(TAG, "STATE: %s", state_str[chat_state_]);
|
ESP_LOGI(TAG, "STATE: %s", state_str[chat_state_]);
|
||||||
|
|
||||||
@@ -488,16 +508,6 @@ void Application::HandleAudioPacket(AudioPacket* packet) {
|
|||||||
|
|
||||||
// This will block until the audio device has finished playing the audio
|
// This will block until the audio device has finished playing the audio
|
||||||
audio_device_->OutputData(packet->pcm);
|
audio_device_->OutputData(packet->pcm);
|
||||||
|
|
||||||
if (break_speaking_) {
|
|
||||||
skip_to_end_ = true;
|
|
||||||
|
|
||||||
// Play a silence and skip to the end
|
|
||||||
int frame_size = opus_decode_sample_rate_ / 1000 * opus_duration_ms_;
|
|
||||||
std::vector<int16_t> silence(frame_size);
|
|
||||||
bzero(silence.data(), silence.size() * sizeof(int16_t));
|
|
||||||
audio_device_->OutputData(silence);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kAudioPacketTypeStart:
|
case kAudioPacketTypeStart:
|
||||||
@@ -520,6 +530,9 @@ void Application::HandleAudioPacket(AudioPacket* packet) {
|
|||||||
ESP_LOGI(TAG, "<< %s", packet->text.c_str());
|
ESP_LOGI(TAG, "<< %s", packet->text.c_str());
|
||||||
break;
|
break;
|
||||||
case kAudioPacketTypeSentenceEnd:
|
case kAudioPacketTypeSentenceEnd:
|
||||||
|
if (break_speaking_) {
|
||||||
|
skip_to_end_ = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGI(TAG, "Unknown packet type: %d", packet->type);
|
ESP_LOGI(TAG, "Unknown packet type: %d", packet->type);
|
||||||
@@ -622,8 +635,7 @@ void Application::StartWebSocketClient() {
|
|||||||
SetDecodeSampleRate(sample_rate->valueint);
|
SetDecodeSampleRate(sample_rate->valueint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the device is speaking, we need to break the speaking
|
// If the device is speaking, we need to skip the last session
|
||||||
break_speaking_ = true;
|
|
||||||
skip_to_end_ = true;
|
skip_to_end_ = true;
|
||||||
} else if (strcmp(state->valuestring, "stop") == 0) {
|
} else if (strcmp(state->valuestring, "stop") == 0) {
|
||||||
packet->type = kAudioPacketTypeStop;
|
packet->type = kAudioPacketTypeStop;
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public:
|
|||||||
void Schedule(std::function<void()> callback);
|
void Schedule(std::function<void()> callback);
|
||||||
void SetChatState(ChatState state);
|
void SetChatState(ChatState state);
|
||||||
void Alert(const std::string&& title, const std::string&& message);
|
void Alert(const std::string&& title, const std::string&& message);
|
||||||
|
void AbortSpeaking();
|
||||||
// 删除拷贝构造函数和赋值运算符
|
// 删除拷贝构造函数和赋值运算符
|
||||||
Application(const Application&) = delete;
|
Application(const Application&) = delete;
|
||||||
Application& operator=(const Application&) = delete;
|
Application& operator=(const Application&) = delete;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ void AudioDevice::CreateSimplexChannels() {
|
|||||||
.role = I2S_ROLE_MASTER,
|
.role = I2S_ROLE_MASTER,
|
||||||
.dma_desc_num = 6,
|
.dma_desc_num = 6,
|
||||||
.dma_frame_num = 240,
|
.dma_frame_num = 240,
|
||||||
.auto_clear_after_cb = false,
|
.auto_clear_after_cb = true,
|
||||||
.auto_clear_before_cb = false,
|
.auto_clear_before_cb = false,
|
||||||
.intr_priority = 0,
|
.intr_priority = 0,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user