| | |
| | | #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 |
| | |
| | | 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) { |
| | |
| | | } |
| | | } |
| | | |
| | | 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'); |
| | |
| | | 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); |
| | | } |
| | |
| | | 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) { |
| | |
| | | // 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]; |