把它做成生产功能之前,需要先拆开协议事实、产品承诺和运行成本,三者混在一起很容易得到错误结论。 协商竞态不是罕见边界:页面刷新、addTrack、ICE restart 和双方同时点击连接都可能在同一时间触发 offer。Perfect Negotiation 把冲突处理放进统一状态机,而不是在每个功能里加延时。
WebRTC 的判断依据必须来自两端状态、信令版本和实际选中的候选对。只看某个浏览器回调会遗漏 glare、ICE 切路与对端刷新造成的分叉。
落地方案的关键部件
这项能力横跨客户端、网络与服务端,局部最优很容易制造全局故障。工程决策需要同时约束两端行为、持久化事实和运维预算。
- 依据稳定且双方一致的设备标识确定 polite 角色,重连后角色不能随机翻转。
- 用 makingOffer、isSettingRemoteAnswerPending 与 signalingState 共同判断是否发生碰撞。
- polite 端回滚本地 offer 后接受远端 offer;impolite 端明确忽略碰撞 offer 及其候选。
Perfect Negotiation 的价值不是少写几行异常捕获,而是把所有需要重新协商的功能放进同一个有角色、有版本、有回滚语义的队列。
别让错误假设进入生产
边界条件会把隐藏假设变成真实事故。弱网、刷新、并发和容量上限必须组合测试,因为单独出现时它们往往都能被重试掩盖。
- 只忽略 offer 却继续添加它的 ICE candidate,随后得到难以解释的候选错误。
- 角色取自临时连接 ID,刷新后双方都认为自己 polite 或都认为自己 impolite。
- 为屏幕共享另写一套协商锁,与 ICE restart 的锁互不知情,最终死锁。
发布闸门应该检查什么
发布闸门应包含确定性回归、随机时序探索和真实浏览器组合。发现一次失败后保存 seed 与状态轨迹,让它永久成为可重放用例。
- 让双方同时 addTrack、同时 restart 和同时发送手工连接请求,验证协商最终回到 stable。
- 随机打乱 offer、answer 和 candidate 的信令到达时间,确认旧版本不会改变当前连接。
- 连续运行数百轮 glare 场景,断言只有一个 PeerConnection、一个开放通道和一次成功通知。
完成并不等于主路径跑通,而是每个终态都能对账、每个自动动作都受用户意图约束、每个成本都有明确上限。