/*

  • ============================================================================
  • ESP32 音频处理模块 - 完整逐行注释版本
  • ============================================================================
  • 功能概述:
  • 本模块实现基于 ESP32 的音频采集与播放功能,通过 I2C 控制 ES8311 音频编解码器,
  • 通过 I2S 接口传输音频数据,支持麦克风录音和扬声器播放,采样率 16kHz、
  • 单声道、16bit 采样深度,集成功率放大器(PA)控制。
  • ============================================================================
    */

// ============================================================================
// 头文件包含
// ============================================================================

#include “bsp_sound.h”
/* 包含本模块对外暴露的接口声明头文件,通常包含 bsp_sound_init、
bsp_sound_open、bsp_sound_write、bsp_sound_read 等函数的原型声明 */

// ============================================================================
// 硬件引脚定义 - I2C 接口
// ============================================================================

#define SCL_PIN GPIO_NUM_1
/* 定义 I2C 时钟线(SCL)使用的 GPIO 引脚编号为 GPIO_NUM_1。
SCL(Serial Clock)是 I2C 总线的时钟信号线,用于同步数据传输 */

#define SDA_PIN GPIO_NUM_0
/* 定义 I2C 数据线(SDA)使用的 GPIO 引脚编号为 GPIO_NUM_0。
SDA(Serial Data)是 I2C 总线的数据信号线,用于双向数据传输。
这两条线都需要外部上拉电阻(通常 4.7kΩ),也可使用 I2C 控制器内部上拉 */

// ============================================================================
// 硬件引脚定义 - I2S 音频接口
// ============================================================================

#define I2S_MCK_PIN 3
/* 定义 I2S 主时钟(MCK - Master Clock)引脚编号。
MCK 是 I2S 接口的主时钟信号,频率通常是采样率的 256 倍。
对于 16kHz 采样率,MCK 频率为 16000 × 256 = 4.096MHz */

#define I2S_BCK_PIN 2
/* 定义 I2S 位时钟(BCK - Bit Clock)引脚编号。
BCK 是 I2S 接口的位时钟,每个 BCK 周期传输一个比特。
对于立体声 16bit 采样,BCK 频率 = 采样率 × 位深 × 2 = 16000 × 16 × 2 = 512kHz */

#define I2S_DATA_WS_PIN 5
/* 定义 I2S 字选择信号(WS - Word Select)引脚编号。
WS 用于区分左右声道和帧同步。对于单声道,WS 仍然工作但只传输一个声道的数据。
WS 频率 = 采样率 = 16kHz(每个音频样本对应一个 WS 周期)*/

#define I2S_DATA_OUT_PIN 6
/* 定义 I2S 数据输出引脚编号。
此引脚用于连接到编解码器的数据输入(DIN),
ESP32 通过此引脚向编解码器发送播放音频数据 */

#define I2S_DATA_IN_PIN 4
/* 定义 I2S 数据输入引脚编号。
此引脚用于连接到编解码器的数据输出(DOUT),
ESP32 通过此引脚从编解码器接收录音音频数据 */

// ============================================================================
// 硬件引脚定义 - 功率放大器(PA)控制
// ============================================================================

#define PA_GPIO 7
/* 定义功率放大器使能引脚编号。
此 GPIO 引脚用于控制外部功率放大器的工作状态:

  • 高电平:功率放大器使能,可以驱动扬声器
  • 低电平:功率放大器禁用,断开扬声器连接
    PA 芯片通常为 8205 或类似的 NMOS/PMOS 开关 */

// ============================================================================
// 全局变量 - 设备句柄
// ============================================================================

// i2c总线句柄
static i2c_master_bus_handle_t i2c_bus_handle = NULL;
/* 定义全局静态变量 i2c_bus_handle,用于存储 I2C 主总线的句柄。
此句柄由 i2c_new_master_bus() 函数返回,用于后续创建 I2C 设备。
初始化为 NULL,在 bsp_sound_i2c_init() 中被赋值。
static 关键字限制了其作用域仅限于本文件,提高了封装性 */

i2s_chan_handle_t micHandle = NULL;
/* 定义全局变量,用于存储 I2S 麦克风录音通道的句柄。
此句柄由 i2s_new_channel() 函数返回,代表 I2S 的接收(RX)通道。
用于配置、启用、禁用和控制麦克风数据接收 */

