🔧 AI 知识库

我把 ESP32 小喇叭升级成了 TTS 播报版:网页输入文字,设备直接出声

原文链接

我把 ESP32 小喇叭升级成了 TTS 播报版:网页输入文字,设备直接出声

原文链接:https://mp.weixin.qq.com/s/X1Ud811saY39poEefazSjQ?scene=1 作者:PHPer技术 发布时间:2026-05-22 GitHub:https://github.com/Kaiii-create/kai-sound-tts

摘要

从「网页输入 MP3 地址 ESP32 播放」升级为「网页输入任意文本,ESP32 直接出声」。整条链路:网页 → PHP 调度 → Python 火山引擎 TTS → MQTT 下发 → ESP32 HTTP 拉流 → MAX98357A 播放。作者重点不是炫技,而是把每个坑都拆清楚了——长文本断流、MQTT 控制链 vs HTTP 音频链的混淆、插播比想的难得多。


完整链路

网页输入文本
    ↓
PHP 编排请求
    ↓
Python 调用火山引擎 TTS
    ↓
生成可播放 stream_url
    ↓
MQTT 下发给 ESP32
    ↓
ESP32 拉取 HTTP MP3 流
    ↓
MAX98357A 播放

版本定义:v1.0.0-mqtt


三个关键坑

1. 长文本整段播,中途容易断

不是 TTS 生成不了,是播放时间越长 ESP32 越容易撞 WiFi 抖动,HTTP 音频流就断。长文本真正的问题不是「能不能生成」,而是「单条流拉太久,网络一抖就断」。

2. MQTT 控制链和 HTTP 播放链不是一回事

调试时最容易混淆的两条链:

  • MQTT:控制链,告诉 ESP32 去播哪个地址
  • HTTP:音频链,ESP32 自己去拉流

混在一起想就容易判断错问题到底出在哪一层。

3. 插播没想的那么简单

ESP32 在播放 HTTP 流时 MQTT 并不总是稳定,第二条命令未必能在播放中稳稳送到。作者选择先不搞强插播,把顺序播报稳定做扎实。


收敛方案:四个优化

  1. PHP 自动断句分段:按 。!?; 优先断,,、: 再切,长度兜底。不再让 ESP32 一次扛整段长文本。

  2. PHP 预生成每一段 TTS:先全部生成好,播完一段立刻发下一段,省掉「现播现做现等」的等待时间。

  3. ESP32 侧加 AudioFileSourceBuffer 32KB 本地缓冲:网络抖一下不至于立刻断。

  4. 最终结构

用户文本 → PHP 断句分段 → PHP 预生成 TTS stream_url
→ MQTT 下发 tts + url → ESP32 打开 HTTP stream
→ AudioFileSourceBuffer 本地缓冲 → I2S 播放 → MAX98357A 输出

已知边界

问题现状
段间停顿预生成优化后比「现播现做」顺很多,但仍非完全无缝
WiFi 依赖播放稳定性很吃现场网络环境
插播不主打,优先顺序播报稳定
传输层MQTT 控制 + HTTP 拉流,下一版想试 UDP 方向

适合场景

  • 本地语音提示 / 设备播报
  • 物联网语音输出 / 定时提醒
  • 文字转语音硬件联动(ESP32 + MQTT + I2S 音频 + 本地控制页面)

作者的核心感悟

一个硬件项目真正难的地方,往往不是代码本身,而是把整条链路一层一层确认清楚——页面有没有发出请求、PHP 有没有下发 MQTT、Python 有没有生成 TTS、ESP32 有没有收到命令、有没有真的打开流、WiFi 有没有中途抖动、I2S 有没有真的在播。只要有一层没确认清楚,表面现象就可能完全像另一层出了问题。

这个版本的意义不在于「它已经完美了」,而在于「它已经不是一个想法了,而是一条真正跑通、而且已经能工作的链路」。