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