diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 69bd6894..0bea3199 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -247,7 +247,7 @@ config USE_AUDIO_PROCESSOR config USE_REALTIME_CHAT bool "启用可语音打断的实时对话模式(需要 AEC 支持)" default n - depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3) + depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3) help 需要 ESP32 S3 与 AEC 开启,因为性能不够,不建议和微信聊天界面风格同时开启 diff --git a/main/audio_processing/audio_processor.cc b/main/audio_processing/audio_processor.cc index 8c72af3a..b726e1c1 100644 --- a/main/audio_processing/audio_processor.cc +++ b/main/audio_processing/audio_processor.cc @@ -28,7 +28,7 @@ void AudioProcessor::Initialize(AudioCodec* codec, bool realtime_chat) { afe_config_t* afe_config = afe_config_init(input_format.c_str(), NULL, AFE_TYPE_VC, AFE_MODE_HIGH_PERF); if (realtime_chat) { afe_config->aec_init = true; - afe_config->aec_mode = AEC_MODE_VOIP_LOW_COST; + afe_config->aec_mode = AEC_MODE_VOIP_HIGH_PERF; } else { afe_config->aec_init = false; } diff --git a/main/boards/esp-box-lite/box_audio_codec_lite.cc b/main/boards/esp-box-lite/box_audio_codec_lite.cc index 050d6d6c..25b8ed59 100644 --- a/main/boards/esp-box-lite/box_audio_codec_lite.cc +++ b/main/boards/esp-box-lite/box_audio_codec_lite.cc @@ -3,6 +3,7 @@ #include #include #include +#include static const char TAG[] = "BoxAudioCodecLite"; @@ -11,7 +12,10 @@ BoxAudioCodecLite::BoxAudioCodecLite(void* i2c_master_handle, int input_sample_r gpio_num_t pa_pin, bool input_reference) { duplex_ = true; // 是否双工 input_reference_ = input_reference; // 是否使用参考输入,实现回声消除 - input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 + if (input_reference) { + ref_buffer_.resize(960 * 2); + } + input_channels_ = 2 + input_reference_; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; @@ -108,18 +112,7 @@ void BoxAudioCodecLite::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, g .ext_clk_freq_hz = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256 }, - .slot_cfg = { - .data_bit_width = I2S_DATA_BIT_WIDTH_16BIT, - .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, - .slot_mode = I2S_SLOT_MODE_STEREO, - .slot_mask = I2S_STD_SLOT_BOTH, - .ws_width = I2S_DATA_BIT_WIDTH_16BIT, - .ws_pol = false, - .bit_shift = true, - .left_align = true, - .big_endian = false, - .bit_order_lsb = false - }, + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = mclk, .bclk = bclk, @@ -187,13 +180,13 @@ void BoxAudioCodecLite::EnableInput(bool enable) { if (enable) { esp_codec_dev_sample_info_t fs = { .bits_per_sample = 16, - .channel = 4, - .channel_mask = ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), - .sample_rate = (uint32_t)output_sample_rate_, + .channel = (uint8_t)(input_channels_ - input_reference_), + .channel_mask = 0, + .sample_rate = (uint32_t)input_sample_rate_, .mclk_multiple = 0, }; - if (input_reference_) { - fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(1); + for (int i = 0;i < fs.channel; i++) { + fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(i); } ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); // 麦克风增益解决收音太小的问题 @@ -227,7 +220,30 @@ void BoxAudioCodecLite::EnableOutput(bool enable) { int BoxAudioCodecLite::Read(int16_t* dest, int samples) { if (input_enabled_) { - ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_read(input_dev_, (void*)dest, samples * sizeof(int16_t))); + if (!input_reference_) { + ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_read(input_dev_, (void*)dest, samples * sizeof(int16_t))); + } + else { + int size = samples / input_channels_; + int channels = input_channels_ - input_reference_; + std::vector data(size * channels); + // read mic data + ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_read(input_dev_, (void*)data.data(), data.size() * sizeof(int16_t))); + int j = 0; + int i = 0; + while (i< samples) { + // mic data + for (int p = 0; p < channels; p++) { + dest[i++] = data[j++]; + } + // ref data + dest[i++] = read_pos_ < write_pos_? ref_buffer_[read_pos_++] : 0; + } + + if (read_pos_ == write_pos_) { + read_pos_ = write_pos_ = 0; + } + } } return samples; } @@ -235,6 +251,22 @@ int BoxAudioCodecLite::Read(int16_t* dest, int samples) { int BoxAudioCodecLite::Write(const int16_t* data, int samples) { if (output_enabled_) { ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_write(output_dev_, (void*)data, samples * sizeof(int16_t))); + if (input_reference_) { // 板子不支持硬件回采,采用缓存播放缓冲来实现回声消除 + if (write_pos_ - read_pos_ + samples > ref_buffer_.size()) { + assert(ref_buffer_.size() >= samples); + // 写溢出,只保留最近的数据 + read_pos_ = write_pos_ + samples - ref_buffer_.size(); + } + if (read_pos_) { + if (write_pos_ != read_pos_) { + memmove(ref_buffer_.data(), ref_buffer_.data() + read_pos_, (write_pos_ - read_pos_) * sizeof(int16_t)); + } + write_pos_ -= read_pos_; + read_pos_ = 0; + } + memcpy(&ref_buffer_[write_pos_], data, samples * sizeof(int16_t)); + write_pos_ += samples; + } } return samples; } \ No newline at end of file diff --git a/main/boards/esp-box-lite/box_audio_codec_lite.h b/main/boards/esp-box-lite/box_audio_codec_lite.h index 646f3985..50fd3617 100644 --- a/main/boards/esp-box-lite/box_audio_codec_lite.h +++ b/main/boards/esp-box-lite/box_audio_codec_lite.h @@ -17,6 +17,10 @@ private: esp_codec_dev_handle_t output_dev_ = nullptr; esp_codec_dev_handle_t input_dev_ = nullptr; + // ref buffer used for aec + std::vector ref_buffer_; + int read_pos_ = 0; + int write_pos_ = 0; void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din); diff --git a/main/boards/esp-box-lite/config.h b/main/boards/esp-box-lite/config.h index 82cde9c6..ee345edf 100644 --- a/main/boards/esp-box-lite/config.h +++ b/main/boards/esp-box-lite/config.h @@ -3,10 +3,10 @@ #include -#define AUDIO_INPUT_SAMPLE_RATE 24000 -#define AUDIO_OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_INPUT_SAMPLE_RATE 16000 +#define AUDIO_OUTPUT_SAMPLE_RATE 16000 -#define AUDIO_INPUT_REFERENCE true +#define AUDIO_INPUT_REFERENCE CONFIG_USE_AUDIO_PROCESSOR #define AUDIO_I2S_GPIO_MCLK GPIO_NUM_2 #define AUDIO_I2S_GPIO_WS GPIO_NUM_47 diff --git a/main/boards/esp-box-lite/esp_box_lite_board.cc b/main/boards/esp-box-lite/esp_box_lite_board.cc index 95ca242b..633fab17 100644 --- a/main/boards/esp-box-lite/esp_box_lite_board.cc +++ b/main/boards/esp-box-lite/esp_box_lite_board.cc @@ -185,11 +185,10 @@ private: esp_lcd_panel_reset(panel); esp_lcd_panel_init(panel); - esp_lcd_panel_invert_color(panel, false); + esp_lcd_panel_invert_color(panel, DISPLAY_BACKLIGHT_OUTPUT_INVERT); esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY); esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y); esp_lcd_panel_disp_on_off(panel, true); - esp_lcd_panel_invert_color(panel, true); display_ = new SpiLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, {