ESP32音频/语音技术(4)AudioTools 库及转发播放程序分析

一、arduino-audio-tools 简介

GitHub - pschatzmann/arduino-audio-tools: Audio Tools (a powerful Audio library for Microcontrollers and the Desktop) · GitHub

项目归属 :开源仓库,作者 pschatzmann,仓库名 arduino-audio-tools,开源协议 GPL-3.0。平台兼容:Arduino、PlatformIO、ESP-IDF、Zephyr,同时支持 Linux/Windows/macOS 桌面编译运行音频程序,2.4k Star、368 Fork、66 位贡献者、38 个版本发布、4353 次代码提交;代码主体为 C 语言 (85.5%)、C++(8.9%)。定位:轻量、基于头文件的 C++ 音频处理通用库,核心设计思想沿用 Arduino Stream 流体系

1、核心功能模块

1. 音频输入输出(源与输出端)

  • 支持 I2S、模拟 Audio、USB 音频、Flash 内存文件等音频数据源 (Sources)
  • 输出 Sink:I2S 数字功放、模拟喇叭、USB 声卡、网络传输等

2. 编解码支持

内置 MP3/AAC/WAV/FLAC 编码器、解码器,封装 EncodedAudioStream 统一处理编码流

3. 音频 DSP 音效处理

  • 音效:增益、失真、回声、混响等特效 AudioEffectStream
  • 均衡:三段均衡器
  • 滤波器、采样格式转换器、音频数据缓冲队列
  • 支持对接第三方 DSP 库,内置音符频率库、正弦波等音频信号生成器 GeneratedSoundStream

4. 配套工具组件

  • 高精度定时采样器 TimerCallbackAudioStream(精准音频采样时钟)
  • 跨设备有线 / 无线音频传输封装
  • 一体化播放器类 AudioPlayer,简化播放开发
  • 日志系统:分级日志(Debug/Info/Warning/Error),可关闭日志节省内存

2、仓库目录结构关键文件夹

  • src:库核心源码
  • examples:全部示例代码
  • docs:文档
  • jupyter:PC 端音频测试脚本
  • tests-cmake:跨平台 CMake 测试工程
  • 配套编译配置:CMakeLists.txt、idf_component.yml、library.properties 适配多平台编译

3、esp32-s3支持说明

  1. 底层兼容体系 这个库原生适配 ESP-IDF ,仓库里自带 idf_component.yml、CMake 编译脚本,ESP32-S3 在 ESP-IDF 官方框架内完整支持 I2S 外设,库的 I2SStream 驱动可以直接调用 S3 的硬件 I2S。
  2. 仓库内已有 S3 相关示例 源码文件夹 examples 中包含 ESP32-S3、LVGL 搭配音频的示例工程,作者持续在新版本修复 ESP32 系列(C3/S2/S3/C6)的兼容性问题,最新 2026 年 6 月版本迭代依然在完善 ESP32 系列 USB 音频、I2S 配置。
  3. ESP32-S3 可使用的全部能力
  • 硬件 I2S 外接 DAC/ADC 播放、录音
  • S3 内置 USB OTG 声卡输入输出(库明确标注支持 USB Audio)
  • MP3/WAV/FLAC/AAC 软解码播放
  • 内置 DSP 音效:混响、回声、三段均衡、滤波、音调生成
  • WiFi 蓝牙音频串流、SD 卡文件播放、Flash 内置音频播放

4、安装方式

  1. Arduino IDE:下载 ZIP 包导入;或 Git 克隆至 Arduino libraries 目录,git pull一键更新
  2. PlatformIO / ESP-IDF:原生支持,可作为组件直接引入工程

内置极简 Demo:Flash 存储音频文件 → 内存流读取 → I2S 输出,通过StreamCopy自动搬运音频数据,loop 循环持续拷贝即可播放。

使用注意事项:

  1. Arduino IDE 要升级 ESP32 Arduino 核心包到较新版本(2.0.10+),保证 S3 板子定义正常;
  2. I2S 引脚需要按照 ESP32-S3 数据手册重新定义,不要直接照搬 ESP32-WROOM 的引脚;
  3. 使用 USB 音频功能时,S3 的 USB 硬件要正确接线并开启板子 USB 功能。

