使用esp-sr afe,log提示AFE: Ringbuffer of AFE is empty, Please use feed() to write data
-
toney_zhang
- Posts: 2
- Joined: Fri Apr 03, 2026 8:19 am
使用esp-sr afe,log提示AFE: Ringbuffer of AFE is empty, Please use feed() to write data
使用esp-sr afe,log提示AFE: Ringbuffer of AFE is empty, Please use feed() to write data,这是为什么?
-
toney_zhang
- Posts: 2
- Joined: Fri Apr 03, 2026 8:19 am
Re: 使用esp-sr afe,log提示AFE: Ringbuffer of AFE is empty, Please use feed() to write data
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
//
AFE 头文件
#include "esp_afe_sr_iface.h"
#include "esp_afe_config.h"
#include "esp_afe_sr_models.h"
#define MIC_BCLK_IO GPIO_NUM_5
#define MIC_WS_IO GPIO_NUM_4
#define MIC_DI_IO GPIO_NUM_6
#define SPK_BCLK_IO GPIO_NUM_15
#define SPK_WS_IO GPIO_NUM_16
#define SPK_DO_IO GPIO_NUM_7
#define SPK_SD_IO GPIO_NUM_14
#define SAMPLE_RATE 16000
#define SAMPLE_BITS I2S_DATA_BIT_WIDTH_24BIT
#define FRAM_COUNT 8
#define SAMPLE_TIMES 30
#define FRAM_LEN (SAMPLE_TIMES*(SAMPLE_RATE/1E3)) // 240
3的倍数
#define I2S_SLOT_BIT_WIDTH I2S_SLOT_BIT_WIDTH_32BIT
static const char *TAG = "AUDIO_DEMO";
static i2s_chan_handle_t tx_handle;
static i2s_chan_handle_t rx_handle;
//
AFE 全局句柄
static esp_afe_sr_iface_t *afe_handle = NULL;
static esp_afe_sr_data_t *afe_data = NULL;
extern const model_coeff_getter_t WAKENET_MODEL_HILEXIN;
//
AFE 配置(只开 AEC/NS/AGC,关闭唤醒词)
static void afe_init(void)
{
// srmodel_list_t *models = esp_srmodel_init("model");
// if (models == NULL)
// {
// ESP_LOGE(TAG, "Failed to initialize AFE models");
// return;
// }
// 1. 初始化配置
afe_config_t *afe_config = afe_config_init("M", NULL, AFE_TYPE_VC, AFE_MODE_LOW_COST);
if (afe_config == NULL)
{
ESP_LOGE(TAG, "Failed to initialize AFE config");
return;
}
// // 2. 手动微调 (覆盖默认值)
// if (afe_config)
// {
// // 回声消除 (AEC)
// afe_config->aec_init = false;
// afe_config->aec_mode = AEC_MODE_SR_HIGH_PERF;
// afe_config->aec_filter_length = 200;
// // SE (语音增强)
// afe_config->se_init = true;
// // 降噪与增强 (NS/SE)
// afe_config->ns_init = true;
// afe_config->ns_model_name = NULL;
// afe_config->afe_ns_mode = AFE_NS_MODE_WEBRTC;
// // 语音活动检测 (VAD)
// afe_config->vad_init = false;
// afe_config->vad_mode = VAD_MODE_2;
// afe_config->vad_model_name = NULL;
// // 唤醒词 (WakeNet)(必须关闭!)
// afe_config->wakenet_init = false;
// afe_config->wakenet_model_name = NULL;
// afe_config->wakenet_model_name_2 = NULL;
// // 自动增益 (AGC)
// afe_config->agc_init = true;
// afe_config->agc_mode = AFE_AGC_MODE_WEBRTC;
// afe_config->agc_compression_gain_db = 9;
// afe_config->agc_target_level_dbfs = 3;
// // 音频配置(单麦)
// afe_config->pcm_config.total_ch_num = 1;
// afe_config->pcm_config.mic_num = 1;
// afe_config->pcm_config.ref_num = 0;
// // 通用配置
// afe_config->afe_mode = AFE_MODE_HIGH_PERF;
// afe_config->afe_type = AFE_TYPE_SR;
// afe_config->afe_linear_gain = 1.0f;
// }
// 2. 检查配置
afe_config = afe_config_check(afe_config);
if (afe_config == NULL)
{
ESP_LOGE(TAG, "Failed to check AFE config");
return;
}
// 3. 创建实例
afe_handle = esp_afe_handle_from_config(afe_config);
if (afe_handle == NULL)
{
ESP_LOGE(TAG, "Failed to create AFE handle");
return;
}
// 4. 创建数据结构
afe_data = afe_handle->create_from_config(afe_config);
if (afe_data == NULL)
{
ESP_LOGE(TAG, "Failed to create AFE data");
return;
}
}
//
32bit(int32_t) → 16bit(int16_t)(AFE 输入)
static void conv_32to16(const int32_t *in, int16_t *out, int len)
{
for (int i = 0; i < len; i++)
{
// 右移16位,取有效32bit高16bit(适配 ICS43434 左对齐)
// out[2*i] = (int16_t)(in >> 16);
// out[2*i+1] = 0;
// // printf("0x%04X 0x%04X ", out[2*i], out[2*i+1]);
// // if (i % 5 == 4)
// // {
// // printf("\n");
// // }
out = (int16_t)(in >> 16);
}
}
//
16bit(int16_t) → 32bit(int32_t)(I2S 输出)
static void conv_16to32(const int16_t *in, int32_t *out, int len)
{
for (int i = 0; i < len; i++)
{
// 左移16位,还原为32bit容器的32bit格式
out = (int32_t)in[2*i] << 16;
// printf("0x%08lX", out);
// if (i % 10 == 9)
// {
// printf("\n");
// }
}
}
static void gen_sine(int32_t *buf, size_t frame_cnt)
{
static float phase = 0.0f;
const float amp = 8000000.0f;
const float dphase = 2.0f * 3.1415926f * 1000.0f / SAMPLE_RATE;
for(size_t i=0; i<frame_cnt; i++)
{
buf = (int32_t)(sinf(phase) * amp);
phase += dphase;
if(phase > 2*3.1415926f)
{
phase -= 2*3.1415926f;
}
}
}
static void audio_init(void)
{
i2s_std_config_t rx_cfg = {
.clk_cfg = {
.clk_src = I2S_CLK_SRC_DEFAULT, //
音频时钟
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.sample_rate_hz = SAMPLE_RATE,
},
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = MIC_BCLK_IO,
.ws = MIC_WS_IO,
.dout = I2S_GPIO_UNUSED,
.din = MIC_DI_IO,
},
.slot_cfg = {
.data_bit_width = SAMPLE_BITS,
.slot_bit_width = I2S_SLOT_BIT_WIDTH,
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT,
.ws_width = SAMPLE_BITS,
.ws_pol = false,
.bit_shift = true,
.left_align = true, //
必须false
.big_endian = false,
.bit_order_lsb = false,
},
};
i2s_std_config_t tx_cfg = {
.clk_cfg = {
.clk_src = I2S_CLK_SRC_DEFAULT, //
音频时钟
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.sample_rate_hz = SAMPLE_RATE,
},
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = SPK_BCLK_IO,
.ws = SPK_WS_IO,
.dout = SPK_DO_IO,
.din = I2S_GPIO_UNUSED,
},
.slot_cfg = {
.data_bit_width = SAMPLE_BITS,
.slot_bit_width = I2S_SLOT_BIT_WIDTH,
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT,
.ws_width = SAMPLE_BITS,
.ws_pol = false,
.bit_shift = true,
.left_align = true, //
必须false
.big_endian = false,
.bit_order_lsb = false,
},
};
i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
rx_chan_cfg.dma_desc_num = FRAM_COUNT;
rx_chan_cfg.dma_frame_num = FRAM_LEN;
ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_handle));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &rx_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
tx_chan_cfg.dma_desc_num = FRAM_COUNT;
tx_chan_cfg.dma_frame_num = FRAM_LEN;
ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_handle, NULL));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &tx_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << SPK_SD_IO),
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&io_conf);
gpio_set_level(SPK_SD_IO, 1);
ESP_LOGI(TAG, "I2S Init OK");
}
static void audio_task(void *pvParameters)
{
audio_init();
afe_init();
//
正确大小:帧数 × 4字节(32bit)
size_t i2s_buf_len = FRAM_LEN * sizeof(int32_t);
int32_t *i2s_rx_buf = heap_caps_malloc(i2s_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!i2s_rx_buf)
{
ESP_LOGE(TAG, "I2S rx malloc failed");
heap_caps_free(i2s_rx_buf);
vTaskDelete(NULL);
return;
}
ESP_LOGI("I2S", "I2S rx buf len: %d", i2s_buf_len);
const int afe_chunk = afe_handle->get_feed_chunksize(afe_data);
const int feed_nch = afe_handle->get_feed_channel_num(afe_data);
const size_t afe_buf_len = afe_chunk * sizeof(int16_t) * feed_nch; // feed_nch代表“MR”通道数
ESP_LOGI("AFE", "AFE chunk: %d, feed_nch: %d, buf len: %d", afe_chunk, feed_nch, afe_buf_len);
int16_t *afe_in_buf = heap_caps_malloc(afe_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
int16_t *afe_out_buf = heap_caps_malloc(afe_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!afe_in_buf || !afe_out_buf)
{
ESP_LOGE(TAG, "AFE malloc failed");
heap_caps_free(afe_in_buf);
heap_caps_free(afe_out_buf);
vTaskDelete(NULL);
return;
}
int32_t *i2s_tx_buf = heap_caps_malloc(i2s_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!i2s_tx_buf)
{
ESP_LOGE(TAG, "I2S tx malloc failed");
heap_caps_free(i2s_tx_buf);
vTaskDelete(NULL);
return;
}
while (1)
{
size_t bytes_read, bytes_written;
esp_err_t ret = ESP_OK;
// 1. 读取 I2S 麦克风数据
ret = i2s_channel_read(rx_handle, i2s_rx_buf, i2s_buf_len, &bytes_read, portMAX_DELAY);
if (ret != ESP_OK || bytes_read == 0)
{
continue;
}
const int input_sample_cnt = bytes_read / sizeof(int32_t);
// 2. 格式转换:32bit -> 16bit
// 注意:这里生成的 16bit 数据是交错的 [Mic, 0, Mic, 0...]
conv_32to16(i2s_rx_buf, afe_in_buf, input_sample_cnt);
// 3. 喂数据给 AFE
afe_handle->feed(afe_data, afe_in_buf);
// 4. 获取 AFE 处理结果
afe_fetch_result_t *res = afe_handle->fetch_with_delay(afe_data, 0);
// 5. 准备播放缓冲区(先清零,防止爆音)
memset(i2s_tx_buf, 0, i2s_buf_len);
if (res && res->ret_value == ESP_OK)
{
//
只有当 fetch 成功时,才进行转换和播放
// 计算输出样本数(根据 AFE 返回的实际字节数)
int output_sample_cnt = res->data_size / sizeof(int16_t);
// 转换回 32bit 用于 I2S 播放
conv_16to32(res->data, i2s_tx_buf, output_sample_cnt);
// 6. 播放处理后的数据
//
关键:播放 i2s_tx_buf (AFE 输出),而不是 i2s_rx_buf
ret = i2s_channel_write(tx_handle, i2s_tx_buf, output_sample_cnt * sizeof(int32_t), &bytes_written, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "I2S write failed");
}
}
else
{
// 如果 fetch 失败,i2s_tx_buf 保持全 0 (静音),这是正常的启动过程
// 长度要对应输出样本数
ret = i2s_channel_write(tx_handle, i2s_rx_buf, bytes_read, &bytes_written, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "I2S write failed");
}
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
void app_main(void)
{
xTaskCreatePinnedToCore(audio_task, "audio_task", 8192, NULL, 5, NULL, 0);
while (1)
{
vTaskDelay(1000);
}
}
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
//
#include "esp_afe_sr_iface.h"
#include "esp_afe_config.h"
#include "esp_afe_sr_models.h"
#define MIC_BCLK_IO GPIO_NUM_5
#define MIC_WS_IO GPIO_NUM_4
#define MIC_DI_IO GPIO_NUM_6
#define SPK_BCLK_IO GPIO_NUM_15
#define SPK_WS_IO GPIO_NUM_16
#define SPK_DO_IO GPIO_NUM_7
#define SPK_SD_IO GPIO_NUM_14
#define SAMPLE_RATE 16000
#define SAMPLE_BITS I2S_DATA_BIT_WIDTH_24BIT
#define FRAM_COUNT 8
#define SAMPLE_TIMES 30
#define FRAM_LEN (SAMPLE_TIMES*(SAMPLE_RATE/1E3)) // 240
#define I2S_SLOT_BIT_WIDTH I2S_SLOT_BIT_WIDTH_32BIT
static const char *TAG = "AUDIO_DEMO";
static i2s_chan_handle_t tx_handle;
static i2s_chan_handle_t rx_handle;
//
static esp_afe_sr_iface_t *afe_handle = NULL;
static esp_afe_sr_data_t *afe_data = NULL;
extern const model_coeff_getter_t WAKENET_MODEL_HILEXIN;
//
static void afe_init(void)
{
// srmodel_list_t *models = esp_srmodel_init("model");
// if (models == NULL)
// {
// ESP_LOGE(TAG, "Failed to initialize AFE models");
// return;
// }
// 1. 初始化配置
afe_config_t *afe_config = afe_config_init("M", NULL, AFE_TYPE_VC, AFE_MODE_LOW_COST);
if (afe_config == NULL)
{
ESP_LOGE(TAG, "Failed to initialize AFE config");
return;
}
// // 2. 手动微调 (覆盖默认值)
// if (afe_config)
// {
// // 回声消除 (AEC)
// afe_config->aec_init = false;
// afe_config->aec_mode = AEC_MODE_SR_HIGH_PERF;
// afe_config->aec_filter_length = 200;
// // SE (语音增强)
// afe_config->se_init = true;
// // 降噪与增强 (NS/SE)
// afe_config->ns_init = true;
// afe_config->ns_model_name = NULL;
// afe_config->afe_ns_mode = AFE_NS_MODE_WEBRTC;
// // 语音活动检测 (VAD)
// afe_config->vad_init = false;
// afe_config->vad_mode = VAD_MODE_2;
// afe_config->vad_model_name = NULL;
// // 唤醒词 (WakeNet)(必须关闭!)
// afe_config->wakenet_init = false;
// afe_config->wakenet_model_name = NULL;
// afe_config->wakenet_model_name_2 = NULL;
// // 自动增益 (AGC)
// afe_config->agc_init = true;
// afe_config->agc_mode = AFE_AGC_MODE_WEBRTC;
// afe_config->agc_compression_gain_db = 9;
// afe_config->agc_target_level_dbfs = 3;
// // 音频配置(单麦)
// afe_config->pcm_config.total_ch_num = 1;
// afe_config->pcm_config.mic_num = 1;
// afe_config->pcm_config.ref_num = 0;
// // 通用配置
// afe_config->afe_mode = AFE_MODE_HIGH_PERF;
// afe_config->afe_type = AFE_TYPE_SR;
// afe_config->afe_linear_gain = 1.0f;
// }
// 2. 检查配置
afe_config = afe_config_check(afe_config);
if (afe_config == NULL)
{
ESP_LOGE(TAG, "Failed to check AFE config");
return;
}
// 3. 创建实例
afe_handle = esp_afe_handle_from_config(afe_config);
if (afe_handle == NULL)
{
ESP_LOGE(TAG, "Failed to create AFE handle");
return;
}
// 4. 创建数据结构
afe_data = afe_handle->create_from_config(afe_config);
if (afe_data == NULL)
{
ESP_LOGE(TAG, "Failed to create AFE data");
return;
}
}
//
static void conv_32to16(const int32_t *in, int16_t *out, int len)
{
for (int i = 0; i < len; i++)
{
// 右移16位,取有效32bit高16bit(适配 ICS43434 左对齐)
// out[2*i] = (int16_t)(in >> 16);
// out[2*i+1] = 0;
// // printf("0x%04X 0x%04X ", out[2*i], out[2*i+1]);
// // if (i % 5 == 4)
// // {
// // printf("\n");
// // }
out = (int16_t)(in >> 16);
}
}
//
static void conv_16to32(const int16_t *in, int32_t *out, int len)
{
for (int i = 0; i < len; i++)
{
// 左移16位,还原为32bit容器的32bit格式
out = (int32_t)in[2*i] << 16;
// printf("0x%08lX", out);
// if (i % 10 == 9)
// {
// printf("\n");
// }
}
}
static void gen_sine(int32_t *buf, size_t frame_cnt)
{
static float phase = 0.0f;
const float amp = 8000000.0f;
const float dphase = 2.0f * 3.1415926f * 1000.0f / SAMPLE_RATE;
for(size_t i=0; i<frame_cnt; i++)
{
buf = (int32_t)(sinf(phase) * amp);
phase += dphase;
if(phase > 2*3.1415926f)
{
phase -= 2*3.1415926f;
}
}
}
static void audio_init(void)
{
i2s_std_config_t rx_cfg = {
.clk_cfg = {
.clk_src = I2S_CLK_SRC_DEFAULT, //
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.sample_rate_hz = SAMPLE_RATE,
},
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = MIC_BCLK_IO,
.ws = MIC_WS_IO,
.dout = I2S_GPIO_UNUSED,
.din = MIC_DI_IO,
},
.slot_cfg = {
.data_bit_width = SAMPLE_BITS,
.slot_bit_width = I2S_SLOT_BIT_WIDTH,
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT,
.ws_width = SAMPLE_BITS,
.ws_pol = false,
.bit_shift = true,
.left_align = true, //
.big_endian = false,
.bit_order_lsb = false,
},
};
i2s_std_config_t tx_cfg = {
.clk_cfg = {
.clk_src = I2S_CLK_SRC_DEFAULT, //
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.sample_rate_hz = SAMPLE_RATE,
},
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = SPK_BCLK_IO,
.ws = SPK_WS_IO,
.dout = SPK_DO_IO,
.din = I2S_GPIO_UNUSED,
},
.slot_cfg = {
.data_bit_width = SAMPLE_BITS,
.slot_bit_width = I2S_SLOT_BIT_WIDTH,
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT,
.ws_width = SAMPLE_BITS,
.ws_pol = false,
.bit_shift = true,
.left_align = true, //
.big_endian = false,
.bit_order_lsb = false,
},
};
i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
rx_chan_cfg.dma_desc_num = FRAM_COUNT;
rx_chan_cfg.dma_frame_num = FRAM_LEN;
ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_handle));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &rx_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
tx_chan_cfg.dma_desc_num = FRAM_COUNT;
tx_chan_cfg.dma_frame_num = FRAM_LEN;
ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_handle, NULL));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &tx_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << SPK_SD_IO),
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&io_conf);
gpio_set_level(SPK_SD_IO, 1);
ESP_LOGI(TAG, "I2S Init OK");
}
static void audio_task(void *pvParameters)
{
audio_init();
afe_init();
//
size_t i2s_buf_len = FRAM_LEN * sizeof(int32_t);
int32_t *i2s_rx_buf = heap_caps_malloc(i2s_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!i2s_rx_buf)
{
ESP_LOGE(TAG, "I2S rx malloc failed");
heap_caps_free(i2s_rx_buf);
vTaskDelete(NULL);
return;
}
ESP_LOGI("I2S", "I2S rx buf len: %d", i2s_buf_len);
const int afe_chunk = afe_handle->get_feed_chunksize(afe_data);
const int feed_nch = afe_handle->get_feed_channel_num(afe_data);
const size_t afe_buf_len = afe_chunk * sizeof(int16_t) * feed_nch; // feed_nch代表“MR”通道数
ESP_LOGI("AFE", "AFE chunk: %d, feed_nch: %d, buf len: %d", afe_chunk, feed_nch, afe_buf_len);
int16_t *afe_in_buf = heap_caps_malloc(afe_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
int16_t *afe_out_buf = heap_caps_malloc(afe_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!afe_in_buf || !afe_out_buf)
{
ESP_LOGE(TAG, "AFE malloc failed");
heap_caps_free(afe_in_buf);
heap_caps_free(afe_out_buf);
vTaskDelete(NULL);
return;
}
int32_t *i2s_tx_buf = heap_caps_malloc(i2s_buf_len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!i2s_tx_buf)
{
ESP_LOGE(TAG, "I2S tx malloc failed");
heap_caps_free(i2s_tx_buf);
vTaskDelete(NULL);
return;
}
while (1)
{
size_t bytes_read, bytes_written;
esp_err_t ret = ESP_OK;
// 1. 读取 I2S 麦克风数据
ret = i2s_channel_read(rx_handle, i2s_rx_buf, i2s_buf_len, &bytes_read, portMAX_DELAY);
if (ret != ESP_OK || bytes_read == 0)
{
continue;
}
const int input_sample_cnt = bytes_read / sizeof(int32_t);
// 2. 格式转换:32bit -> 16bit
// 注意:这里生成的 16bit 数据是交错的 [Mic, 0, Mic, 0...]
conv_32to16(i2s_rx_buf, afe_in_buf, input_sample_cnt);
// 3. 喂数据给 AFE
afe_handle->feed(afe_data, afe_in_buf);
// 4. 获取 AFE 处理结果
afe_fetch_result_t *res = afe_handle->fetch_with_delay(afe_data, 0);
// 5. 准备播放缓冲区(先清零,防止爆音)
memset(i2s_tx_buf, 0, i2s_buf_len);
if (res && res->ret_value == ESP_OK)
{
//
// 计算输出样本数(根据 AFE 返回的实际字节数)
int output_sample_cnt = res->data_size / sizeof(int16_t);
// 转换回 32bit 用于 I2S 播放
conv_16to32(res->data, i2s_tx_buf, output_sample_cnt);
// 6. 播放处理后的数据
//
ret = i2s_channel_write(tx_handle, i2s_tx_buf, output_sample_cnt * sizeof(int32_t), &bytes_written, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "I2S write failed");
}
}
else
{
// 如果 fetch 失败,i2s_tx_buf 保持全 0 (静音),这是正常的启动过程
// 长度要对应输出样本数
ret = i2s_channel_write(tx_handle, i2s_rx_buf, bytes_read, &bytes_written, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "I2S write failed");
}
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
void app_main(void)
{
xTaskCreatePinnedToCore(audio_task, "audio_task", 8192, NULL, 5, NULL, 0);
while (1)
{
vTaskDelay(1000);
}
}
Who is online
Users browsing this forum: No registered users and 2 guests