mediasoup Lite ICE实现说明

目录

一. 前言

二. Lite ICE流程

三. STUN协议说明

STUN Header

STUN Body

四. mediasoup Lite ICE实现源码剖析


一. 前言

        ICE 是一种交互式建立连接的流程协议。ICE 有两种模式(Full ICE 和 Lite ICE),Full ICE 要求建立连接的双方都要执行连通性检测,而 Lite ICE 则只要求响应 STUN binding request 信息即可,它不需要添加候选者并对候选者进行连通性检测。

        媒体服务器一般都使用的是 Lite ICE 实现,因为媒体服务器通常部署在公网,它的网络没有限制,因此一般只需要客户端检测与媒体服务器提供的候选者地址是连通的即可。

二. Lite ICE流程

        mediasoup 客户端要进行推流首先要创建通道,创建通道是通过 createWebRtcTransport 信令完成的,该信令返回的信息包含 {id, iceParameters, iceCandidates, dtlsParameters, sctpParameters},如下是一个示例值,包含了 ICE 的用户名,密码,使用的是 Lite ICE,以及候选者地址,优先级,协议等。

示例:{ id: ‘c0fe3f31-a764-40ff-88ff-69c14b83afda’,

iceParameters: { iceLite: true, password: ‘0pcc8bpoj1ug2s30p6ldh4qlgan1n5wd’, usernameFragment: '6jeiq5rqh7ke06dqzgnvzmg3iwtjxbqr' },

iceCandidates: [{"foundation":"udpcandidate","ip":"10.211.55.5","port":44445,"priority":1076302079,"protocol":"udp","type":"host"}],

dtlsParameters: { fingerprints: [ {"algorithm":"sha-224","value":"21:81:82:05:AD:52:C3:64:C1:F8:FF:44:65:79:97:51:85:D1:7A:20:13:6F:B0:B6:25:EA:B4:46"}, ... ], role: 'auto' },

sctpParameters: { MIS: 1024, OS: 1024, isDataChannel: true, maxMessageSize: 262144, port: 5000, sctpBufferedAmount: 0, sendBufferSize: 262144 } }

        mediasoup 的 WebRtcTransport 对应 webrtc 的 RTCPeerConnection,mediasoup 客户端收到 createWebRtcTransport 的返回结果后会创建 WebRtcTransport(即对应一个 RTCPeerConnection),然后将 createWebRtcTransport 信令返回的 ICE 等参数信息设置到 remoteSdp 中,在媒体协商的时候将 remoteSdp 设置为 RTCPeerConnection 的remoteDescription,之后就开始发送 binding request 进行连通性检测。

        设置的 remoteSdp 部分内容如下所示,可以看到 usernameFragment 的内容在 a=ice-ufrag,password 的内容在 a=ice-pwd 中,a=candidate 的内容为 iceCandidates 的内容。

        抓包分析 Lite ICE 流程如下所示,mediasoup 客户端发送 STUN binding request 消息,携带 USERNAME, GOOG-NETWORK-INFO, ICE-CONTROLLING, PRIORITY, MESSAGE-INTEGRITY 以及 FINGERPRINT 属性。

        mediasoup 服务端收到 STUN binding request 消息后,回复 STUN binding response 消息,携带 XOR-MAPPED-ADDRESS, MESSAGE-INTEGRITY, FINGERPRINT 属性。

        之后 mediasoup 客户端发送 DTLS Client Hello 消息,说明客户端收到服务器回复的 STUN binding response 消息后 ICE 状态已经是成功连接的状态了。

三. STUN协议说明

        STUN工作原理 这篇博客描述了 STUN 报文的格式,ICE 实现要求遵循 RFC5389 而不是 RFC3489,RFC5389 的 STUN 报文格式如下所示。

STUN Header

STUN Message Type 的 14bit 含义如下,M11-M0 表示 Method,目前只有 Binding 一种 Method,C1C0 表示 Class,C1C0=0b00 表示请求,C1C0=0b01 表示指示,C1C0=0b10 表示请求成功的响应,C1C0=0b11 表示请求失败的响应。

Message Length 表示 STUN 报文 Body 的长度

Magic Cookie 固定为 0x2112a442

Transaction ID 表示事务 ID,用于关联请求和响应,响应携带事务 ID 以表明这是对哪个请求的响应