i2s_chan_handle_t speakerHandle = NULL;
/* 定义全局变量,用于存储 I2S 扬声器播放通道的句柄。
此句柄由 i2s_new_channel() 函数返回,代表 I2S 的发送(TX)通道。
用于配置、启用、禁用和控制扬声器数据发送 */

esp_codec_dev_handle_t codec_dev = NULL;
/* 定义全局变量,用于存储音频编解码器(ES8311)设备的句柄。
此句柄由 esp_codec_dev_new() 函数返回,代表整个音频编解码系统。
用于控制编解码器的工作模式、音量、增益等参数,以及进行音频数据读写 */

// ============================================================================
// I2C 初始化函数
// ============================================================================

void bsp_sound_i2c_init(void)
{
/* 此函数初始化 I2C 总线,用于与 ES8311 音频编解码器通信。
I2C 总线为 ES8311 提供控制命令通道,如寄存器读写、模式配置等。
参数:无
返回值:无
*/

// i2c总线配置
i2c_master_bus_config_t i2c_bus_config = {0};
/* 声明并初始化 I2C 主总线配置结构体 i2c_bus_config。
   = {0} 表示将所有字段初始化为 0,确保未显式设置的字段有默认值。
   i2c_master_bus_config_t 包含 I2C 总线的所有配置参数 */

i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
/* 设置 I2C 时钟源为默认值。
   I2C_CLK_SRC_DEFAULT 通常指 APB 时钟(Advanced Peripheral Bus Clock),
   ESP32 上 APB 时钟频率为 80MHz,作为 I2C 时钟的基准 */

i2c_bus_config.i2c_port = I2C_NUM_0;
/* 设置使用 I2C 硬件外设端口 0。
   ESP32 通常有多个 I2C 端口(如 I2C_NUM_0、I2C_NUM_1),
   此处选择 I2C_NUM_0 连接 ES8311 编解码器 */

i2c_bus_config.scl_io_num = SCL_PIN;
/* 设置 I2C 时钟线(SCL)使用的 GPIO 引脚为 SCL_PIN(即 GPIO_NUM_1) */

i2c_bus_config.sda_io_num = SDA_PIN;
/* 设置 I2C 数据线(SDA)使用的 GPIO 引脚为 SDA_PIN(即 GPIO_NUM_0) */

i2c_bus_config.glitch_ignore_cnt = 7; /* 对sda和scl上的信号做滤波 ,默认7*/
/* 设置毛刺(glitch)过滤计数为 7。
   I2C 信号线易受电磁干扰,导致短时的错误信号(毛刺)。
   此参数设定 I2C 控制器忽略短于 7 个 APB 时钟周期的信号波动。
   即:glitch_ignore_cnt × APB_clk_period ≈ 7 × 12.5ns = 87.5ns
   这样可以滤除高频噪声但不影响正常 I2C 信号 */

i2c_bus_config.flags.enable_internal_pullup = true; // 开启内部上拉
/* 启用 I2C 总线的内部上拉电阻。
   I2C 标准要求 SCL 和 SDA 都需要上拉电阻(通常 4.7kΩ)以保证空闲时为高电平。
   设置为 true 时,I2C 控制器内部提供的上拉电阻用于此目的。
   这样可以省去外部上拉电阻(虽然通常仍建议使用外部电阻以获得更稳定的性能)*/

// 创建i2c总线
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
/* 调用 API 根据 i2c_bus_config 配置创建新的 I2C 主总线。
   参数:
   - &i2c_bus_config:指向配置结构体的指针,包含上述所有配置参数
   - &i2c_bus_handle:指向句柄指针的指针,函数将返回的句柄存储到此变量
   函数成功返回后,i2c_bus_handle 可用于后续 I2C 设备的创建和通信 */

}
/* 结束 bsp_sound_i2c_init 函数 */

// ============================================================================
// I2S 初始化函数
// ============================================================================