二、实时录音‑转发播放示例分析

1、 实时录音‑转发播放示例

硬件环境:

  • I2S0:INMP441 MEMS 麦克风(录音输入)
  • I2S1:MAX98357A I2S 功放(音频输出播放) 功能:INMP441 采集音频,不存文件,实时把采集到的数据直接转发给 I2S1 输出到喇叭,实现实时监听 / 对讲。 ⚠️ 会有微小延迟,来自 I2S DMA 缓冲区,属于正常现象。

程序源码:

复制代码
#include "AudioTools.h"

// ---------------引脚定义----------------
// INMP441 I2S0 录音
#define I2S0_BCLK  5
#define I2S0_WS    4
#define I2S0_IN    6

// MAX98357A I2S1 播放输出
#define I2S1_BCLK  15
#define I2S1_WS    16
#define I2S1_OUT   7

// 音频参数 INMP441标准配置
const uint16_t sample_rate = 16000;
const uint8_t channels = 1;        // INMP441单声道
const uint8_t bits_per_sample = 16;

// ✅ 在构造函数指定硬件I2S端口,不再写在config里
I2SStream i2s_in(I2S_NUM_0);    // I2S0 麦克风输入
I2SStream i2s_out(I2S_NUM_1);   // I2S1 MAX98357输出
StreamCopy copier(i2s_out, i2s_in); // 把i2s_in的数据拷贝到i2s_out

void setup() {
    Serial.begin(115200);

    // ========= I2S0 麦克风输入配置 RX_MODE =========
    auto cfg_in = i2s_in.defaultConfig(RX_MODE);
    cfg_in.pin_bck = I2S0_BCLK;
    cfg_in.pin_ws  = I2S0_WS;
    cfg_in.pin_data = I2S0_IN;
    cfg_in.sample_rate = sample_rate;
    cfg_in.channels = channels;
    cfg_in.bits_per_sample = bits_per_sample;
    // 可选调小缓冲区降低延迟
    // cfg_in.buffer_size = 512;
    i2s_in.begin(cfg_in);

    // ========= I2S1 MAX98357输出配置 TX_MODE =========
    auto cfg_out = i2s_out.defaultConfig(TX_MODE);
    cfg_out.pin_bck = I2S1_BCLK;
    cfg_out.pin_ws  = I2S1_WS;
    cfg_out.pin_data = I2S1_OUT;
    cfg_out.sample_rate = sample_rate;
    cfg_out.channels = channels;
    cfg_out.bits_per_sample = bits_per_sample;
    // cfg_out.buffer_size = 512;
    i2s_out.begin(cfg_out);

    Serial.println("录音转发已启动");
}

void loop() {
    // 从i2s_in读音频,直接写入i2s_out,实时转发
    copier.copy();
}

2、AudioTools 库开发分析

(1)数据流与库功能清单

数据流(库内部路径):

INMP441 → I2S0 硬件 → I2SStream (i2s_in) 内部 DMA 缓冲区 → StreamCopy.copy () 搬运 → I2SStream (i2s_out) 内部 DMA 缓冲区 → I2S1 硬件 → MAX98357A 喇叭。

用户代码没有直接操作 read/write,全部交给 StreamCopy 完成。

宏定义(库内置)说明:

  1. RX_MODE:I2S 接收模式(录音)
  2. TX_MODE:I2S 发送模式(播放)
  3. I2S_NUM_0 / I2S_NUM_1:ESP32 硬件 I2S 控制器编号,传入 I2SStream 构造函数。

整体库提供的功能清单:

|-----------------------|---------------------------------------|----------------------|
| 功能模块 | 库提供能力 | 在本程序作用 |
| I2S 硬件抽象 I2SStream | 封装 ESP32 I2S 硬件、DMA,提供 Stream 读写接口 | I2S0 采集麦克风;I2S1 输出功放 |
| 配置系统 defaultConfig () | 快速生成默认参数结构体,修改参数后给 begin () | 设置采样率、声道、引脚 |
| 流拷贝 StreamCopy | 两个 Stream 之间实时搬运字节流 | 实现录音数据实时转发播放 |
| 双 I2S 并发支持 | 支持同时实例化 I2S_NUM_0、I2S_NUM_1 两套 I2S 外设 | 一路录音一路播放同时工作 |

