20、ICE重启(ICE Restart):ICE重启的触发、新ICE ufrag/pwd的生成、媒体流不中断的切换

ICE重启,说白了就是让双方重新进行一次完整的连通性检查。你可能会问:「好好的,为什么要重启?」嗯,这个问题我当年也问过自己。有一次线上会议,用户网络突然切换,画面卡了十几秒才恢复——那时候我就意识到,ICE重启不是锦上添花,而是保命技能。

什么时候需要触发ICE重启?

我个人习惯把触发场景分成三类:

  • 网络切换:比如用户从WiFi切到4G,或者VPN断开重连。这时候原来的候选者地址全变了,不重启不行。
  • 连接超时:ICE链路长时间收不到响应,STUN请求重试几次都失败。我遇到过一种情况——用户的防火墙规则变了,但应用层完全不知道,只能靠ICE重启来「破局」。
  • 应用层主动要求:比如你发现码率骤降、丢包率飙升,想强制刷新路径。这时候重启一下,说不定能找到更好的链路。

核心判断标准:只要你觉得当前的ICE候选者列表已经不可靠了,那就重启。别犹豫。

新ICE ufrag/pwd的生成

ICE重启的关键动作是什么?生成新的 ufragpwd。这两个东西就像是会话的「临时身份证」——旧的作废,新的生效。

在WebRTC里,生成方式其实很简单:

// 伪代码示例
const newUfrag = generateRandomString(4);  // 比如 "aB3x"
const newPwd   = generateRandomString(22); // 比如 "9kLmNpQrStUvWxYz123456"

你可能会问:「为什么ufrag这么短,pwd这么长?」

其实ufrag只是用来做初步匹配的,短一点没关系。pwd才是真正的密钥,用于STUN消息的完整性校验——长一点更安全。我记得有一次自己手写测试代码,把pwd设成了8位,结果安全扫描直接报警。嗯,从那以后我再也不敢偷懒了。

我的习惯:每次生成新凭证后,我会在SDP的 ice-ufragice-pwd 字段里更新。同时把 ice-lite 之类的属性也重新评估一下——别让旧配置污染了新会话。

媒体流不中断的切换

这才是ICE重启最刺激的部分。你想想看,用户正在视频通话,你突然把底层的传输链路换了——画面不能黑、声音不能断。怎么做到的?

WebRTC的设计很巧妙:ICE重启和媒体流是解耦的

具体来说:

  1. 先发SRD(SetRemoteDescription):把新的SDP(含新ufrag/pwd)发给远端。这时候远端就知道:「哦,要重启ICE了」。
  2. 旧链路继续用:在ICE新链路连通之前,媒体数据还是走老路。不会因为你在协商就切断画面。
  3. 新链路连通后切换:一旦新的候选者对成功建立连接,WebRTC内部会做一次「无缝切换」——把媒体流从旧socket迁移到新socket上。

注意:切换不是瞬间完成的。新旧链路会短暂共存。我见过一个坑——如果旧链路的RTT比新链路小很多,切换后反而可能出现短暂的乱序。解决办法是:在切换时适当增大jitter buffer,给乱序包一点缓冲时间。

ICE重启的完整流程(SVG图)

ICE重启完整流程 触发条件 生成新 ufrag / pwd 创建新SDP(含新凭证) 发送 SRD(远端) 新旧链路共存 → 无缝切换 网络切换 连接超时 应用层触发 随机生成 长度固定 媒体流不中断 旧链路继续用

避坑指南

我曾经踩过一个坑:ICE重启时,只更新了本地的ufrag/pwd,忘了通知远端。结果远端还在用旧凭证校验STUN消息,全部被丢弃。画面直接黑了10秒。

所以我的建议是:

  • 一定要成对更新:本地和远端的ufrag/pwd必须同步。你发SRD的时候,确保远端收到了新的SDP。
  • 不要频繁重启:ICE重启本身有开销。如果每秒都在重启,那说明你的网络环境已经病入膏肓了——应该先解决网络问题。
  • 监控切换耗时:我一般会在日志里打一个时间戳,记录从发起重启到新链路连通花了多久。如果超过5秒,说明候选者收集或者连通性检查出了问题。

小技巧:如果你用的是 RTCPeerConnectioncreateOffer 方法,记得把 iceRestart 选项设为 true。这样浏览器会自动帮你生成新的ufrag/pwd,省得自己手动拼SDP。

总结一下

ICE重启不是什么黑魔法。说白了就是三步:

  1. 判断要不要重启(网络变了、超时了、应用层想换路)
  2. 生成新凭证(ufrag/pwd)并塞进SDP
  3. 发送SRD,让新旧链路共存一会儿,然后无缝切换

嗯,就这么简单。但简单不代表容易——我见过太多人栽在「忘记同步凭证」或者「切换时机不对」上。你只要记住:媒体流不中断是底线,新链路连通是目标。把握好这两点,ICE重启就不会出大问题。