void bsp_sound_i2s_init(void)
{
/* 此函数初始化 I2S(Inter-IC Sound)接口,用于传输音频数据。
I2S 是一个专为音频设计的数字接口标准,支持高质量的音频流传输。
参数:无
返回值:无
*/

// 通道配置
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
/* 创建并初始化 I2S 通道配置结构体 chan_cfg。
   宏 I2S_CHANNEL_DEFAULT_CONFIG 接收两个参数:
   - I2S_NUM_0:使用 I2S 硬件外设编号 0(对应 I2C 中的 I2C_NUM_0)
   - I2S_ROLE_MASTER:ESP32 作为 I2S 主设备(Master)
     主设备产生和控制时钟(MCK、BCK、WS),从设备(编解码器)同步于这些时钟
   函数返回一个预配置的结构体,包含常见默认设置 */

i2s_std_config_t std_cfg = {
    /* 创建 I2S 标准模式配置结构体 std_cfg。
       标准模式是最常用的 I2S 工作模式,支持 Philips 标准格式 */

    .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
    /* 配置 I2S 时钟。
       I2S_STD_CLK_DEFAULT_CONFIG(16000) 宏基于 16000Hz 采样率生成
       默认时钟配置,包括:
       - 采样率(Sample Rate):16000Hz(16kHz)
       - MCK 频率:16000 × 256 = 4.096MHz
       - BCK 频率:根据采样位深和声道数计算
       这是一个适合语音识别和通讯的采样率 */

    .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_MONO),
    /* 配置 I2S 插槽(Slot)模式,即数据格式和声道配置。
       I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG 生成 Philips 标准 I2S 格式配置:
       - 第一个参数 16:采样位深为 16 位(16bit),表示每个音频样本用 16 比特表示
         范围 -32768 到 +32767(有符号整数)
       - 第二个参数 I2S_SLOT_MODE_MONO:单声道模式
         单声道使用一个 I2S 时间槽(Slot),数据通过左或右通道传输
         相比立体声(需两个 Slot)节省带宽 */

    .gpio_cfg = {
        /* I2S 接口的 GPIO 引脚配置 */

        .mclk = I2S_MCK_PIN,
        /* 设置主时钟引脚为 I2S_MCK_PIN(GPIO_NUM_3)。
           MCK 是 I2S 的参考时钟,频率 = 采样率 × 256 */

        .bclk = I2S_BCK_PIN,
        /* 设置位时钟引脚为 I2S_BCK_PIN(GPIO_NUM_2)。
           BCK 同步每个比特的传输 */

        .ws = I2S_DATA_WS_PIN,
        /* 设置字选择/帧同步引脚为 I2S_DATA_WS_PIN(GPIO_NUM_5)。
           WS 用于标记帧边界和声道区分(对单声道仍需使用) */

        .dout = I2S_DATA_OUT_PIN,
        /* 设置数据输出引脚为 I2S_DATA_OUT_PIN(GPIO_NUM_6)。
           此引脚输出播放(Playback)音频数据,连接到编解码器的 DIN */

        .din = I2S_DATA_IN_PIN,
        /* 设置数据输入引脚为 I2S_DATA_IN_PIN(GPIO_NUM_4)。
           此引脚接收录音(Record)音频数据,连接到编解码器的 DOUT */
    },
};
/* 结束 i2s_std_config_t 结构体初始化 */

// 创建通道
i2s_new_channel(&chan_cfg,
                &speakerHandle,
                &micHandle);
/* 调用 API 基于上述配置创建 I2S 通道。
   参数说明:
   - &chan_cfg:指向通道配置的指针(Master/Slave 模式等)
   - &speakerHandle:指向扬声器通道句柄的指针(发送/TX 通道)
     此句柄用于控制扬声器播放数据流
   - &micHandle:指向麦克风通道句柄的指针(接收/RX 通道)
     此句柄用于控制麦克风录音数据流
   注意:一个 I2S 端口可支持多个虚拟通道(如收发分离)*/

// 初始化通道
i2s_channel_init_std_mode(speakerHandle, &std_cfg);
/* 调用 API 初始化扬声器通道为标准 I2S 模式。
   参数:
   - speakerHandle:扬声器通道句柄
   - &std_cfg:指向标准模式配置的指针(包含时钟、插槽、GPIO 配置)
   此调用配置扬声器通道的所有工作参数 */

i2s_channel_init_std_mode(micHandle, &std_cfg);
/* 调用 API 初始化麦克风通道为标准 I2S 模式。
   参数同上,配置麦克风通道的所有工作参数 */

// 通道使能
i2s_channel_enable(speakerHandle);
/* 调用 API 启用(使能)扬声器通道。
   此调用后扬声器通道准备好接收播放数据并产生 I2S 信号 */

i2s_channel_enable(micHandle);
/* 调用 API 启用(使能)麦克风通道。
   此调用后麦克风通道准备好接收 I2S 信号并提供录音数据 */

}
/* 结束 bsp_sound_i2s_init 函数 */