(2)核心类分析

程序中使用双 I2S,INMP441 录音实时转发到 MAX98357 播放。

复制代码
I2SStream i2s_in(I2S_NUM_0);
I2SStream i2s_out(I2S_NUM_1);
StreamCopy copier(i2s_out, i2s_in);

1. I2SStream 类

封装 ESP32 I2S 硬件外设,继承 Arduino Stream,所以可以当作流对象,可读可写。 构造函数:I2SStream(i2s_port) 指定硬件 I2S 端口 (I2S_NUM_0 / I2S_NUM_1)

成员函数

  1. defaultConfig(RX_MODE)****/ defaultConfig(TX_MODE)
  • RX_MODE:生成**I2S 输入(录音)**默认配置;
  • TX_MODE:生成I2S 输出(播放) 默认配置; 返回 I2SConfigESP32V1 配置结构体,你再修改引脚、采样率、声道、位深、buffer_size。
  1. begin(config) 把配置传入,初始化 I2S 硬件、DMA 缓冲区,启动 I2S 外设。 录音端:I2S0 开始接收 INMP441 音频数据存入 DMA 缓冲区; 播放端:I2S1 准备向外输出 I2S 数字音频。

I2SStream 本身内部实现了 read() / write(),上层不用直接调用,交给 StreamCopy 处理。

配置结构体字段(代码修改的)

  • pin_bck:I2S 位时钟引脚
  • pin_ws:I2S 帧时钟 (LRCK) 引脚
  • pin_data:数据引脚;RX 模式是 I2S 输入 SD;TX 模式是 I2S 输出 DIN
  • sample_rate:采样率
  • channels:声道数
  • bits_per_sample:采样位深
  • buffer_size:DMA 缓冲区大小(可选,控制延迟、抗卡顿)

2. StreamCopy 类(核心转发功能)

复制代码
StreamCopy copier(i2s_out, i2s_in);

构造参数:StreamCopy(目标输出流, 源输入流) 作用:从源流读取音频字节,自动拷贝写入目标流,实现音频数据流转发。

成员函数

  1. copier.copy() 在 loop 循环反复调用。
  • 非阻塞函数:每次调用拷贝一块可用音频数据,不会阻塞死等;
  • 内部逻辑:从i2s_in(I2S0录音)读 DMA 缓冲区数据 → 直接写入i2s_out(I2S1播放);
  • 返回值:成功拷贝的字节数;返回 0 代表当前没有可用数据。

✨这就是 "录音直接推送播放" 的关键,没有中间文件、没有用户数组缓存,数据在库内部 DMA 流转。

StreamCopy 适配所有继承 Stream 的对象:MemoryStream、I2SStream、FileStream 都可以互相拷贝。


相关推荐
martindelophy1 小时前
浏览器视频导出太慢怎么优化?一次 WebCodecs 实践:8 分钟视频耗时降低 31%
性能优化·音视频·优化
Dovis(誓平步青云)2 小时前
常用命令藏得太深?怎么做一个快捷命令坞
运维·前端·自动化·音视频·prometheus
microrain3 小时前
读数是 1008,用电量是 8:SagooIoT 计算服务的增量口径与七种计算策略
物联网·golang·计算服务·sagooiot
星恒讯工业路由器5 小时前
从5G-A到6G:工业通信网络的技术演进与产业落地
网络·物联网·5g·智能路由器·工业路由器·工业物联网·5g-a
开开心心就好6 小时前
把手机变成电脑麦克风,WiFi连接就能用
智能手机·ffmpeg·计算机外设·电脑·word·音视频
Dovis(誓平步青云)7 小时前
现场问题先关闭还是先验收,建筑任务怎样处理依赖
前端·javascript·数据库·mysql·音视频
原子延迟8 小时前
视频还没出画面怎么判断是不是坏了
图像处理·人工智能·计算机视觉·音视频
小猴子爱上树9 小时前
跨马翻译:批量图片翻译+视频字幕+智能抠图,跨境电商翻译工具
python·音视频
Evanfu021610 小时前
整部短剧文件怎么管理:目录、命名与版本规则
aigc·音视频·视频·机器翻译·自动翻译