Skip to content

SDD-00:项目启动与价值边界定义

SDD-00:项目启动与价值边界定义

Section titled “SDD-00:项目启动与价值边界定义”

项目名称:esp-audio-stream
中文名称:ESP32 产品级实时音频流传输层
阶段状态:00 环节结论版
目标状态:进入 SDD-01 前的项目基线


esp-audio-stream 是一个面向 ESP32 系列资源受限设备的实时音频流传输策略层,用于让设备侧音频上行、服务端音频下行以及未来双向音频流在弱网、断线、慢消费、慢播放、队列堆积、播放缓冲下溢等真实产品场景下保持可控、可观测、可恢复。

它不是音频框架,不是 WebRTC 重写,不是 WebSocket Demo,也不是协议合集。


最初项目偏向 Audio Uplink Transport Layer,重点是设备麦克风音频上传。

经过重新审视,真实语音产品通常不只有上行:

  • 设备麦克风音频上传到云端。
  • 云端 TTS / 语音回复下发到设备播放。
  • 远程播报或云端音频流下发。
  • 未来可能支持半双工或全双工语音交互。
  • 上行和下行都需要状态、缓冲、重连、丢弃、统计和故障诊断。

因此项目定位从:

ESP32 产品级实时音频上行传输层

修正为:

ESP32 产品级实时音频流传输层

也就是从单向 uplink 升级为更完整的 audio stream transport。


ESP32 发送或接收音频并不难。

难的是在真实产品中回答这些问题:

  • Wi-Fi 断开后如何恢复?
  • 服务端消费变慢时,音频发送队列是否会无限堆积?
  • 网络恢复后,是否应该继续发送旧音频?
  • 实时上行音频的最大延迟如何控制?
  • 音频采集任务会不会被网络发送阻塞?
  • 上行失败时,如何定位是 Wi-Fi、DNS、TLS、Socket、服务端还是队列问题?
  • 云端 TTS 音频下发中断后如何恢复?
  • 网络抖动时播放缓冲如何控制?
  • 下行音频是否需要保序、丢弃、截断或重新同步?
  • 播放端消费变慢时,接收队列是否会无限增长?
  • 播放缓冲下溢时,如何上报和恢复?
  • 新的语音回复到达时,是否应该打断旧的下行音频?
  • 设备端如何区分网络问题、解码问题、播放问题和服务端问题?
  • 上行和下行是否共享同一连接?
  • 控制消息、上行音频和下行音频是否应该分离?
  • 半双工 / 全双工场景下如何管理方向状态?
  • 如何统一统计收发两端的时延、队列、丢帧、重连和错误?

本项目的核心问题不是“用什么协议传音频”,而是:

在 ESP32 等资源受限设备上,如何构建一个产品级实时音频流传输层,使上行、下行和未来双向音频流在复杂网络条件下具备明确的行为边界、可诊断能力和可恢复能力。


为避免低价值重复和范围失控,本项目明确不做:

  • 不做 I2S 麦克风驱动。
  • 不做扬声器 / I2S 播放驱动。
  • 不做音频编解码库。
  • 不做完整音频 pipeline 框架。
  • 不重写 ESP-ADF。
  • 不重写 WebRTC。
  • 不做 SIP / RTSP / RTMP 协议栈。
  • 不做通用网络库。
  • 不做云端语音识别 SDK。
  • 不做云端 TTS SDK。
  • 不做“ESP32 WebSocket 音频上传 Demo”。
  • 不做“ESP32 WebSocket 音频播放 Demo”。
  • 不以“支持协议数量”作为核心价值。

本项目只聚焦一个层次:

Audio Capture / Encoder Audio Decoder / Player
↓ ↑
└────── esp-audio-stream ─────────┘
↓ ↑
Protocol Backend
↓ ↑
Server / Cloud / AI Service

本项目主要负责:

  • 统一音频帧模型。
  • 上行音频帧序号与时间戳。
  • 下行音频帧序号与时间戳。
  • 有界发送队列。
  • 有界接收 / 播放队列。
  • 最大队列时长控制。
  • 最大音频帧生命周期控制。
  • 过期音频帧丢弃。
  • 队列满时的丢帧策略。
  • 播放缓冲下溢 / 溢出统计。
  • 采集、发送、接收、播放之间的解耦。
  • 控制面与数据面分离。
  • 方向状态管理:uplink / downlink / bidirectional。
  • 连接状态机。
  • 重连与恢复策略。
  • 传输统计指标。
  • 错误分类。
  • 弱网测试工具。
  • 参考服务端 / 接收端 / 下发端实现。
  • 协议 backend 抽象。