// ============================================================================
// ES8311 编解码器初始化函数
// ============================================================================

void bsp_sound_es8311_init(void)
{
/* 此函数初始化 ES8311 音频编解码器芯片及其驱动程序。
ES8311 是一个集成音频模数转换器(ADC)和数模转换器(DAC)的芯片,
可进行音频的录音和播放,通过 I2C 进行控制。
参数:无
返回值:无
*/

// i2s配置
audio_codec_i2s_cfg_t i2s_cfg = {
    /* 创建 I2S 配置结构体 i2s_cfg,用于连接 I2S 硬件和编解码器驱动 */

    .rx_handle = micHandle,
    /* 设置 I2S 接收通道句柄为 micHandle。
       rx(receive)对应录音数据流,来自麦克风/模拟输入。
       编解码器驱动将通过此句柄写入录音数据 */

    .tx_handle = speakerHandle,
    /* 设置 I2S 发送通道句柄为 speakerHandle。
       tx(transmit)对应播放数据流,发往扬声器/模拟输出。
       编解码器驱动将通过此句柄读取播放数据 */
};
/* 结束 i2s_cfg 初始化 */

// 数据接口
const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg);
/* 调用 API 根据 i2s_cfg 创建 I2S 数据接口抽象对象。
   返回 data_if 指针指向一个数据接口结构体,包含如何通过 I2S 收发数据的方法函数。
   此接口将被后续的编解码器设备配置使用 */

// i2配置
audio_codec_i2c_cfg_t i2c_cfg = {
    /* 创建 I2C 配置结构体 i2c_cfg,用于 ES8311 的控制通信 */

    .addr = ES8311_CODEC_DEFAULT_ADDR,
    /* 设置 ES8311 芯片的 I2C 从地址。
       ES8311_CODEC_DEFAULT_ADDR 是 Espressif 驱动定义的默认 I2C 地址,
       通常为 0x18(十进制 24)。此地址用于与芯片通信 */

    .port = I2C_NUM_0,
    /* 设置使用 I2C 端口 0(与前面 bsp_sound_i2c_init 中创建的总线对应) */

    .bus_handle = i2c_bus_handle
    /* 设置 I2C 总线句柄为之前创建的 i2c_bus_handle。
       驱动程序使用此句柄访问 I2C 总线 */
};
/* 结束 i2c_cfg 初始化 */

// 控制接口
const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
/* 调用 API 根据 i2c_cfg 创建 I2C 控制接口抽象对象。
   返回 out_ctrl_if 指针指向一个控制接口结构体,包含如何通过 I2C
   读写 ES8311 寄存器的方法函数 */

// gpio接口
const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();
/* 调用 API 创建 GPIO 接口抽象对象。
   返回 gpio_if 指针指向一个 GPIO 接口结构体,用于控制功率放大器(PA)
   和其他需要 GPIO 控制的功能。无参数,使用系统默认的 GPIO 实现 */

es8311_codec_cfg_t es8311_cfg = {
    /* 创建 ES8311 编解码器配置结构体 es8311_cfg */

    .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH,
    /* 设置编解码器工作模式。
       ESP_CODEC_DEV_WORK_MODE_BOTH 表示同时支持:
       - 播放模式(DAC):播放数字信号到模拟扬声器
       - 录音模式(ADC):从模拟麦克风录制数字信号
       其他模式包括仅播放或仅录音 */

    .ctrl_if = out_ctrl_if,
    /* 设置控制接口为前面创建的 out_ctrl_if */

    .gpio_if = gpio_if,
    /* 设置 GPIO 接口为前面创建的 gpio_if */

    .pa_pin = PA_GPIO,
    /* 设置功率放大器(PA)控制引脚为 PA_GPIO(GPIO_NUM_7)。
       驱动程序在需要启用扬声器时会控制此引脚(拉高),
       在不需要时会禁用(拉低)以节省功耗 */

    .use_mclk = true,
    /* 启用 MCLK(主时钟)使用。
       true 表示 ES8311 需要 I2S MCK 作为参考时钟。
       MCK 用于生成内部时钟,确保与 I2S 接口同步 */
};
/* 结束 es8311_cfg 初始化 */

// 创建编码器接口
const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);
/* 调用 API 根据 es8311_cfg 创建 ES8311 编解码器接口抽象对象。
   返回 out_codec_if 指针指向一个编解码器接口结构体,包含所有
   与 ES8311 芯片交互的方法函数 */

