实时音频传输实验:UDP 与 WSS

本文最后更新于 2026-09-02

声音如何往返

你对着一个语音设备说:“给我讲个故事。”几秒后,扬声器里开始传出回答。我们很容易想到背后的 ASR、LLM 和 TTS,却很少追问另一件事:刚才那句话究竟是怎样到达服务端的,生成后的声音又是怎样回到设备的?

设备并不是等你说完,再把一个完整录音文件上传。更常见的做法是边录、边切帧、边编码、边发送:麦克风采集到的声音被切成几十毫秒一帧,压缩成 Opus 后持续上行;返回的音频也会一帧一帧到达设备,经过缓冲、解码和缺帧处理,最后才进入扬声器。

先跟着其中一帧声音,看看它是怎样绕一圈回来的:

一句话,是怎样绕一圈回来的? 从你开口,到设备再次发声
  1. 你说一句话 声音进入设备麦克风
  2. 采集与 Opus 编码 PCM 切成 20 ms 音频帧
  3. 理解或回声 真实产品处理;本文安全回声
  4. 缓冲、解码与补偿 重排、PLC 或补静音
  5. 你听到回复 连续、碎裂,或短暂冻结

本文的实验范围:用安全回声替代 VAD、ASR、LLM 与 TTS,只比较中间的网络传输和设备播放。

这里的“实时”不是尽快下载完一个音频文件,而是让每一帧赶上自己的播放时间:

提前到达 进入缓冲区 可以吸收抖动,但等待不能无限增加
按时到达 正常进入播放 内容和时间同时正确
迟到 收到也可能过期 错过时间线后,不应再追播旧声音

真正要比较的,不是谁最后收得更多,而是谁能把更多音频按时送进扬声器

协议平时藏在体验背后,只有弱网出现时,它的性格才会变得明显:丢了一帧,是继续播放后面的内容,还是等待它重传?断网 3 秒后,是尽快追上当前进度,还是把积压的旧音频补完?控制消息和音频应该共用一条连接,还是分别传输?

这正是本次实验的起点。现有方案由 MQTT 管理控制与状态、UDP 传输音频;另一条候选路线是 WSS,让控制消息和音频帧共用一条安全长连接。我们想比较的不是两个发送 API,而是两套完整链路在相同音源、相同播放器和相同网络损伤下会怎样表现。

为了不让模型处理时间干扰结论,本轮先拿掉 VAD、ASR、LLM 和 TTS,只保留“设备发送 Opus、服务端安全回声、设备按真实时间轴播放”的传输闭环。文章想回答的也不是“谁永远更快”,而是:两套链路会以什么方式失败,为什么“最终收齐”和“按时可播”不是一回事,以及这些差异应该怎样影响产品选型。

数据快照:2026 年 8 月 27 日。本文数字来自正式归档的 CSV、JSON 与最终播放 WAV,只代表当时的实验实现、设备、局域网和测试参数,不构成通用协议排名。

认识关键概念

先不用记住所有缩写。整套实验可以先分成四块:

声音 PCM → 20 ms 帧 → Opus 连续声波如何变成可传输的数据
传输 MQTT · UDP · WSS 控制消息和音频帧怎样穿过网络
播放 Buffer · 截止 · PLC 帧到达之后,设备怎样把它变成听感
本轮移除 VAD → ASR → LLM → TTS 先隔离智能处理,只观察传输和播放

从声音到音频帧

声音本质上是连续变化的声波。麦克风把它按固定频率采样为数字信号,得到未压缩的 PCM;实时传输时,又会把连续 PCM 切成很短的音频帧。本实验采用 16 kHz、单声道、每帧 20 ms,因此 30 秒音频约有 1500 帧。

Opus 是面向语音和实时互动的音频编码格式,用来在音质、码率和延迟之间做取舍。它负责压缩音频,但不决定这些帧最终通过 UDP 还是 WSS 传输。

VAD、ASR、TTS 与 E2E

  • VAD 判断什么时候开始说话、什么时候停止;
  • ASR 把语音识别成文字;
  • LLM 理解上下文并生成回答;
  • TTS 把回答文字合成为声音;
  • E2E 延迟:通常指从用户停止说话,到最终听见系统回复的完整等待。

