mediasoup create/connect WebRtcTransport 流程分析

一. 前言

        在这篇博客中我们介绍了 mediasoup-demo 启动流程与信令交互,关键信令包括 getRouterRtpCapabilites,join, createWebRtcTransport, connectWebRtcTransport, produce,本文将介绍 createWebRtcTransport 和 connectRtcTransport 的流程。

二. createWebRtcTransport

        mediasoup-demo 信令层接收到 createWebRtcTransport 消息后处理请求参数并作为 webRtcTransportOptions 传递给 mediasoup C++ 层创建 transport 使用,请求参数包括 { forceTcp, producing, consuming, sctpCapabilities }。

         mediasoup Router 接收到 ROUTER_CREATE_WEBRTC_TRANSPORT 请求后创建 RTC::WebRtcTransport 对象。

         WebRtcTransport 构造函数处理流程如下,首先获取 enableUdp, enableTcp, preferUdp, preferTcp 参数配置,如果 enableUdp=true 则返回的候选者地址列表包含 UDP 类型的 (ip, port),如果 enableTcp=true 则返回的候选者地址列表包含 TCP 类型的 (ip, port),preferUdp=true 表示更倾向于使用 UDP,preferTcp=true 表示更倾向于使用 TCP,倾向性体现在候选地址的优先级。

        如果 enableUdp 和 enableTcp 同时为 true,说明需要返回两种协议类型的候选者列表,因此 iceCandidates 的大小设置为 listenIps 的 2 倍,每个 iceCandidates 对应一个 UdpSocket 或者 TcpSocket。UdpSocket 底层是 libuv 的 uv_udp_t 对象,它会在收到 UDP 报文数据后回调 WebRtcTransport 的 OnUdpSocketPacketReceived 处理,TcpSocket 底层则是 libuv 的 uv_tcp_t 对象。

候选者的优先级计算规则为:

icePriority = 2^24 * IceTypePreference + 2^8 * localPreference + 2^0 * (256 - IceComponent)。

IceTypePreference 为固定值 64,IceComponent 为固定值 1,说明 icePriority 与 localPreference 成正相关关系,

localPreference = IceCandidateDefaultLocalPriority - iceLocalPreferenceDecrement,

IceCandidateDefaultLocalPriority 为固定值 10000,而 iceLocalPreferenceDecrement 每次计算完一个地址列表后都会自增 100,也就是地址列表中靠后的地址优先级低于靠前的地址,并且如果设置了 preferUdp 或者 preferTcp 相应类型的候选者 localPreference 会加上 1000。

         WebRtcTransport 构造函数最后创建 ICE Server 和 DTLS Transport 对象。

        ICE 称为交互式连通建立方式(Interactive Connectivity Establishment)。ICE 有两种类型,一种是 full ICE,这种方式通信的双方都要进行连通性检查,另一种是 lite ICE,这种方式 lite ICE 方只要被动回应 reponse 消息即可,即 lite ICE 端不需要主动进行连通性检查,只要 full 端完成连通性检查即可,ICE Server 对应 lite ICE 实现。

        DTLS 是 UDP 层的安全传输协议(类似于 TLS),用来交换 SRTP 加解密的密钥。mediasoup 在启动时会读取配置的证书文件,然后为证书生成不同的散列值(指纹),在验证证书有效性时就可以比对指纹,如果指纹相等说明下发的证书没有被修改过。

        transport 创建完成后,信令层会监听 C++ 层发送的 sctpstatechange, dtlsstatechange, trace 事件并作出相应处理。

         

        createWebRtcTransport 最后返回 { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters }。

字段 含义
id 传输通道id
iceParameters ICE类型,ICE用户名,密码
iceCandidates ICE候选者信息,包括ip, 端口, 协议类型, 优先级等信息
dtlsParameters 用于DTLS握手的证书指纹信息
sctpParameters SCTP配置信息

        客户端在收到 createWebRtcTransport 的返回结果后会开启媒体连通性检查,即对 ICE candidates 列表地址发送 STUN 包 binding request ,mediasoup 收到后回应 binding response,如下是抓包内容。

        STUN 报文头部如下所示,Message Type 表示消息类型(包含 Message Method 和 Message Class),Message Length 表示 STUN 消息长度,不包含 20 字节头部,Magic Cookie 值固定为 0x2112A442,Transaction Id 为事务 ID,用于请求和响应的标记 ID 号。RFC3489 定义了 128 bit 的事务 ID,而 RFC5389 将 128bit 的事务 ID 分成 32bit 的 Magic Cookie 和 96bit 的 Transaction Id,因此根据 Magic Cookie 值可以区分是 RFC3489 还是 RFC5389 的 STUN 协议。

        STUN 报文头部后面跟着 0 个或多个属性(attribute),每个属性都采用 TLV 格式编码。

Type 属性 含义
0x0001 MAPPED-ADDRESS 获取客户端映射后地址
0x0006 USERNAME 通知用户名
0x0007 PASSWORD 密码,用于安全认证
0x0008 MESSAGE-INTEGRITY 消息完整性,包含一段SHA-1散列值
0x0009 ERROR-CODE 错误码类型
0x000A UNKNOWN-ATTRIBUTES 未知属性
0x0020

XOR-MAPPED-ADDRESS

异或映射地址
0x0024

PRIORITY

候选者优先级
0x0025 USE-CANDIDATE 提名该候选者
0x8028 FINGERPRINT 对消息进行CRC值校验
0x8029 ICE-CONTROLLED 用于区分ICE角色,answer乙方为controlled角色
0x802A ICE-CONTROLLING 用于区分ICE角色,offer一方为controlling角色

三. connectWebRtcTransport

        connectWebRtcTransport 的请求参数为 transportId 和 dtlsParameters。

         mediasoup C++ 接收到 TRANSPORT_CONNECT 消息请求后会转到对应的 transport 处理,对于 WebRtcTransport 的处理则需要确定对端选择的 DTLS 角色,并开启 DTLS 交互。

         DTLS 交互流程如下所示,关于 DTLS 流程每一步含义说明请参考这篇文章

         执行 DtlsTransport Run 函数后 DTLS 状态进入 CONNECTING,对于 Client 角色,调用 openssl SSL_set_connect_state,SSL_do_handshake,对于 Server 角色调用 openssl SSL_set_accept_state,SSL_do_handshake。

 

        DTLS 协商完成后计算出 SRTP 使用的密钥,通知 WebRtcTransport->OnDtlsTransportConnected,WebRtcTransport 收到后建立 srtpSendSession,最后通知 mediasoup-demo 信令层 dtlsstatechange (connected)。

 

猜你喜欢

转载自blog.csdn.net/weixin_38102771/article/details/128487350