一、arduino-audio-tools 简介

项目归属 :开源仓库,作者 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支持说明
- 底层兼容体系 这个库原生适配 ESP-IDF ,仓库里自带
idf_component.yml、CMake 编译脚本,ESP32-S3 在 ESP-IDF 官方框架内完整支持 I2S 外设,库的I2SStream驱动可以直接调用 S3 的硬件 I2S。 - 仓库内已有 S3 相关示例 源码文件夹
examples中包含 ESP32-S3、LVGL 搭配音频的示例工程,作者持续在新版本修复 ESP32 系列(C3/S2/S3/C6)的兼容性问题,最新 2026 年 6 月版本迭代依然在完善 ESP32 系列 USB 音频、I2S 配置。 - ESP32-S3 可使用的全部能力
- 硬件 I2S 外接 DAC/ADC 播放、录音
- S3 内置 USB OTG 声卡输入输出(库明确标注支持 USB Audio)
- MP3/WAV/FLAC/AAC 软解码播放
- 内置 DSP 音效:混响、回声、三段均衡、滤波、音调生成
- WiFi 蓝牙音频串流、SD 卡文件播放、Flash 内置音频播放
4、安装方式
- Arduino IDE:下载 ZIP 包导入;或 Git 克隆至 Arduino libraries 目录,
git pull一键更新 - PlatformIO / ESP-IDF:原生支持,可作为组件直接引入工程
内置极简 Demo:Flash 存储音频文件 → 内存流读取 → I2S 输出,通过StreamCopy自动搬运音频数据,loop 循环持续拷贝即可播放。
使用注意事项:
- Arduino IDE 要升级 ESP32 Arduino 核心包到较新版本(2.0.10+),保证 S3 板子定义正常;
- I2S 引脚需要按照 ESP32-S3 数据手册重新定义,不要直接照搬 ESP32-WROOM 的引脚;
- 使用 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 完成。
宏定义(库内置)说明:
RX_MODE:I2S 接收模式(录音)TX_MODE:I2S 发送模式(播放)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)
成员函数
- defaultConfig(RX_MODE)****/ defaultConfig(TX_MODE)
RX_MODE:生成**I2S 输入(录音)**默认配置;TX_MODE:生成I2S 输出(播放) 默认配置; 返回I2SConfigESP32V1配置结构体,你再修改引脚、采样率、声道、位深、buffer_size。
- 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 输出 DINsample_rate:采样率channels:声道数bits_per_sample:采样位深buffer_size:DMA 缓冲区大小(可选,控制延迟、抗卡顿)
2. StreamCopy 类(核心转发功能)
StreamCopy copier(i2s_out, i2s_in);
构造参数:StreamCopy(目标输出流, 源输入流) 作用:从源流读取音频字节,自动拷贝写入目标流,实现音频数据流转发。
成员函数
- copier.copy() 在 loop 循环反复调用。
- 非阻塞函数:每次调用拷贝一块可用音频数据,不会阻塞死等;
- 内部逻辑:从
i2s_in(I2S0录音)读 DMA 缓冲区数据 → 直接写入i2s_out(I2S1播放); - 返回值:成功拷贝的字节数;返回 0 代表当前没有可用数据。
✨这就是 "录音直接推送播放" 的关键,没有中间文件、没有用户数组缓存,数据在库内部 DMA 流转。
StreamCopy 适配所有继承 Stream 的对象:MemoryStream、I2SStream、FileStream 都可以互相拷贝。