本文没有接入这些模块,因此后文的 TTFA 只是传输侧首个音频回包到达的时间,不能等同于真实 AI 对话的 E2E 首响。

控制面、媒体面与传输协议

  • 控制面负责鉴权、会话建立、开始与停止、状态和错误等低频消息;
  • 媒体面负责连续发送高频音频帧;
  • MQTT 是发布/订阅消息协议,在本文中只管理控制和状态,不承载音频;
  • UDP 以数据报为单位发送,不保证到达和顺序,也不会为了一个旧包阻塞后续新包;
  • WSS/TLS 是运行在 TLS 和 TCP 之上的安全 WebSocket,可以在同一条连接中传递结构化控制消息和二进制音频帧。

因此,后文的“MQTT+UDP”和“WSS/TLS”都指完整实验链路,而不是只比较 UDP 与 WebSocket 的单个发送函数。

播放器为什么也属于传输实验

  • RTT / P95分别观察一次往返耗时和较差长尾,平均值正常时,P95 仍可能暴露偶发冻结;
  • TTFA 在本文中特指从触发测试到客户端收到首个音频回包;
  • Jitter Buffer 会先缓存少量帧,吸收抖动和轻微乱序,代价是增加等待;
  • PLC 会在帧缺失时用估算音频或静音填补时间线,只能掩盖损伤,不能找回原内容;
  • 播放截止表示一帧应该被播放的时间,超过截止才到达的数据即使最终收到了,也可能已经不能使用;
  • 队头阻塞指 TCP 等待前面丢失的数据完成重传时,后续数据也不能越过它交付给应用。

这些概念共同解释了本文最核心的判断:实时音频既要保证内容正确,也要保证时间正确。

比较两条链路

实验比较的是两种组织控制消息和音频帧的方式:一套把控制面与媒体面分开,另一套让它们共用一条安全长连接。

在 MQTT+UDP 方案中,设备先通过 MQTT 完成连接与会话协商,拿到媒体参数后再启动 UDP。音频以 Opus 帧双向传输,生命周期消息仍由 MQTT 承载。因此,这不是“只使用 UDP”,而是一套需要维持控制面和媒体面一致性的双通道系统。

WSS 方案仍然需要鉴权、Hello、会话创建、音频参数协商、开始、停止、心跳和重连;减少的是独立媒体地址、端口和双连接状态同步。热会话还可以复用同一条安全长连接。WSS 运行在 TLS 和 TCP 之上,产品级部署通常可以复用 443、标准证书体系和成熟网关,但也继承了 TCP 可靠有序交付的行为。

安全口径也需要分开看:实验中的 UDP 媒体已经做了加密与完整性校验的功能验证,但本地 MQTT 控制链路没有验证 TLS;WSS 验证了 TLS 与证书固定。它们都是实验功能检查,不代表现网具备同等能力,也不等于完成生产安全审计。

两套链路的差异可以先浓缩成一句话:

  • UDP 不会为了一个旧包阻塞后续新包,但丢包恢复、安全和拥塞治理要由应用层完成。
  • WSS 会通过 TCP 重传并按序交付,但前面的包没有补齐时,后续音频也无法先交给播放器。

WebRTC 没有放进这次定量排名。它是一套包含 ICE、STUN/TURN、DTLS-SRTP、RTP/RTCP、抖动缓冲、拥塞控制和媒体恢复的完整实时媒体技术栈,更适合复杂公网穿透、强全双工、多端或音视频场景。本轮没有实现同口径 WebRTC 真机实验,不能用 UDP/WSS 的数字替它下结论。

实验怎么搭

实验台刻意拿掉智能处理,只保留一条能真实发送、真实受损、真实播放并留下证据的音频闭环:

实验台概览 同一台真机、同一份声音、同一套损伤和证据口径
设备iPhone 16 Pro Max真机,不是模拟器
音源16 kHz · 单声道20 ms 一帧 Opus
弱网Docker + tc netem丢包、抖动、乱序、限速、短断
证据CSV · JSON · WAV数字和最终听感一起保存
设备侧iPhone

上行
Wi-Fi / 局域网
弱网主要在下行

服务侧Mac / DockerMQTT · UDP Echo · WSS Gateway

