基于ESP8266Audio库实现ESP8266多WAV文件带时间戳播放需求
基于ESP8266的多音频流时间戳播放实现
我正在开发基于ESP8266的脚本,使用ESP8266Audio库播放多个十六进制编码的WAV文件,需要实现不同时间戳的多音频流播放。硬件采用ESP8266与TIP 120晶体管,现有代码如下:
#include <Arduino.h> #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorWAV.h" #include "AudioOutputI2SNoDAC.h" #include <ESP8266WiFi.h> #include <SPI.h> #include <SD.h> // VIOLA 采样来自声音示例库 #include "viola.h" #include "viola02.h" AudioGeneratorWAV *wav; AudioFileSourcePROGMEM *file; AudioOutputI2SNoDAC *out; void setup() { Serial.begin(115200); delay(1000); Serial.printf("WAV start\n"); audioLogger = &Serial; out = new AudioOutputI2SNoDAC(); // out02 = new AudioOutputI2SNoDAC(); // out -> SetGain(0.08); } void Play(const void *data, uint32_t len) { file = new AudioFileSourcePROGMEM( data, len ); wav = new AudioGeneratorWAV(); wav->begin(file, out); delay(3000); while (true) { if (wav->isRunning()) { if (!wav->loop()) wav->stop(); } else { Serial.printf("WAV done\n"); delay(1000); break; } } } void loop() { Play(viola,sizeof(viola)); Play(viola02,sizeof(viola02)); }
现有代码问题
当前代码是串行阻塞式播放:Play函数里的while(true)和delay会彻底卡住主循环,两个音频只能按顺序播放,完全无法实现多流同时按时间戳触发的需求。
解决方案:非阻塞多音频流实现
要实现不同时间戳的多音频播放,需要给每个音频流创建独立的播放实例,在主循环中异步处理每个流的播放逻辑,避免阻塞。
修改后的代码示例
#include <Arduino.h> #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorWAV.h" #include "AudioOutputI2SNoDAC.h" #include <ESP8266WiFi.h> #include <SPI.h> #include <SD.h> #include "viola.h" #include "viola02.h" // 定义音频流结构体,存储实例、启动时间戳等信息 struct AudioStream { AudioGeneratorWAV* wav; AudioFileSourcePROGMEM* file; unsigned long startTimestamp; // 启动时间(系统运行毫秒数) bool isInitialized; // 是否已创建播放实例 const void* data; uint32_t len; }; AudioOutputI2SNoDAC *out; AudioStream streams[2]; // 管理两个音频流 void setup() { Serial.begin(115200); delay(1000); Serial.printf("Multi-Audio Stream Start\n"); audioLogger = &Serial; out = new AudioOutputI2SNoDAC(); out->SetGain(0.08); // 根据实际音量需求调整增益 // 初始化音频流参数 streams[0] = {nullptr, nullptr, 2000, false, viola, sizeof(viola)}; // 系统启动后2秒播放viola streams[1] = {nullptr, nullptr, 5000, false, viola02, sizeof(viola02)}; // 系统启动后5秒播放viola02 } void loop() { unsigned long currentMillis = millis(); for (int i = 0; i < 2; i++) { AudioStream& stream = streams[i]; // 到达启动时间且未初始化时,创建播放实例 if (currentMillis >= stream.startTimestamp && !stream.isInitialized) { stream.file = new AudioFileSourcePROGMEM(stream.data, stream.len); stream.wav = new AudioGeneratorWAV(); stream.wav->begin(stream.file, out); stream.isInitialized = true; Serial.printf("Started audio stream %d\n", i+1); } // 已初始化且正在播放时,执行播放循环 if (stream.isInitialized && stream.wav->isRunning()) { if (!stream.wav->loop()) { stream.wav->stop(); // 播放完成后释放内存,避免ESP8266资源耗尽 delete stream.wav; delete stream.file; stream.wav = nullptr; stream.file = nullptr; stream.isInitialized = false; Serial.printf("Completed audio stream %d\n", i+1); } } } }
关键说明
- 非阻塞逻辑:用
millis()获取系统运行时间替代delay,通过时间戳判断是否启动音频,主循环始终保持响应。 - 独立实例:每个音频流拥有专属的
AudioGeneratorWAV和AudioFileSourcePROGMEM实例,避免资源冲突。 - 资源回收:播放完成后主动释放实例内存,适配ESP8266有限的RAM资源。
- 时间戳控制:通过
startTimestamp字段自由设置每个音频的启动时间,实现多流按计划播放。
硬件注意事项
TIP 120晶体管用于音频放大时,需确保电路连接正确:
- ESP8266的I2S输出引脚串联限流电阻后连接TIP 120基极
- TIP 120集电极接电源,发射极接扬声器,同时并联续流二极管保护器件
内容的提问来源于stack exchange,提问作者Fahim Uz Zaman
相关产品推荐
相关产品推荐

