WebRTC candidate

WebRTC candidate,第1张

一. 前言

        WebRTC 音视频通信的双方需要知道对端的通信地址才能进行通信,WebRTC 采用 ICE 方式与通信对端建立通信连接,ICE 中很关键的一个步骤就是收集候选者信息,本端需要将自己的主机候选者,NAT 映射后的候选者以及中继候选者等信息发送给对端,对端也需要发送候选者信息给到本端,双方进行媒体连通性检测,检测成功后才能进行通信。

二. candidate

        候选者也叫 candidate,它是一个网络地址信息,例如通信时本地准备使用的 IP 是 192.168.1.2,端口是 10001,采用 UDP 协议,那么这些信息组合起来就是一个 host candidate,一个 candidate 包含协议,IP,端口和类型。

例如:a=candidate:...UDP...192.168.1.2 10001 typ host

        除了 host 类型的 candidate 外还有 srflx candidate 以及 relay candidate 等,各种候选者的含义说明如下。

        主机候选者(Local Address)是本地使用的 IP 地址和端口,例如通过 ipconfig 查看到 WLAN 网卡的 IP 地址是 192.168.1.2,并且准备使用 10001 端口。

        服务端映射候选者(Server Reflexive Address)是 NAT 映射后使用的 IP 地址和端口。

        中继候选者(Relayed Address) 是 TURN 服务器开辟的 IP 地址和端口,TURN 服务器是用来应对当通信对端 NAT 穿越失败无法建立 P2P 通信时,通过 TURN 服务器转发数据包,TURN 服务器一般都部署在带公网 IP 的机器上。

        WebRTC example 提供了一个可以收集 candidate 的工具,通过该工具我们可以收集 Local Address 和 Server Reflexive Address,如果你搭建了 TURN 服务器,将 TURN 服务地址添加到 ICE Servers 中,你还可以收集到 Relayed Address。

三. WebRTC收集candidate源码剖析

        当本地通过 createOffer 生成 local SDP 后会再调用 setLocalDescription 设置到本地描述信息中,setLocalDescription 中就会进行 candidate 收集。

        如下当 PeerConnection::DoSetLocalDescription 完成 ApplyLocalDescription 后会执行 transport_controller_->MaybeStartGathering() 开始 candidate 收集。

void PeerConnection::DoSetLocalDescription(
    std::unique_ptr desc,
    rtc::scoped_refptr observer) {
  // 省略...(详见src/pc/peer_connection.cc)
  error = ApplyLocalDescription(std::move(desc));

  // 省略...

  // MaybeStartGathering needs to be called after posting
  // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
  // before signaling that SetLocalDescription completed.
  transport_controller_->MaybeStartGathering();

  // 省略...
}

        如果当前线程不是网络线程,则向网络线程发送 MaybeStartGathering 的任务,否则执行 dtls->ice_transport()->MaybeStartGathering() 的逻辑。

        MaybeStartGathering 逻辑如下,如果当前状态为未收集过 candidate 的状态或者准备重启 ICE 的状态,则进入正在收集的状态,并且往 allocator_sessions_ 添加一个 session(该 session 是一个 PortAllocatorSession 对象),然后调用 session 的 StartGettingPorts。

 

        调用 StartGettingPorts 后的驱动流程为:GetPortConfiguarations -> OnConfigReady -> OnAllocate -> OnAllocationSequenceObjectsCreated。

 

 

        GetPortConfiguarations 首先创建 PortConfiguration 对象 config,然后往 config 对象添加 stun_servers,turn_servers 地址信息。

 

        OnConfigReady 则是将 PortConfiguration 对象塞入 configs_ 中。

 

 

        OnAllocate 中调用了 DoAllocate,DoAllocate 中最重要的逻辑就是为每个 Network 生成一个 AllocationSequence 对象(如果你对 Network 对象不太熟悉,可以先阅读这篇博客了解 WebRTC 收集网卡信息的流程)。

        DoAllocate 中使用 Network, PortConfiguration 以及 sequence_flags 创建 AllocationSequence 对象后,会再为 AllocationSequence 对象执行 Init 初始化。 

        AllocationSequence::Init 调用 BasicPacketSocketFactory::CreateUdpSocket 创建出 socket,该 socket 绑定了 Network 对应的 ip 地址以及从 [min_port, max_port] 范围挑选的一个可用端口,socket 创建的调用流程如下。

         AllocationSequence::Init 执行完成后会再调用 AllocationSequence::Start,该函数主要是给网络线程发送 MSG_ALLOCATION_PHASE 消息,驱动 UDPPort,TcpPort,StunPort,RelayPort 等对象的创建。

        我们以 CreateUDPPorts 为例说明 host candidate 是如何收集的,对于收集服务器反射地址候选者请阅读这篇博客,对于收集中继地址候选者请阅读这篇博客。

        CreateUDPPorts 逻辑如下,首先是创建出 UDPPort 对象,然后通过 BasicPortAllocatorSession::AddAllocatedPort 添加 UDPPort 进行处理。

        BasicPortAllocatorSession::AddAllocatedPort 主要是为 port content_name, component 等属性,并关联一些事件的回调处理函数,然后执行 PrepareAddress。

        PrepareAddress 调用了 OnLocalAddressReady,OnLocalAddressReady 又调用 AddAddress 创建 candidate。

 

        至此本地候选者即创建完毕,对于服务器反射地址候选者的收集请阅读这篇博客,对于中继地址候选者的收集请阅读这篇博客,候选者信息创建完成后会给网络线程发送 MSG_SEQUENCEOBJECTS_CREATED 消息,回调 OnAllocationSequenceObjectsCreated 候选者创建完成。

四. 参考资料

RFC5245

RFC8445

RFC5766

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/892993.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-14
下一篇 2022-05-14

发表评论

登录后才能评论

评论列表(0条)

保存