// 编解码器设备配置
esp_codec_dev_cfg_t dev_cfg = {
    /* 创建编解码器设备配置结构体 dev_cfg */

    .codec_if = out_codec_if,
    /* 设置编解码器接口为前面创建的 out_codec_if(ES8311) */

    .data_if = data_if,
    /* 设置数据接口为前面创建的 data_if(I2S) */

    .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT
    /* 设置设备类型为支持输入和输出。
       ESP_CODEC_DEV_TYPE_IN_OUT 表示:
       - 输入(Input):通过 ADC 接收麦克风数据
       - 输出(Output):通过 DAC 发送扬声器数据
       其他类型包括仅输入或仅输出 */
};
/* 结束 dev_cfg 初始化 */

codec_dev = esp_codec_dev_new(&dev_cfg);
/* 调用 API 根据 dev_cfg 创建编解码器设备。
   此函数综合编解码器接口和数据接口,返回一个高层次的
   编解码器设备句柄 codec_dev,用于后续的音频操作 */

// 设置音量
esp_codec_dev_set_out_vol(codec_dev, 80.0);
/* 调用 API 设置输出音量为 80.0(通常是百分比或 0-100 的值)。
   参数:
   - codec_dev:编解码器设备句柄
   - 80.0:输出音量级别(DAC 音量,用于控制扬声器音量)
   此设置在初始化时设定默认播放音量 */

// 设置输入增益
esp_codec_dev_set_in_gain(codec_dev, 10.0);
/* 调用 API 设置输入增益为 10.0(单位通常是 dB 或百分比)。
   参数:
   - codec_dev:编解码器设备句柄
   - 10.0:输入增益级别(ADC 增益,用于放大麦克风信号)
   此设置在初始化时设定默认录音增益,使低幅度的麦克风信号放大 */

}
/* 结束 bsp_sound_es8311_init 函数 */

// ============================================================================
// 音频模块总初始化函数
// ============================================================================

void bsp_sound_init(void)
{
/* 此函数是音频子系统的总初始化入口,按照依赖顺序初始化各个模块。
参数:无
返回值:无
*/

// 1. i2c的初始化
bsp_sound_i2c_init();
/* 第一步:初始化 I2C 总线。
   I2C 是 ES8311 的控制通道,必须首先初始化以便后续通过 I2C
   配置编解码器 */

// 2. i2s的初始化
bsp_sound_i2s_init();
/* 第二步:初始化 I2S 接口。
   I2S 是音频数据的传输通道,需要在 I2C 之后初始化以便
   建立 I2S 通道和时钟配置 */

// 3. es8311的初始化
bsp_sound_es8311_init();
/* 第三步:初始化 ES8311 编解码器。
   此步骤依赖前两步已完成,利用已初始化的 I2C 和 I2S 接口
   来配置 ES8311 芯片的工作模式、音量、增益等参数 */

}
/* 结束 bsp_sound_init 函数 */

// ============================================================================
// 音频设备打开函数
// ============================================================================

void bsp_sound_open(void)
{
/* 此函数打开音频设备,使其准备好进行音频数据的读写操作。
必须在 bsp_sound_init() 后调用,以启动编解码器的工作。
参数:无
返回值:无
*/

esp_codec_dev_sample_info_t fs = {
    /* 创建音频采样信息结构体 fs(Frequency Sample Info)*/

    .sample_rate = 16000,
    /* 设置采样率为 16000Hz(16kHz)。
       采样率定义每秒采集/输出的音频样本数。
       16kHz 是语音识别和语音通讯的标准采样率 */

    .channel = 1,
    /* 设置通道数为 1,表示单声道。
       1 = 单声道(Mono):仅有一个音频通道
       2 = 立体声(Stereo):左右两个独立通道 */

    .bits_per_sample = 16,
    /* 设置每个采样的位深为 16 比特。
       16bit 采样深度能表示 65536 个不同的幅度值(-32768 到 +32767)
       提供足够的动态范围和信噪比用于语音 */
};
/* 结束 fs 结构体初始化 */

if (codec_dev) {
    /* 检查编解码器设备句柄是否有效(非 NULL)*/

    esp_codec_dev_open(codec_dev, &fs);
    /* 调用 API 打开编解码器设备。
       参数:
       - codec_dev:编解码器设备句柄
       - &fs:指向采样信息结构体的指针
       此调用会初始化 ADC/DAC,启动编解码器工作,
       使其准备好进行音频读写 */
}
/* 结束 if 条件块 */

}
/* 结束 bsp_sound_open 函数 */