Mac 运行本地 MQTT Broker、UDP 音频回声服务和 WSS Gateway。服务端只是安全音频回声实验台,不包含真实 VAD、ASR、LLM 或 TTS。

测试分成三层:先在正常网络中区分冷连接与热会话,再用 30 秒长流跑丢包、抖动、乱序、限速和短断矩阵,最后选取代表场景逐协议试听最终 WAV。每一轮遵循同一条流程:

  1. 01加载同一音源复用永久基准 Opus
  2. 02完成会话连接、鉴权与参数协商
  3. 03施加损伤确认媒体就绪后再开始
  4. 04回声 30 秒两种协议交错运行
  5. 05按时钟播放迟到、PLC 和静音进入时间线
  6. 06保存证据CSV、JSON、WAV 与评分

同一个声音走两条链路

手机只录制一次 10 秒永久基准语音,并缓存编码后的 Opus 帧。30 秒正式轮次将这段基准循环三次,两种协议复用完全相同的音源:

  • 16 kHz;
  • 单声道;
  • 每帧 20 ms;
  • 30 秒约 1500 帧。

这样可以避免“第一次说得快、第二次说得慢”或麦克风环境变化污染协议对比。每个正式批次还会保存音源指纹,用于核对 A/B 两侧是否真的使用了同一输入;公开文章只保留这一验证方法,不公开具体指纹。

弱网发生在真实 IP 层

Mac 上的服务运行在 Docker/Linux 网络栈中,通过 tc netem 对真实 IP 包制造:

  • 随机丢包;
  • 固定延迟;
  • 抖动与乱序;
  • 带宽限制;
  • 短时完全断流。

正式弱网主要作用在 Mac/Docker → iPhone 的返回方向,可以把它理解为对 TTS 下行播放路径的模拟。手机麦克风上行并没有被同一个 qdisc 直接损伤,因此本文不能扩展为“完整上行弱网”或“上下行同时拥塞”的结论。

这一点很重要。实验里的 RTT 包含一次上行和一次下行,但主动制造的主要损伤集中在返回方向;只写“10% 丢包环境”而不说明方向,会让结论看起来比证据覆盖得更广。

最终 WAV 记录的是播放器经历了什么

每轮测试都会保存 App 最终排入扬声器时间轴的 PCM WAV:

1
2
3
4
5
6
Opus 到达
→ Jitter Buffer 重排与等待
→ 到达播放时钟
→ 有帧:解码为真实 PCM
→ 缺帧:PLC 或补 20ms 静音
→ 写入最终播放 WAV

因此,这份 WAV 不是服务端原始音频,也不是“最终收到的数据重新拼接”的理想版本。它包含播放器当时实际使用的缺帧处理:v3.16 以补静音为主,v3.18 会先进行最多三帧的简化短缺帧隐藏,随后再补静音。这样才能把“UDP 多个短缺口”和“WSS 较少但更长的冻结”还原为听感证据。

指标必须先定义起止点

指标 本实验含义 不能代表什么
TTFA 从触发测试到客户端收到首个音频回包的时间 不是扬声器首播,更不是真实 AI 从停说到回复首声的 E2E
RTT / P95 单帧往返耗时及长尾 不能单独说明音频是否连续
收到帧数 应用最终接收到的帧 不等于全部赶上播放截止
迟到 / 过期帧 到达应用但已经错过播放位置的帧 不应再追播为“完整内容”
卡顿次数 连续缺帧形成了多少段缺口 不反映每段缺口有多长
累计卡顿 所有缺口的总时长 可能掩盖一次特别长的冻结
最长卡顿 最严重的一次连续停顿 不能替代整体可懂度
人工评分 测试者对最终播放 WAV 的主观评价 不是大规模双盲听测

平均 RTT 只是其中一项。实时音频至少还要同时看 P95、卡顿次数、累计时长、最长停顿、迟到帧和最终听感。

让数据可信

