IceController · 选路的大脑

一堆候选对里,用哪条传媒体、什么时候切换、下一个 ping 谁?这些决策抽出成了 IceController。这一章读 base/ice_controller_interface.h 的 ShouldSwitchConnection/SortAndSwitchConnection,以及 controlling/controlled 两种 ICE 角色如何分工——一方拍板,一方跟随。

作者 David更新于 第 23 篇(共 112 篇)

IceController · 选路的大脑

P2PTransportChannel 手里握着一堆 Connection,每条路的通断、RTT 各不相同。到底用哪条传媒体?什么时候从一条切到另一条?下一个该 ping 谁? 这些「选路决策」被专门抽成一个组件——IceController(p2p/base/ice_controller_interface.h)。把决策独立出来,是为了能替换不同的选路策略。这一章读它。

决策接口

IceControllerInterface 的核心方法,就是几个「决策」(p2p/base/ice_controller_interface.h):

// p2p/base/ice_controller_interface.h(节选)
class IceControllerInterface {
  // 该不该从当前连接切换?(某事件触发时问)
  virtual SwitchResult ShouldSwitchConnection(IceSwitchReason reason,
                                              const Connection* connection) = 0;
  // 重新排序所有连接,并决定是否切换选中的那条
  virtual SwitchResult SortAndSwitchConnection(IceSwitchReason reason) = 0;
  // 还有:选下一个该 ping 的连接、决定该剔除哪些差连接……
};

它不亲自收发包,只做判断:给它一堆连接的当前状况(通断、RTT、候选类型优先级、是否被提名),它回答「用哪条、切不切、ping 谁」。P2PTransportChannel 的 SortConnectionsAndUpdateState 每次跑,都来问它。

选路的权衡

IceController 选路,权衡这些因素:

选路不是「选一次就完」,而是持续的动态过程。 网络在变:Wi-Fi 信号忽强忽弱、更优的路径可能刚刚才通、选中的路可能突然丢 ping 变得不可靠。所以 IceController 会在每次连接状态变化时重新评估(SortAndSwitchConnection),必要时无缝切换到更好的连接——媒体正在流,切换却对上层几乎透明。这就是为什么 STUN ping 永不停止:持续探测,才能持续掌握每条路的实时状况,让选路始终基于最新情报。把选路逻辑抽成独立的 IceController 接口,也让 WebRTC 能试验不同策略(甚至让上层注入自定义 controller)。

Controlling 与 Controlled:谁拍板

选路还有一个「谁说了算」的问题。ICE 规定,一次连接里两端角色不对等(p2p/base/transport_description.h):

// p2p/base/transport_description.h
enum IceRole { ICEROLE_CONTROLLING = 0, ICEROLE_CONTROLLED, ICEROLE_UNKNOWN };
  • ICEROLE_CONTROLLING(控制方) —— 最终拍板用哪条连接的一方。它通过提名机制,指定「就用这条」。
  • ICEROLE_CONTROLLED(受控方) —— 跟随控制方的决定。

为什么要分角色?为了避免「两边各选各的、选到不同的路」。 如果两端都自作主张,可能 A 认定用路径 1、B 认定用路径 2,媒体就对不上。ICE 用「一方控制、一方跟随」打破对称:控制方拍板,受控方服从,保证双方最终选中同一条路。角色在协商时确定(通常发 offer 的一方是 controlling),写在 SDP 的 ice 参数里。万一双方角色冲突(都以为自己 controlling,即「角色冲突」),ICE 有一套基于 tie-breaker 随机数的规则来裁决,让一方让步。分布式系统里,『谁做决定』和『决定是什么』同样重要——这是 ICE 一个精巧的设计。

小结与下一章

IceController 是选路的大脑(p2p/base/ice_controller_interface.h),被 P2PTransportChannel 委托做决策:ShouldSwitchConnection / SortAndSwitchConnection 判断「用哪条、切不切、ping 谁」,权衡通断稳定性、候选优先级、RTT、提名。选路是持续动态的,网络一变就重评估、无缝切换。角色上分 controlling(拍板)/ controlled(跟随),避免两端选到不同的路;冲突用 tie-breaker 裁决。

控制方怎么「拍板」?靠提名。而网络剧变(换 Wi-Fi、掉线)时,整个 ICE 还能重启重来。下一章讲提名与 ICE 重启。👉 提名与 ICE 重启。

参考资料

  • [1] libwebrtc 源码.p2p/base/ice_controller_interface.h(ShouldSwitchConnection / SortAndSwitchConnection)、g3doc/ice.md。
  • [2] libwebrtc 源码.p2p/base/transport_description.h(IceRole)、p2p/base/basic_ice_controller.h(默认实现)。
  • [3] IETF RFC 8445「ICE」§ Role Determination、Nomination。

本页目录