// ============================================================================
// 音频设备关闭函数
// ============================================================================

void bsp_sound_close(void)
{
/* 此函数关闭音频设备,停止音频处理并释放相关资源。
参数:无
返回值:无
*/

if (codec_dev) {
    /* 检查编解码器设备句柄是否有效(非 NULL)*/

    esp_codec_dev_close(codec_dev);
    /* 调用 API 关闭编解码器设备。
       参数:codec_dev - 编解码器设备句柄
       此调用会停止 ADC/DAC 工作,关闭编解码器,节省功耗 */
}
/* 结束 if 条件块 */

}
/* 结束 bsp_sound_close 函数 */

// ============================================================================
// 音频数据写入函数(用于播放)
// ============================================================================

db_state_t bsp_sound_write(uint8_t data, int size)
{
/
此函数将音频数据写入编解码器进行播放。

   参数说明:
   - data:指向音频数据缓冲区的指针,包含要播放的 PCM 数据
   - size:音频数据的字节数

   返回值:
   - DB_OK:写入成功
   - DB_ERROR:写入失败(输入参数无效或设备未就绪)
*/

if (codec_dev && data && size > 0) {
    /* 检查三个条件:
       - codec_dev:编解码器设备句柄是否有效(非 NULL)
       - data:数据指针是否有效(非 NULL)
       - size > 0:要写入的数据大小是否大于 0
       三个条件都满足才进行写入操作 */

    return esp_codec_dev_write(codec_dev, data, size) == ESP_CODEC_DEV_OK ? DB_OK : DB_ERROR;
    /* 调用 API 将数据写入编解码器。
       参数:
       - codec_dev:编解码器设备句柄
       - data:指向要写入的音频数据的指针
       - size:数据大小

       函数返回值检查(三元操作符):
       - 如果返回 ESP_CODEC_DEV_OK(成功),则返回 DB_OK
       - 否则返回 DB_ERROR(失败)

       函数会将 PCM 数据发送到 ES8311 DAC,经过功率放大后
       驱动扬声器发声 */
}

return DB_ERROR;
/* 如果参数检查失败,返回错误状态码 */

}
/* 结束 bsp_sound_write 函数 */

// ============================================================================
// 音频数据读取函数(用于录音)
// ============================================================================

/**

  • @brief 读取麦克风的数据

  • @param data 数据存储的缓冲区

  • @param size 读取的数据长度
    /
    db_state_t bsp_sound_read(uint8_t data[], int size)
    {
    /
    此函数从编解码器读取音频数据(来自麦克风)。
    麦克风通过模拟信号输入 ES8311,经过 ADC 转换为数字 PCM 数据,
    此函数将 PCM 数据从编解码器读出。

    参数说明:
    - data[]:指向音频数据缓冲区的数组,用于存储读取的麦克风数据
    - size:要读取的数据字节数
    
    返回值:
    - DB_OK:读取成功
    - DB_ERROR:读取失败(输入参数无效或设备未就绪)
    

    */

    if (codec_dev && data && size > 0) {
    /* 检查三个条件:
    - codec_dev:编解码器设备句柄是否有效(非 NULL)
    - data:缓冲区指针是否有效(非 NULL)
    - size > 0:要读取的数据大小是否大于 0
    三个条件都满足才进行读取操作 */

     return esp_codec_dev_read(codec_dev, data, size) == ESP_CODEC_DEV_OK ? DB_OK : DB_ERROR;
     /* 调用 API 从编解码器读取数据。
        参数:
        - codec_dev:编解码器设备句柄
        - data:指向缓冲区的指针,用于存储读取的数据
        - size:要读取的字节数
    
        函数返回值检查(三元操作符):
        - 如果返回 ESP_CODEC_DEV_OK(成功),则返回 DB_OK
        - 否则返回 DB_ERROR(失败)
    
        此函数阻塞式调用,会从 ADC 读取麦克风采集的 PCM 数据。
        应用可以进行进一步处理,如语音识别、压缩编码等 */
    

    }

    return DB_ERROR;
    /* 如果参数检查失败,返回错误状态码 /
    }
    /
    结束 bsp_sound_read 函数 */

// ============================================================================
// 文件结束
// ============================================================================

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