这次项目真正耗时的部分,不是把两条 Socket 连接跑起来,而是不断校准“到底在测什么”。

  1. v1 ~ v3.1
    先让两条链路跑起来建立冷连接、热会话、RTT、P95 和 TTFA 口径
  2. v3.2 ~ v3.8
    把弱网做得更接近真实长流、tc netem、实际丢包校准、短断与安全验证
  3. v3.9 ~ v3.16
    让数字可以被听见接入真声音、Opus、播放 WAV、人工评分与 70 轮基线
  4. v3.17
    发现 12 轮不能用于性能结论弱网施加过早,暴露的是测试台时序,而不是媒体能力
  5. v3.18
    修正时机,完成实验闭环正式弱网配对 30 轮,并完成 3 组人工 A/B

能产生数字,不等于能产生结论。真正的工作,是让每个数字都知道自己从哪里来、能说明什么、又不能说明什么。

先建立统一口径

早期版本先打通 MQTT+UDP 和 WebSocket/WSS,逐步区分:

  • 冷连接与热会话;
  • 连接建立与会话协商;
  • RTT 与 P95;
  • 首个音频回包与完整传输;
  • 10 秒、30 秒和 60 秒长流。

如果这些时间点混在一起,一次 TLS 握手、一次 MQTT 会话创建或一次媒体首帧等待都可能被错误归因给“协议速度”。

再从应用层模拟走向真实网络损伤

应用层可以故意跳过固定帧、延迟回包或调整顺序,非常适合验证播放器和统计逻辑;但服务已经收到完整数据后再“不回某些帧”,不会触发 TCP 的真实重传与按序交付。

因此后续版本把正式选型证据迁移到 Linux tc netem:UDP 包可以在真实网络层丢失或乱序,WSS 底层 TCP 也必须面对同一层面的重传和队头阻塞。应用层损伤仍然保留,但只用于功能回归,不与网络层结果混排。

从模拟负载升级为真实声音

仅发送递增字节可以证明连接稳定,却回答不了“听起来怎样”。项目随后加入:

  • 手机麦克风录制;
  • Opus 编解码;
  • 扬声器播放;
  • 永久基准音源;
  • 同源协议 A/B;
  • 最终播放 WAV;
  • 每种协议独立人工评分。

到这一步,客观记录才能与真实听感对应起来。

一次无效批次改变了正式流程

在 v3.17 中,弱网规则施加得太早,部分 UDP 测试还没有完成控制协商就进入了损伤环境,最终表现为会话超时。这个失败更像测试台时序问题,而不是媒体链路的真实弱网能力。

这 12 轮没有被删除,也没有被包装成协议结论,而是作为诊断证据隔离。v3.18 将顺序修正为:

1
2
3
4
5
建立连接
→ 完成 Hello 与会话协商
→ 确认媒体阶段就绪
→ 施加网络损伤
→ 开始发送音频

修正后的正式弱网配对 30/30 轮都成功进入媒体阶段并完成归档,实验才真正闭环。这里的“成功”只表示会话与实验流程完成,不表示全部帧收齐或全程没有卡顿。

这个过程也提醒我:一套会产生数字的工具,不一定是一套能产生结论的工具。 无效记录的价值在于暴露测试台问题,而不是被悄悄排除后假装实验从未出错。

保证公平比较

正式实验采用了几项固定规则。

音频与播放逻辑一致

  • 两种协议复用同一永久基准 Opus;
  • 帧长、测试时长和基础播放缓冲一致;
  • 共用播放时钟、Jitter Buffer 和卡顿统计;
  • 无人值守矩阵中的协议顺序自动交错平衡,避免永远由某一侧先跑。

控制阶段与媒体阶段分开

每轮先完成连接和会话协商,再对媒体返回方向施加损伤。连接失败、控制超时和媒体弱网由不同字段记录,避免把控制面故障混入播放结论。

主观与客观证据并行

无人值守回归用于观察多轮趋势;人工 A/B 用同一音源分别播放 UDP 和 WSS,并对最终声音评分。最终三组人工测试固定先听 UDP、再听 WSS,并非随机或盲测,因此只用于辅助解释失效形态。两类证据不会互相替代:

  • 单次试听更容易解释“为什么难听”;
  • 多轮统计更适合判断某种趋势是否稳定。

每个结论都能追溯

正式结果保存:

  • CSV 与完整 JSON;
  • 批次标识和版本;
  • 音源一致性指纹;
  • 网络场景和实际损伤计数;
  • 人工评分与备注;
  • 最终播放 WAV。

