From 70481429367ca00144b24f118cbfdfb28b02967d Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期三, 26 八月 2026 15:54:31 +0800
Subject: [PATCH] add sening functions
---
xiaozhi-esp32-2.2.6/main/audio/wake_words/afe_wake_word.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/xiaozhi-esp32-2.2.6/main/audio/wake_words/afe_wake_word.cc b/xiaozhi-esp32-2.2.6/main/audio/wake_words/afe_wake_word.cc
index 8fc5fef..bfae615 100644
--- a/xiaozhi-esp32-2.2.6/main/audio/wake_words/afe_wake_word.cc
+++ b/xiaozhi-esp32-2.2.6/main/audio/wake_words/afe_wake_word.cc
@@ -1,6 +1,9 @@
#include "afe_wake_word.h"
#include "audio_service.h"
+#include "boards/sening-xiaozhi-s3/system.h"
#include <esp_log.h>
+#include <esp_mn_models.h>
+#include <esp_mn_speech_commands.h>
#include <sstream>
#define DETECTION_RUNNING_EVENT 1
@@ -18,6 +21,9 @@
AfeWakeWord::~AfeWakeWord() {
if (afe_data_ != nullptr) {
afe_iface_->destroy(afe_data_);
+ }
+ if (multinet_data_ != nullptr && multinet_ != nullptr) {
+ multinet_->destroy(multinet_data_);
}
if (wake_word_encode_task_stack_ != nullptr) {
@@ -63,6 +69,22 @@
}
}
+ multinet_model_ = esp_srmodel_filter(models_, ESP_MN_PREFIX, "cn");
+ if (multinet_model_ == nullptr) {
+ multinet_model_ = esp_srmodel_filter(models_, ESP_MN_PREFIX, NULL);
+ }
+ if (multinet_model_ != nullptr) {
+ multinet_ = esp_mn_handle_from_name(multinet_model_);
+ multinet_data_ = multinet_->create(multinet_model_, 3000);
+ multinet_->set_det_threshold(multinet_data_, 0.2f);
+ esp_mn_commands_clear();
+ esp_mn_commands_add(1, OFFLINE_COMMAND_WORD_PINYIN);
+ esp_mn_commands_update();
+ multinet_->print_active_speech_commands(multinet_data_);
+ } else {
+ ESP_LOGW(TAG, "MultiNet model not found, offline command word disabled");
+ }
+
std::string input_format;
for (int i = 0; i < codec_->input_channels() - ref_num; i++) {
input_format.push_back('M');
@@ -93,6 +115,10 @@
wake_word_detected_callback_ = callback;
}
+void AfeWakeWord::OnOfflineCommandDetected(std::function<void(const std::string& command)> callback) {
+ offline_command_detected_callback_ = callback;
+}
+
void AfeWakeWord::Start() {
xEventGroupSetBits(event_group_, DETECTION_RUNNING_EVENT);
}
@@ -104,7 +130,11 @@
if (afe_data_ != nullptr) {
afe_iface_->reset_buffer(afe_data_);
}
+ if (multinet_data_ != nullptr) {
+ multinet_->clean(multinet_data_);
+ }
input_buffer_.clear();
+ multinet_input_buffer_.clear();
}
void AfeWakeWord::Feed(const std::vector<int16_t>& data) {
@@ -149,6 +179,32 @@
// Store the wake word data for voice recognition, like who is speaking
StoreWakeWordData(res->data, res->data_size / sizeof(int16_t));
+ if (multinet_data_ != nullptr) {
+ multinet_input_buffer_.insert(multinet_input_buffer_.end(), res->data, res->data + res->data_size / sizeof(int16_t));
+ int chunksize = multinet_->get_samp_chunksize(multinet_data_);
+ while (multinet_input_buffer_.size() >= chunksize) {
+ esp_mn_state_t mn_state = multinet_->detect(multinet_data_, multinet_input_buffer_.data());
+ if (mn_state == ESP_MN_STATE_DETECTED) {
+ esp_mn_results_t *mn_result = multinet_->get_results(multinet_data_);
+ for (int i = 0; i < mn_result->num; i++) {
+ ESP_LOGI(TAG, "Offline command detected: command_id=%d, string=%s, prob=%f",
+ mn_result->command_id[i], mn_result->string, mn_result->prob[i]);
+ if (mn_result->command_id[i] == 1 && offline_command_detected_callback_) {
+ offline_command_detected_callback_(OFFLINE_COMMAND_WORD);
+ }
+ }
+ multinet_->clean(multinet_data_);
+ multinet_input_buffer_.clear();
+ break;
+ } else if (mn_state == ESP_MN_STATE_TIMEOUT) {
+ multinet_->clean(multinet_data_);
+ multinet_input_buffer_.clear();
+ break;
+ }
+ multinet_input_buffer_.erase(multinet_input_buffer_.begin(), multinet_input_buffer_.begin() + chunksize);
+ }
+ }
+
if (res->wakeup_state == WAKENET_DETECTED) {
Stop();
last_detected_wake_word_ = wake_words_[res->wakenet_model_index - 1];
--
Gitblit v1.9.1