wangzhibo
2026-08-26 70481429367ca00144b24f118cbfdfb28b02967d
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];