错误网络、服务未启动、损伤未校准和测试台时序错误不会删除,但会明确标记为诊断或无效记录,不进入正式统计。

实验结果

先看一轮反直觉的 10% 丢包

有了前面的背景和指标定义,再看最终人工 A/B 中的一轮 30 秒同源音频:

10% 丢包 · 30 秒同源人工 A/B 同一个声音,两种完全不同的弱网失效形态
MQTT + UDP缺口多,但每次较短
收到帧数
1354 / 1500
卡顿次数
127 次
累计卡顿
2920 ms
最长卡顿
40 ms
人工评分
3 / 5
WSS / TLS缺口少,但可能更长
收到帧数
1500 / 1500
卡顿次数
12 次
累计卡顿
1620 ms
最长卡顿
1280 ms
人工评分
4 / 5

收齐 ≠ 按时可播:最终内容更完整,与每次停顿更短,是两个不同目标。

WSS 最终收齐了全部帧,卡顿次数和累计时长也更少;但它出现了一次 1.28 秒的长冻结。UDP 丢了 146 帧,卡顿更碎,却能较快追上当前播放进度。

这组结果把实时音频选型中最容易忽略的问题摆在了桌面上:“内容最终完整”和“每一帧按时可播放”是两个不同目标。 它来自固定先 UDP、再 WSS 的单次人工试听,适合解释失效形态,不应该单独用来宣布协议胜负;正式判断还要结合后面的多轮配对数据。

媒体策略调整前的 70 轮基线

v3.16 完成了 70 轮无人值守回归流程,MQTT+UDP 与 WSS 各 35 轮。这里的“完成”同样不等于音频完整或没有卡顿。它已经具备固定 80 ms 缓冲、播放时钟和播放截止,因此不是完全裸协议;更准确的称呼是 媒体策略继续调整前的基线

场景 MQTT + UDP WSS / TLS 观察
正常冷连接 TTFA P50 2267.3 ms 1477.9 ms 本批 WSS 冷启动更快
正常热会话 TTFA P50 1267.6 ms 1422.4 ms 本批 UDP 略快
极端抖动累计卡顿(每协议 3×30 秒合计) 38.64 s 71.22 s UDP 更容易追上实时进度
3 秒短断累计卡顿(每协议 3×30 秒合计) 9.12 s 9.18 s 两者基本持平

其中正常冷连接与热会话的 TTFA P50 均来自每协议 10 轮;弱网卡顿则是每协议三轮 30 秒音频的合计,不能误读为一段 30 秒音频卡住了 71.22 秒。

这批数据可以说明不同场景的趋势,却不能与 v3.18 直接相减并声称“优化提升了多少”。v3.18 调整了弱网施加时机、部分计时路径和媒体策略,两版适合各自做同版本横向比较,不适合做简单纵向百分比。

正式弱网配对 30 轮

v3.18 覆盖 5 个网络档位、2 种协议、每档 3 轮,共 30/30 轮完成会话与实验流程。下面选出最能解释差异的四档;4500 帧表示每协议三轮、每轮 1500 帧的合计:

网络场景 MQTT + UDP(三轮合计) WSS / TLS(三轮合计) 本批观察
10% 随机丢包 4034/4500 帧;415 次卡顿;9.32 s;最长 80 ms 4500/4500 帧;40 次;7.26 s;最长 540 ms WSS 更完整、累计损伤更少;UDP 单次缺口更短
极端抖动/乱序 4500/4500 帧;684 次;18.22 s;最长 120 ms 4500/4500 帧;138 次;27.70 s;最长 1.24 s UDP 更容易追实时;WSS 次数少但冻结更长
3 秒短断 4050/4500 帧;4 次;9.00 s;最长 3.00 s 4500/4500 帧;3 次;9.10 s;最长 3.06 s;455 帧迟到 最终体验基本持平
96 kbps 限速 4500/4500 帧;1 次;0.42 s;最长 420 ms 4500/4500 帧;13 次;3.74 s;最长 2.62 s 本批 UDP 更好,WSS 出现排队长尾