STUN Body

        STUN 消息体的内容是一系列属性,每个属性都是 Type, Length, Value 结构,我们主要讲解 Lite ICE 流程涉及到的属性含义,注意下面的属性值不完全属于 RFC5389 规范的定义,例如 PRIORITY,USE-CANDIDATE,ICE-CONTROLLING 是由 RFC5245 ICE 规范对 RFC STUN 协议的扩展,而 GOOG-NETWORK-INFO 是 webrtc 对 STUN 协议的扩展。

属性名称Type说明
USERNAME0x0006ICE用户名
GOOG-NETWORK-INFO0xC057网络信息,包含network-id以及network cost信息
ICE-CONTROLLING0x802AICE控制角色,携带该属性表示是控制方,与之对应的为受控方(ICE-CONTROLLED),对于 mediasoup,客户端需要进行连通性检测,是控制方角色,而服务器是受控方角色
PRIORITY0x0024优先级
MESSAGE-INTEGRITY0x0008用于消息完整性验证,该值的计算是基于SHA-1的HMAC算法,密钥使用 ICE 的 password,消息体则使用 STUN 消息内容(不包含该属性本身以及 FINGERPRINT 属性的内容)
FINGERPRINT0x8028消息指纹
XOR-MAPPED-ADDRESS0x0020异或地址
USE-CANDIDATE0x0025该属性只会出现在ICE控制方,表示ICE控制方已经选择好候选地址并准备通信,ICE受控方收到该消息后将该消息发送的对端地址设置为通信的对端地址即可

四. mediasoup Lite ICE实现源码剖析

        WebRtcTransport 收到数据包后调用 WebRtcTransport::OnPacketReceived,该函数会判断接收到的消息是什么类型的消息,如果是 STUN 协议的消息,就调用 OnStunDataReceived 进行处理,STUN 协议消息的判断即根据上述描述的 STUN 报文格式进行判断即可。

       WebRtcTransport::OnStunDataReceived 会调用 RTC::StunPacket::Parse 解析消息,得到 StunPacket,之后调用 IceServer::ProcessStunPacket 进行处理。

        IceServer 是 WebRtcTransport 的一个成员变量, 它负责维护 WebRtcTransport 的 ICE 当前状态信息,例如保存 ICE 用户名密码,连接状态,所有的对端候选地址以及当前选中使用的对端候选地址,如下是 IceServer 的成员变量。

class IceServer
{
public:
	enum class IceState
	{
		NEW = 1,
		CONNECTED,
		COMPLETED,
		DISCONNECTED
	};

// ......

private:
	// Passed by argument.
	Listener* listener{ nullptr };
	// Others.
	std::string usernameFragment;
	std::string password;
	std::string oldUsernameFragment;
	std::string oldPassword;
	uint32_t remoteNomination{ 0u };
	IceState state{ IceState::NEW };
	std::list<RTC::TransportTuple> tuples;
	RTC::TransportTuple* selectedTuple{ nullptr };
};

        IceServer::ProcessStunPacket 处理流程如下所示,首先判断 STUN 消息是否是一个正常的消息,如果 Method 不是 binding,说明不是一个正常的 STUN Message,或者如果 STUN binding request 消息没有携带 FINGERPRINT 属性,也不是一个正常的消息,返回错误响应即可。

        接下来判断 STUN Message 是否携带了 MESSAGE-INTEGRITY, PRIORITY, USERNAME 等属性,如果当中任意一个属性不包含,则返回错误响应。

        之后再调用 packet->CheckAuthentication 校验消息,CheckAuthentication 主要是校验 STUN Message 的用户名是否正确,以及 MESSAGE-INTEGRITY 是否正确。

         StunPacket::CheckAuthentication 处理逻辑如下所示,首先是判断 USERNAME 属性分号前的用户名与服务器本地用户名是否相等,如果不相等则认证失败,如果相等,再判断 MESSAGE-INTEGRITY 属性是否正确,避免使用在传输过程中被篡改的消息。

        接下来再判断如果 STUN Message 携带了 ICE-CONTROLLED 属性,则返回角色错误的失败响应,因为 mediasoup 客户端是控制方角色,mediasoup 服务端是受控方角色,所以 mediasoup 客户端发送的 STUN Message 不应该携带 ICE-CONTROLLED,而应当是 ICE-CONTROLLING。

        如果前面的合法性都校验通过,接下来就是执行对 STUN binding request 的响应,即生成 STUN binding reponse 消息,并设置 XOR-MAPPED-ADDRESS 属性值,然后添加 MESSAGE-INTEGRITY 以及 FINGERPRINT 属性值。

        至此 mediasoup 接收 STUN binding request 并回复 STUN binding response 的流程就讲解完成,收到 STUN binding request 最后一步处理函数是 HandleTuple(tuple, packet->HasUseCandidate(), packet->HasNomination(), nomination);

        HandleTuple 的处理逻辑如下所示,客户端第一次发送的 STUN binding request 消息没有携带 USE-CANDIDATE 和 NOMINATION,并且此时是 New 状态,因此执行下面的逻辑,此时将当前的对端地址信息添加到 IceServer 的 tuples 成员变量,并设置当前 tuple 为 selectedTuple,设置为 selectedTuple 即表示这个对端地址信息是 WebRtcTransport 认为的客户端的通信地址,之后需要往客户端发送的媒体数据就会往这个地址发送,这些操作完成之后 ICE 状态变成 CONNECTED。

        连通性检测成功后,mediasoup 客户端会再发送 STUN binding request 消息进行保活,此时发送的 STUN bindind request 会增加 USE-CANDIDATE 属性,表示 mediasoup 客户端已经确定使用该连接进行后续的通信。

        当 ICE 处于 CONNECTED 状态,再收到 STUN binding request 消息后执行的逻辑如下,如果 STUN binding request 里包含 USE-CANDIDATE 则会将 tuple 设置为 selectedTuple,如果包含 NOMINATION 则必须属性里携带的提名值大于当前使用的提名值,处理完成后将 ICE 状态设置为 COMPLETED。

        当 ICE 处于 COMPLETED 状态收到 STUN binding request 后的处理与 ICE 处于 CONNECTED 时收到 STUN binding request 的处理基本类似,如下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/61899.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ruoyi若依 组织架构设计--[ 角色管理 ]