ESP-ADF 是本项目必须研究、兼容和借势的生态基座,但不是本项目的直接竞品。

ESP-ADF 的定位是:

ESP32 音频应用开发框架

它适合处理 audio pipeline、audio element、ringbuffer、codec、I2S stream、HTTP stream、播放器、录音器、蓝牙音频、VoIP、RTSP/SIP/RTMP 等音频应用场景。

本项目的定位是:

实时音频流传输策略层

它只关注:

  • 实时音频上行。
  • 实时音频下行。
  • 未来双向音频流。
  • 弱网行为。
  • 收发队列策略。
  • 音频帧生命周期。
  • 播放缓冲行为。
  • 重连恢复。
  • 传输状态机。
  • 传输可观测性。
  • 协议 backend 抽象。
  • 产品级测试与诊断。

因此,本项目不替代 ESP-ADF。

正确关系是:

ESP-ADF / ESP-IDF / I2S / Codec / Player
↓ ↑
esp-audio-stream
↓ ↑
WebSocket / UDP / RTP-like / WebRTC adapter
↓ ↑
Server / Cloud / AI Backend

未来本项目既可以独立用于 ESP-IDF 项目,也可以作为 ESP-ADF pipeline 中的 stream transport element 使用。


本项目不反对直接使用 WebSocket 或 WebRTC。

对于 Demo、局域网测试、简单音频上传或播放、小规模产品,直接 WebSocket 发送/接收音频可能已经足够。

对于完整实时音视频通信、浏览器互通、NAT 穿透、多方通信等场景,WebRTC 可能是更合适的选择。

但是,WebSocket 和 WebRTC 不是本项目要解决的全部问题。

本项目关注的是协议之上的产品行为:

  • 上行发送队列是否有上限?
  • 下行接收 / 播放队列是否有上限?
  • 音频帧是否有生命周期?
  • 网络阻塞时是否会拖死采集任务?
  • 播放阻塞时是否会拖死接收任务?
  • 服务端慢消费时上行延迟是否无限增长?
  • 客户端慢播放时下行延迟是否无限增长?
  • 断线重连后是否会补发或播放过期音频?
  • 错误原因是否可分类?
  • 指标是否可观测?
  • backend 是否可替换?

因此,本项目不替代 WebSocket,也不替代 WebRTC。

WebSocket、UDP、RTP-like、WebRTC、QUIC 等都应被视为 backend,而不是架构中心。


本项目的价值不在于“又实现了一个传输协议”。

本项目的价值在于:

把实时音频流传输过程中容易被 Demo 忽略的弱网、队列、重连、丢帧、播放缓冲、状态、统计和诊断问题,抽象成一个可复用、可测试、可维护的产品级传输策略层。

一句话总结:

协议能传音频,不代表产品级音频流行为可控。

本项目要证明的是:

在相同硬件、相同音频源、相同网络故障、相同服务端条件下,
策略层方案比直接发包 / 直接收包方案更可控、更可观测、更容易恢复。

本项目第一阶段不直接对标 ESP-ADF。

第一阶段真正的价值验证对象是:

Direct WebSocket Baseline

包括:

Uplink Baseline:
Audio Frame → websocket_send()
Downlink Baseline:
websocket_recv() → Audio Frame → player_write()

我们必须证明:

Audio Frame ↔ esp-audio-stream ↔ WebSocket Backend

在真实异常条件下比直接 WebSocket 收发更可控。


V0 / MVP 不追求多协议,也不要求同时把上行和下行做到完整产品形态。

首版最小有价值形态建议是:

统一 AudioFrame
+ 方向字段:uplink / downlink / control
+ 有界发送队列
+ 有界接收 / 播放队列
+ 音频帧生命周期
+ 丢帧 / 丢包 / 丢播放策略
+ WebSocket backend
+ 连接状态机
+ 重连恢复
+ 收发统计
+ 错误分类
+ 测试服务端
+ 故障注入工具
+ Direct WebSocket baseline 对比