这张表不支持“WSS 在弱网下全面胜出”,也不支持“UDP 一定更快”。它更像四种不同的失败方式:

  • 随机高丢包中,可靠重传能保护内容完整性,但可能换来更长的单次等待;
  • 极端抖动中,UDP 可以放弃旧帧追上当前进度,WSS 更容易积累队头阻塞;
  • 物理网络完全断开 3 秒时,两种协议都无法创造音频,差异只在恢复后怎样处理旧数据;
  • 在本批 96 kbps 档位中,当前 WSS 实现出现了排队长尾;但实际 Opus 有效载荷明显低于这个上限,这个结果更像一次值得追查的长尾样本,不能外推成“WSS 在所有限速环境中都更差”。

人工 A/B 把数字变成了声音

最终人工 A/B 选择 10% 丢包、极端抖动/乱序和 3 秒短断三个代表场景:

场景 MQTT + UDP WSS / TLS 听感解释
10% 丢包 3 / 5 4 / 5 WSS 本轮可懂度更好,但出现一次长冻结
极端抖动/乱序 4 / 5 4 / 5 UDP 更碎,WSS 单次停顿倾向更长
3 秒短断 2 / 5 2 / 5 双方都出现接近 3 秒静音

人工结果主要来自一名测试者和三个场景,作用是解释听感,不是替代统计。极端抖动的单轮 WSS 累计卡顿甚至好于该轮 UDP,而 30 轮配对中的总体方向相反,这正说明弱网具有波动性:不能拿最好或最差的一轮概括整个协议。

收齐不等于可播

音频每 20 ms 就有一个固定播放位置。播放器不能无限等待,因为等得越久,交互就越不像实时系统。

假设当前要播放第 100 帧:

1
2
3
4
5
6
7
8
播放时钟:  ... 98 ── 99 ── 100 ── 101 ── 102 ...

UDP 到达: 98 99 × 101 102
100 丢失
结果: PLC/静音,随后继续播放 101

WSS 到达: 98 99 [等待 100 重传,同时 101/102 被阻塞]
结果: 一段冻结;恢复时部分帧可能已经过期

UDP 的典型风险是直接缺失:旧帧丢失后不会自己回来,应用可以用 PLC 或短静音掩盖,但内容可能碎裂、断字。

WSS 的典型风险是按序等待:TCP 会努力补回丢失数据,但第 100 帧没有补齐前,后续数据也不能越过它交给应用。连接恢复后,应用可能最终“收到 100%”,其中一部分却已经错过第 101、102 帧原本的播放时间。

因此,实时音频需要同时维护两种正确性:

  • 内容正确性: 数据是否最终到达;
  • 时间正确性: 数据是否在播放截止前到达。

只看服务器发送成功、客户端最终收齐或平均 RTT,都会漏掉时间正确性。3 秒短断实验中,WSS 最终收齐 4500/4500 帧,却有 455 帧迟到;双方最终听感仍然都是接近 3 秒的静音。这就是“收到”与“可播放”最直观的区别。

距离产品化

实验实现不是完全裸协议,已经具备:

  • Jitter Buffer,以及按场景设置下限、仅在播放启动前有限上调的缓冲策略 v1;
  • 固定播放时钟、播放截止与过期帧丢弃;
  • 缺帧时最多重复并衰减最近三帧 PCM,随后补静音的简化短缺帧隐藏;
  • 按场景预设的 Opus 分档码率,而不是依据实时拥塞动态调码率。

但它仍没有实现:

  • 真正的 Opus in-band FEC;
  • UDP 应用层 NACK;
  • 完整的实时拥塞控制。

因此当前结果代表可以运行、可以测量的实验实现,不是两套产品级链路充分优化后的理论上限。

MQTT + UDP 还需要补什么

  • 序号、去重、有限重排窗口和严格播放截止;
  • PLC、可截止 NACK 与可选 FEC;
  • 基于 RTT、丢包和发送队列的动态码率及拥塞控制;
  • 完整性认证、防重放、Nonce、密钥轮换与生命周期;
  • UDP 可达性、NAT 保活和网络切换;
  • MQTT 控制面与 UDP 媒体面的统一状态、追踪和告警。