ruoyi若依 组织架构设计--[ 角色管理 ] 角色新增后端代码 角色修改后端代码 角色查询角色删除角色分配数据权限后端代码 角色分配用户 角色新增 后端代码 有一点&#xff0c;我认为新增的时候&#xff0c;也需要修改redis中的权限。 角色修改 后端代码 因为修改了role_menu表了…

坚鹏:中国邮储银行金融科技前沿技术发展与应用场景第2期培训

中国邮政储蓄银行金融科技前沿技术发展与应用场景第2期培训圆满结束 中国邮政储蓄银行拥有优良的资产质量和显著的成长潜力&#xff0c;是中国领先的大型零售银行。2016年9月在香港联交所挂牌上市&#xff0c;2019年12月在上交所挂牌上市。中国邮政储蓄银行拥有近4万个营业网点…

hcip——期中小试

要求&#xff1a; 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2 、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3 、整张拓扑均使用私网地址进行配置。 4 、整张网络中&#xff0c;运行 O…

Unity Sort Group(排序组)

** Unity 中的Sort Group组组件允许让Sprite Renderer(精灵渲染器)重新决定渲染顺序. ** 作为组件存在 组件内容&#xff1a; Unity 使用Sort Group 组件的Sort layer 和Order in layer的值来确定排序组在渲染队列内相对与场景内其他排序组和游戏对象的优先级。 属性功能So…

最新2024届【海康威视】内推码【GTK3B6】

最新2024届【海康威视】内推码【GTK3B6】 【内推码使用方法】 1.请学弟学妹们登录校招官网&#xff0c;选择岗位投递简历&#xff1b; 2.投递过程中填写内推码完成内推步骤&#xff0c;即可获得内推特权。 内推码&#xff1a;GTK3B6 内推码&#xff1a;GTK3B6 内推码&…

【Python】基础数据结构:列表——元组——字典——集合

文章目录 一、简述二、Python中的列表详解2.1 创建列表2.2 访问列表元素2.3 修改列表元素2.4 列表切片2.5 列表方法2.6 列表推导式 三、Python中的元组详解3.1 创建元组3.2 访问元组元素3.3 元组是不可变的3.4 元组切片3.5 元组方法 四、Python中的字典详解4.1 创建字典4.2 访问…

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?

一、介绍 Decorator&#xff0c;即装饰器&#xff0c;从名字上很容易让我们联想到装饰者模式 简单来讲&#xff0c;装饰者模式就是一种在不改变原类和使用继承的情况下&#xff0c;动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此&#xff0c;其本质也不是什么高大…

避免安装这5种软件,手机广告频繁弹窗且性能下降

在我们使用手机的日常生活中&#xff0c;选择合适的应用软件对于保持良好的使用体验至关重要。然而&#xff0c;有些软件可能会给我们带来不必要的麻烦和困扰。特别是那些频繁弹窗广告、导致手机性能下降的应用程序&#xff0c;我们应该尽量避免安装它们。 首先第一种&#xf…

