实时音频传输实验:UDP 与 WSS
本文最后更新于 2026-09-02
声音如何往返
你对着一个语音设备说:“给我讲个故事。”几秒后,扬声器里开始传出回答。我们很容易想到背后的 ASR、LLM 和 TTS,却很少追问另一件事:刚才那句话究竟是怎样到达服务端的,生成后的声音又是怎样回到设备的?
设备并不是等你说完,再把一个完整录音文件上传。更常见的做法是边录、边切帧、边编码、边发送:麦克风采集到的声音被切成几十毫秒一帧,压缩成 Opus 后持续上行;返回的音频也会一帧一帧到达设备,经过缓冲、解码和缺帧处理,最后才进入扬声器。
先跟着其中一帧声音,看看它是怎样绕一圈回来的:
- 你说一句话 声音进入设备麦克风
- 采集与 Opus 编码 PCM 切成 20 ms 音频帧
- 协议负责上行 MQTT+UDP 或 WSS
- 理解或回声 真实产品处理;本文安全回声
- 协议负责下行 Opus 音频帧返回设备
- 缓冲、解码与补偿 重排、PLC 或补静音
- 你听到回复 连续、碎裂,或短暂冻结
本文的实验范围:用安全回声替代 VAD、ASR、LLM 与 TTS,只比较中间的网络传输和设备播放。
这里的“实时”不是尽快下载完一个音频文件,而是让每一帧赶上自己的播放时间:
真正要比较的,不是谁最后收得更多,而是谁能把更多音频按时送进扬声器。
协议平时藏在体验背后,只有弱网出现时,它的性格才会变得明显:丢了一帧,是继续播放后面的内容,还是等待它重传?断网 3 秒后,是尽快追上当前进度,还是把积压的旧音频补完?控制消息和音频应该共用一条连接,还是分别传输?
这正是本次实验的起点。现有方案由 MQTT 管理控制与状态、UDP 传输音频;另一条候选路线是 WSS,让控制消息和音频帧共用一条安全长连接。我们想比较的不是两个发送 API,而是两套完整链路在相同音源、相同播放器和相同网络损伤下会怎样表现。
为了不让模型处理时间干扰结论,本轮先拿掉 VAD、ASR、LLM 和 TTS,只保留“设备发送 Opus、服务端安全回声、设备按真实时间轴播放”的传输闭环。文章想回答的也不是“谁永远更快”,而是:两套链路会以什么方式失败,为什么“最终收齐”和“按时可播”不是一回事,以及这些差异应该怎样影响产品选型。
数据快照:2026 年 8 月 27 日。本文数字来自正式归档的 CSV、JSON 与最终播放 WAV,只代表当时的实验实现、设备、局域网和测试参数,不构成通用协议排名。
认识关键概念
先不用记住所有缩写。整套实验可以先分成四块:
从声音到音频帧
声音本质上是连续变化的声波。麦克风把它按固定频率采样为数字信号,得到未压缩的 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 的数字替它下结论。
实验怎么搭
实验台刻意拿掉智能处理,只保留一条能真实发送、真实受损、真实播放并留下证据的音频闭环:
上行→
Wi-Fi / 局域网
←弱网主要在下行
Mac 运行本地 MQTT Broker、UDP 音频回声服务和 WSS Gateway。服务端只是安全音频回声实验台,不包含真实 VAD、ASR、LLM 或 TTS。
测试分成三层:先在正常网络中区分冷连接与热会话,再用 30 秒长流跑丢包、抖动、乱序、限速和短断矩阵,最后选取代表场景逐协议试听最终 WAV。每一轮遵循同一条流程:
- 01加载同一音源复用永久基准 Opus
- 02完成会话连接、鉴权与参数协商
- 03施加损伤确认媒体就绪后再开始
- 04回声 30 秒两种协议交错运行
- 05按时钟播放迟到、PLC 和静音进入时间线
- 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 | |
因此,这份 WAV 不是服务端原始音频,也不是“最终收到的数据重新拼接”的理想版本。它包含播放器当时实际使用的缺帧处理:v3.16 以补静音为主,v3.18 会先进行最多三帧的简化短缺帧隐藏,随后再补静音。这样才能把“UDP 多个短缺口”和“WSS 较少但更长的冻结”还原为听感证据。
指标必须先定义起止点
| 指标 | 本实验含义 | 不能代表什么 |
|---|---|---|
| TTFA | 从触发测试到客户端收到首个音频回包的时间 | 不是扬声器首播,更不是真实 AI 从停说到回复首声的 E2E |
| RTT / P95 | 单帧往返耗时及长尾 | 不能单独说明音频是否连续 |
| 收到帧数 | 应用最终接收到的帧 | 不等于全部赶上播放截止 |
| 迟到 / 过期帧 | 到达应用但已经错过播放位置的帧 | 不应再追播为“完整内容” |
| 卡顿次数 | 连续缺帧形成了多少段缺口 | 不反映每段缺口有多长 |
| 累计卡顿 | 所有缺口的总时长 | 可能掩盖一次特别长的冻结 |
| 最长卡顿 | 最严重的一次连续停顿 | 不能替代整体可懂度 |
| 人工评分 | 测试者对最终播放 WAV 的主观评价 | 不是大规模双盲听测 |
平均 RTT 只是其中一项。实时音频至少还要同时看 P95、卡顿次数、累计时长、最长停顿、迟到帧和最终听感。
让数据可信
这次项目真正耗时的部分,不是把两条 Socket 连接跑起来,而是不断校准“到底在测什么”。
-
v1 ~ v3.1
先让两条链路跑起来建立冷连接、热会话、RTT、P95 和 TTFA 口径
-
v3.2 ~ v3.8
把弱网做得更接近真实长流、tc netem、实际丢包校准、短断与安全验证
-
v3.9 ~ v3.16
让数字可以被听见接入真声音、Opus、播放 WAV、人工评分与 70 轮基线
-
v3.17
发现 12 轮不能用于性能结论弱网施加过早,暴露的是测试台时序,而不是媒体能力
-
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 | |
修正后的正式弱网配对 30/30 轮都成功进入媒体阶段并完成归档,实验才真正闭环。这里的“成功”只表示会话与实验流程完成,不表示全部帧收齐或全程没有卡顿。
这个过程也提醒我:一套会产生数字的工具,不一定是一套能产生结论的工具。 无效记录的价值在于暴露测试台问题,而不是被悄悄排除后假装实验从未出错。
保证公平比较
正式实验采用了几项固定规则。
音频与播放逻辑一致
- 两种协议复用同一永久基准 Opus;
- 帧长、测试时长和基础播放缓冲一致;
- 共用播放时钟、Jitter Buffer 和卡顿统计;
- 无人值守矩阵中的协议顺序自动交错平衡,避免永远由某一侧先跑。
控制阶段与媒体阶段分开
每轮先完成连接和会话协商,再对媒体返回方向施加损伤。连接失败、控制超时和媒体弱网由不同字段记录,避免把控制面故障混入播放结论。
主观与客观证据并行
无人值守回归用于观察多轮趋势;人工 A/B 用同一音源分别播放 UDP 和 WSS,并对最终声音评分。最终三组人工测试固定先听 UDP、再听 WSS,并非随机或盲测,因此只用于辅助解释失效形态。两类证据不会互相替代:
- 单次试听更容易解释“为什么难听”;
- 多轮统计更适合判断某种趋势是否稳定。
每个结论都能追溯
正式结果保存:
- CSV 与完整 JSON;
- 批次标识和版本;
- 音源一致性指纹;
- 网络场景和实际损伤计数;
- 人工评分与备注;
- 最终播放 WAV。
错误网络、服务未启动、损伤未校准和测试台时序错误不会删除,但会明确标记为诊断或无效记录,不进入正式统计。
实验结果
先看一轮反直觉的 10% 丢包
有了前面的背景和指标定义,再看最终人工 A/B 中的一轮 30 秒同源音频:
- 收到帧数
- 1354 / 1500
- 卡顿次数
- 127 次
- 累计卡顿
- 2920 ms
- 最长卡顿
- 40 ms
- 人工评分
- 3 / 5
- 收到帧数
- 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 | |
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 完整性认证能力不代表任何现有生产系统已经具备同等能力。
下一阶段更值得投入的是:
- 在上下行分别和同时施加真实弱网;
- 接入真实 VAD、ASR、LLM 与 TTS,测完整停说到首声 E2E;
- 在目标芯片验证 CPU、内存、功耗、温升与长连接保活;
- 扩展家庭 Wi-Fi、热点、企业代理、公网和网络切换;
- 增加多人、多语料、随机顺序的听感实验;
- 分别实现并验证 FEC、可截止 NACK、动态码率和拥塞控制;
- 只有复杂媒体需求明确时,再把 WebRTC 或其他方案纳入同口径专项。
结语
这次实验最有价值的产出,不是“UDP 和 WSS 谁赢了”,而是把一个模糊的协议争论变成了一组可听、可追溯、可复跑的工程证据。
UDP 在弱网中更容易放弃旧包并追上实时进度,代价是内容可能碎裂或缺失;WSS 通常能保留更完整的内容,代价是 TCP 重传和按序交付可能形成更长冻结。两者都必须围绕播放截止、Jitter Buffer、PLC、动态码率、队列和恢复策略继续建设。
实时音频不能只看平均 RTT,也不能只看最终收包率。真正需要回答的是:用户听到的声音是否完整、是否连续,以及为了这两件事,团队愿意承担怎样的网络、安全、部署和长期维护成本。