WSS 还需要补什么

  • 播放截止、过期帧丢弃和取消旧回复;
  • 自适应缓冲、PLC、动态码率和队列上限;
  • TCP 长冻结后的播放追赶;
  • 心跳、有界退避重连和会话恢复;
  • 慢消费者、连接容量、证书轮换和滚动升级观测;
  • 目标设备上的 CPU、内存、功耗和温升验收。

TCP 帮 WSS 解决了可靠、有序传输和通用拥塞控制,但没有替应用解决“旧音频是否还值得播放”。同样,UDP 允许应用更自由地追实时,却不自动提供一套成熟的实时媒体系统。

如何选择

产品场景 更合理的下一步 主要原因
已有 MQTT+UDP 产品 继续完善现有链路,不因协议名称直接迁移 已有投入可以复用;基础 WSS 不保证体验自然升级
没有迁移负担的新产品 优先验证产品级 WSS,同时保留 UDP 对照 443 兼容、标准 TLS、单连接状态、统一排障和多产品复用更有长期价值
封闭网络、资源受限或极低等待 保留产品级 UDP 候选 新包不受旧包阻塞,协议栈较轻,可进行高度定制
强全双工、复杂 AEC、多端、音视频或公网穿透 单独评估 WebRTC 需求已经超出简单一对一音频长连接,需要完整实时媒体栈

这里最关键的区分是“基础协议实现”和“产品级链路”。

  • 基础 WSS 不天然优于当前 MQTT+UDP;把 UDP 音频搬进 WebSocket,不会自动消除卡顿和旧帧积压。
  • 产品级 WSS 的主要收益更多来自网络兼容、安全体系、状态一致性、部署和长期维护,而不是保证每个弱网档都更快。
  • 产品级 UDP 仍然有价值,但前提是团队愿意长期维护恢复、安全、NAT、拥塞和观测能力。

最终选择不应来自一张总分表,而应来自产品对“少量缺字”和“较长等待”的容忍度,以及网络、安全、资源和团队能力的真实约束。

边界与下一步

这次实验仍然不能回答所有产品问题:

  • TTFA 是从触发测试到客户端收到首个音频回包,不是扬声器首播,也不包含 VAD、ASR、LLM、TTS 和业务排队;
  • 主要环境是局域网 Wi-Fi 和本地服务,不代表公网、企业代理或运营商 NAT;
  • iPhone 真机只是最终设备的代理,不能代表嵌入式芯片的资源、功耗和射频表现;
  • 正式网络损伤主要作用在服务端到手机的返回方向,不是完整双向弱网;
  • 人工 A/B 主要是一名测试者和三个代表场景,不是多人双盲听测;
  • 安全实验验证的是功能行为,不等于生产安全审计;
  • WebRTC、QUIC 和厂商 SDK 没有进行同口径测试;
  • 实验中的 UDP 完整性认证能力不代表任何现有生产系统已经具备同等能力。

下一阶段更值得投入的是:

  1. 在上下行分别和同时施加真实弱网;
  2. 接入真实 VAD、ASR、LLM 与 TTS,测完整停说到首声 E2E;
  3. 在目标芯片验证 CPU、内存、功耗、温升与长连接保活;
  4. 扩展家庭 Wi-Fi、热点、企业代理、公网和网络切换;
  5. 增加多人、多语料、随机顺序的听感实验;
  6. 分别实现并验证 FEC、可截止 NACK、动态码率和拥塞控制;
  7. 只有复杂媒体需求明确时,再把 WebRTC 或其他方案纳入同口径专项。

结语

这次实验最有价值的产出,不是“UDP 和 WSS 谁赢了”,而是把一个模糊的协议争论变成了一组可听、可追溯、可复跑的工程证据。

UDP 在弱网中更容易放弃旧包并追上实时进度,代价是内容可能碎裂或缺失;WSS 通常能保留更完整的内容,代价是 TCP 重传和按序交付可能形成更长冻结。两者都必须围绕播放截止、Jitter Buffer、PLC、动态码率、队列和恢复策略继续建设。

实时音频不能只看平均 RTT,也不能只看最终收包率。真正需要回答的是:用户听到的声音是否完整、是否连续,以及为了这两件事,团队愿意承担怎样的网络、安全、部署和长期维护成本。