VR实景导航——开启3D可视化实景导航新体验

数字化时代&#xff0c;我们大家出门在外都是离不开各种导航软件&#xff0c;人们对导航的需求也越来越高&#xff0c;而传统的导航软件由于精度不够&#xff0c;无法满足人们对真实场景的需求&#xff0c;这个时候就需要VR实景导航为我们实景指引目的地的所在。 VR实景导航以其…

【数理知识】协方差,随机变量的的协方差,随机变量分别是单个数字和向量时的协方差

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

使用WebMvcConfigurationSupport后导致原来返回的json数据变为了xml的解决方法

问题 未使用WebMvcConfigurationSupport拦截时返回的数据都是JSON格式&#xff0c;使用WebMvcConfigurationSupport做拦截后数据的返回变为了XML的格式。 原因 在Spring框架中&#xff0c;WebMvcConfigurationSupport 是一个类&#xff0c;它可以用于自定义Spring MVC的配置…

P1833 樱花(多重背包)(内附封面)

樱花 题目背景 《爱与愁的故事第四弹plant》第一章。 题目描述 爱与愁大神后院里种了 n n n 棵樱花树&#xff0c;每棵都有美学值 C i ( 0 ≤ C i ≤ 200 ) C_i(0 \le C_i \le 200) Ci​(0≤Ci​≤200)。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸&#…

代码分析:循环创建N个子进程——为什么最后一个属于父进程?

黑马C/C 2018年32期代码分析 //循环创建n个子进程 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h>int main() {int i 0;for(i0; i<3; i){//创建子进程pid_t pid fork();if(pid&…

Qt实现可伸缩的侧边工具栏(鼠标悬浮控制伸缩栏)

Qt实现可伸缩的侧边工具栏 一直在网上找&#xff0c;发现大多的实现方案都是用一个按钮&#xff0c;按下控制侧边栏的伸缩&#xff0c;但是我想要实现鼠标悬浮在侧边栏的时候就伸出&#xff0c;移开就收缩的功能&#xff0c;也没找到好的参考&#xff0c;所以决定自己实现一个…

QT中使用ffmpeg的api进行视频的播放

在了解ffmpeg使用api进行视频的播放之前&#xff0c;我们首先了解一下视频的播放流程。 一、视频的播放流程 首先是我们最常见的视频文件&#xff0c;在播放流程中首先是要打开视频文件&#xff0c;将视频文件中的数据进行解封装&#xff0c;之后再将解封装之后的视频进行解码…

【LeetCode】287. 寻找重复数

287 . 寻找重复数&#xff08;中等&#xff09; 方法 快慢指针 思路 要解决这道题首先要理解如何将输入的数组看作为链表。对于数组 nums 中的数字范围在 [1, n]&#xff0c;考虑两种情况&#xff1a; 如果数组中没有重复的数字&#xff0c;以 [1, 3, 4, 2] 为例&#xff0c;将…

FPGA优质开源项目 - UDP RGMII千兆以太网

本文介绍一个FPGA开源项目&#xff1a;UDP RGMII千兆以太网通信。该项目在我之前的工作中主要是用于FPGA和电脑端之间进行图像数据传输。本文简要介绍一下该项目的千兆以太网通信方案、以太网IP核的使用以及Vivado工程源代码结构。 Vivado 的 Tri Mode Ethernet MAC IP核需要付…

MPU6050

偏航角&#xff08;Yaw&#xff09; 横滚角&#xff08;ROll&#xff09; 俯仰角&#xff08;Pit&#xff09; 误差 mpu6050里面有一个受力的东西 受重力影响的电容 某个导体就往下一点 根据fma就可以算出当前的加速度值 加速度传感器只输出加速度 知道重力加速度和重力的角度可…

flask中实现restful-api

flask中实现restful-api 举例&#xff0c;我们可以创建一个用于管理任务&#xff08;Task&#xff09;的API。在这个例子中&#xff0c;我们将有以下API&#xff1a; GET /tasks: 获取所有任务POST /tasks: 创建一个新的任务GET /tasks/<id>: 获取一个任务的详情PUT /t…

软工导论知识框架(四)结构化系统的实现

一.编码 编码和测试统称为系统实现。 1.目的&#xff1a;把模块的过程性描述翻译为用选定的程序设计语言书写的源程序&#xff08;源代码&#xff09;。 &#xff08;真正交付给用户使用的&#xff0c;并不是源代码&#xff0c;而是经过编译链接生成的可执行的代码&#xff…