首版可以优先把上行验证做深,同时保留下行接口、状态和测试框架,避免项目名和抽象被 uplink 锁死。

首版不做:

完整 WebRTC backend
完整 QUIC backend
完整 RTP/RTCP 实现
完整 SIP/RTSP/RTMP 支持
复杂自适应码率
复杂拥塞控制
完整云端 SDK
完整播放器框架
完整 TTS SDK

原则 1:协议是 backend,不是架构中心

Section titled “原则 1:协议是 backend,不是架构中心”

项目不能围绕“我要支持 WebSocket、UDP、WebRTC、QUIC”展开。

应该围绕:

AudioFrame
StreamSession
StreamDirection
FrameQueue
PlayQueue
TransportPolicy
StateMachine
Stats
Backend

展开。

原则 2:实时音频优先保证新鲜度

Section titled “原则 2:实时音频优先保证新鲜度”

实时语音不是文件上传,也不是普通音频文件播放。

旧的上行音频在很多场景下没有继续发送的价值。旧的下行音频在交互场景中也可能已经不应该继续播放。

因此,模块默认应支持:

  • 最大帧年龄。
  • 最大发送队列时长。
  • 最大接收 / 播放队列时长。
  • 过期帧丢弃。
  • 重连后丢弃过期音频。
  • 新响应打断旧下行音频的策略。

不允许因为网络阻塞、服务端慢消费或播放慢消费导致音频帧无限堆积。

队列至少需要以下限制:

  • 最大字节数。
  • 最大帧数。
  • 最大缓存时长。
  • 最大帧生命周期。

原则 4:采集、发送、接收、播放必须解耦

Section titled “原则 4:采集、发送、接收、播放必须解耦”

采集任务不应该被网络发送长期阻塞。

接收任务不应该被播放任务长期阻塞。

发送端和播放端都需要明确的背压与丢弃策略。

控制消息和音频帧不应该被同等对待。

控制面:

auth / start / stop / interrupt / heartbeat / config / stats / error

数据面:

uplink audio frame / downlink audio frame / sequence / timestamp / codec / payload

控制消息更关注可靠性。音频帧更关注低延迟、生命周期和可控丢弃。

模块必须能解释:

  • 当前连接状态。
  • 当前方向状态。
  • 是否正在重连。
  • 上行队列中堆积了多少音频。
  • 下行 / 播放队列中堆积了多少音频。
  • 丢了多少上行帧。
  • 丢了多少下行帧。
  • 是否发生播放下溢。
  • send / recv / decode / play 失败原因。
  • 最近一次 backend 错误。
  • Wi-Fi 是否断开。
  • 服务端是否慢消费。
  • 客户端是否慢播放。
  • heap 是否持续下降。
  • task stack 是否危险。

本项目不能因为“架构看起来合理”就成立。

必须通过 baseline 对比证明:

策略层方案带来的收益 > 额外 RAM / CPU / 代码复杂度成本

进入 SDD-01 前,需要接受以下基线:

  • 项目定位已经确定为实时音频流传输层,而不是只做 uplink。
  • 第一阶段可以优先验证上行,但架构必须覆盖下行。
  • ESP-ADF 是生态基座,不是直接竞品。
  • Direct WebSocket 是第一阶段 baseline。
  • WebSocket backend 是 MVP 第一 backend。
  • UDP / RTP-like backend 作为 Phase 2。
  • WebRTC / QUIC 只作为未来 adapter 研究。
  • 第一阶段必须包含价值验证实验。
  • 不通过价值验证,不进入大规模架构设计。

本项目值得继续,但前提是始终坚持以下判断:

让 ESP32 收发音频不稀缺;
让 ESP32 在真实网络环境下稳定、可控、可诊断地持续处理实时音频流,才是价值。

因此,00 环节结论为:

继续推进本项目,但不得做成 ESP-ADF 的低配替代品、WebRTC 的重写版本或 WebSocket 音频 Demo。项目定位应从上行音频上传扩展为实时音频流传输,覆盖上行、下行和未来双向场景。下一阶段应围绕 Direct WebSocket baseline 与 Policy Layer candidate 的价值验证展开。只有当策略层能通过实验数据证明其可控性、可观测性和恢复能力优于直接收发方案时,项目才具备继续开源和产品化的价值。