forked from xiaozhi/xiaozhi-esp32
158 lines
4.6 KiB
C++
158 lines
4.6 KiB
C++
#include "afe_audio_processor.h"
|
|
#include <esp_log.h>
|
|
|
|
#define PROCESSOR_RUNNING 0x01
|
|
|
|
#define TAG "AfeAudioProcessor"
|
|
|
|
AfeAudioProcessor::AfeAudioProcessor()
|
|
: afe_data_(nullptr) {
|
|
event_group_ = xEventGroupCreate();
|
|
}
|
|
|
|
void AfeAudioProcessor::Initialize(AudioCodec* codec) {
|
|
codec_ = codec;
|
|
int ref_num = codec_->input_reference() ? 1 : 0;
|
|
|
|
std::string input_format;
|
|
for (int i = 0; i < codec_->input_channels() - ref_num; i++) {
|
|
input_format.push_back('M');
|
|
}
|
|
for (int i = 0; i < ref_num; i++) {
|
|
input_format.push_back('R');
|
|
}
|
|
|
|
srmodel_list_t *models = esp_srmodel_init("model");
|
|
char* ns_model_name = esp_srmodel_filter(models, ESP_NSNET_PREFIX, NULL);
|
|
|
|
afe_config_t* afe_config = afe_config_init(input_format.c_str(), NULL, AFE_TYPE_VC, AFE_MODE_HIGH_PERF);
|
|
afe_config->aec_mode = AEC_MODE_VOIP_HIGH_PERF;
|
|
afe_config->vad_mode = VAD_MODE_0;
|
|
afe_config->vad_min_noise_ms = 100;
|
|
|
|
if (ns_model_name != nullptr) {
|
|
afe_config->ns_init = true;
|
|
afe_config->ns_model_name = ns_model_name;
|
|
afe_config->afe_ns_mode = AFE_NS_MODE_NET;
|
|
} else {
|
|
afe_config->ns_init = false;
|
|
}
|
|
|
|
afe_config->afe_perferred_core = 1;
|
|
afe_config->afe_perferred_priority = 1;
|
|
afe_config->agc_init = false;
|
|
afe_config->memory_alloc_mode = AFE_MEMORY_ALLOC_MORE_PSRAM;
|
|
|
|
#ifdef CONFIG_USE_DEVICE_AEC
|
|
afe_config->aec_init = true;
|
|
afe_config->vad_init = false;
|
|
#else
|
|
afe_config->aec_init = false;
|
|
afe_config->vad_init = true;
|
|
#endif
|
|
|
|
afe_iface_ = esp_afe_handle_from_config(afe_config);
|
|
afe_data_ = afe_iface_->create_from_config(afe_config);
|
|
|
|
xTaskCreate([](void* arg) {
|
|
auto this_ = (AfeAudioProcessor*)arg;
|
|
this_->AudioProcessorTask();
|
|
vTaskDelete(NULL);
|
|
}, "audio_communication", 4096, this, 3, NULL);
|
|
}
|
|
|
|
AfeAudioProcessor::~AfeAudioProcessor() {
|
|
if (afe_data_ != nullptr) {
|
|
afe_iface_->destroy(afe_data_);
|
|
}
|
|
vEventGroupDelete(event_group_);
|
|
}
|
|
|
|
size_t AfeAudioProcessor::GetFeedSize() {
|
|
if (afe_data_ == nullptr) {
|
|
return 0;
|
|
}
|
|
return afe_iface_->get_feed_chunksize(afe_data_) * codec_->input_channels();
|
|
}
|
|
|
|
void AfeAudioProcessor::Feed(const std::vector<int16_t>& data) {
|
|
if (afe_data_ == nullptr) {
|
|
return;
|
|
}
|
|
afe_iface_->feed(afe_data_, data.data());
|
|
}
|
|
|
|
void AfeAudioProcessor::Start() {
|
|
xEventGroupSetBits(event_group_, PROCESSOR_RUNNING);
|
|
}
|
|
|
|
void AfeAudioProcessor::Stop() {
|
|
xEventGroupClearBits(event_group_, PROCESSOR_RUNNING);
|
|
if (afe_data_ != nullptr) {
|
|
afe_iface_->reset_buffer(afe_data_);
|
|
}
|
|
}
|
|
|
|
bool AfeAudioProcessor::IsRunning() {
|
|
return xEventGroupGetBits(event_group_) & PROCESSOR_RUNNING;
|
|
}
|
|
|
|
void AfeAudioProcessor::OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) {
|
|
output_callback_ = callback;
|
|
}
|
|
|
|
void AfeAudioProcessor::OnVadStateChange(std::function<void(bool speaking)> callback) {
|
|
vad_state_change_callback_ = callback;
|
|
}
|
|
|
|
void AfeAudioProcessor::AudioProcessorTask() {
|
|
auto fetch_size = afe_iface_->get_fetch_chunksize(afe_data_);
|
|
auto feed_size = afe_iface_->get_feed_chunksize(afe_data_);
|
|
ESP_LOGI(TAG, "Audio communication task started, feed size: %d fetch size: %d",
|
|
feed_size, fetch_size);
|
|
|
|
while (true) {
|
|
xEventGroupWaitBits(event_group_, PROCESSOR_RUNNING, pdFALSE, pdTRUE, portMAX_DELAY);
|
|
|
|
auto res = afe_iface_->fetch_with_delay(afe_data_, portMAX_DELAY);
|
|
if ((xEventGroupGetBits(event_group_) & PROCESSOR_RUNNING) == 0) {
|
|
continue;
|
|
}
|
|
if (res == nullptr || res->ret_value == ESP_FAIL) {
|
|
if (res != nullptr) {
|
|
ESP_LOGI(TAG, "Error code: %d", res->ret_value);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// VAD state change
|
|
if (vad_state_change_callback_) {
|
|
if (res->vad_state == VAD_SPEECH && !is_speaking_) {
|
|
is_speaking_ = true;
|
|
vad_state_change_callback_(true);
|
|
} else if (res->vad_state == VAD_SILENCE && is_speaking_) {
|
|
is_speaking_ = false;
|
|
vad_state_change_callback_(false);
|
|
}
|
|
}
|
|
|
|
if (output_callback_) {
|
|
output_callback_(std::vector<int16_t>(res->data, res->data + res->data_size / sizeof(int16_t)));
|
|
}
|
|
}
|
|
}
|
|
|
|
void AfeAudioProcessor::EnableDeviceAec(bool enable) {
|
|
if (enable) {
|
|
#if CONFIG_USE_DEVICE_AEC
|
|
afe_iface_->disable_vad(afe_data_);
|
|
afe_iface_->enable_aec(afe_data_);
|
|
#else
|
|
ESP_LOGE(TAG, "Device AEC is not supported");
|
|
#endif
|
|
} else {
|
|
afe_iface_->disable_aec(afe_data_);
|
|
afe_iface_->enable_vad(afe_data_);
|
|
}
|
|
}
|