大家都知道奥斯卡有提名,其实在 WebRTC 的 ICE 中也有提名,有常规的提名,也有激进的提名,而且提名的候选人不一定是最优秀的候选人喔,本文就带你一探其中玄妙。文章内容主要描述 RFC 5245 中 ICE 相关的状态和 ICE 提名机制,并结合 libnice(0.14) 版本进行分析。

作者:阵图,阿里云开发工程师

审校:泰一,阿里云高级开发工程师

Scene

分析一个问题时候遇到这样的场景:服务端一个 Candidate,客户端三个不同优先级的 Candidate,但是最后居然选择了一个优先级最低的 Pair。

服务端有一个 Relay Candidate,端口 50217。

a=candidate:3 1 udp 503316991 11.135.171.187 50217 typ relay raddr 10.101.107.25 rport 40821

客户端有三个 Candidate,端口 50218(中间优先级),50219(最低优先级),50220(最高优先级)。

Candidate 1:
candidate:592388294 1 udp 47563391 11.135.171.187 50219 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50 Candidate 2:
candidate:592388294 1 udp 48562623 11.135.171.187 50218 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50 Candidate 3:
candidate:592388294 1 udp 49562879 11.135.171.187 50220 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50

但是最后选择的却是最低优先级的 Pair,50219。

Remote selected pair: 1:1 592388294 UDP 11.135.171.187:50219 RELAYED

Candidate's Foundation

Candidate 的 Foundation: 这里先提一下 Foundation,会涉及到 Frozen 状态。

对于一条相同的信道,可能有不同的 Candidate,比如 Relay Candidate 被发现的时候,就可以生成一个新的 Server Reflexive 类型的 Candidate,但是他们都是基于相同的本地地址(IP,端口)和协议,则可以认为这些网络是相似的,则他们就会有相同的 Foundation。其中 Foundation 在 SDP 中为第一个字段,即下面例子中的 '7'。

a=candidate:7 1 udp 503316991 11.178.68.36 51571 typ relay raddr 30.40.198.7 rport 55896

ICE States

ICE 主要有以下五种状态,其中前四种是正常的状态,第五种状态 Frozen 涉及到 ICE Frozen Algorithm

ICE 的五种状态:

  • Waiting: 当连通性检查还没有开始执行的时候(Binding Request 还没发送)。
  • In Progress: 当连通性检查发送了,但是相应检查的事务仍在执行中(Binding Request 已发送)。
  • Successed: 连通性检查执行完成且返回结果成功(Binding Request 已完成)。
  • Failed: 连通性检查执行完成且结果失败(Binding Request 已完成)。
  • Frozen: ,所有 Candidate Pair 初始化完成以后就在这个状态,对于相同的 Foundation(相似的 Candidate),会按照优先级依次选取一个 Pair,Unfreeze,并设置为 Waiting 状态,其他则保持 Frozen。直到选取的 Pair 完成,才会继续 Unfreeze 另一个 Pair。

ICE Nomination

ICE 有两种提名方式:

1.Regular Nomination

对于常规提名,主要工作流程如下:

L                        R
- -
STUN request -> \ L's
<- STUN response / check <- STUN request \ R's
STUN response -> / check STUN request + flag -> \ L's
<- STUN response / check Regular Nomination

Controlling 模式下的 Agent 发起 Binding Request,并且收到对端的 Response,同时对端发起的 Connective Check 完成,Controling 一端会再次发出一个携带 USE_CANDIDATE 标志位的 Binding Request,当 Controlled 一端收到了,就接受这次提名。

2.Aggressive nomination

除了常规提名,还有一种比较激进的提名,常规提名中会新增一次握手。

L                        R
- -
STUN request + flag -> \ L's <- STUN response / check
<- STUN request \ R's
STUN response -> / check Figure 5: Aggressive Nomination

Controlling 模式下的 Agent 发起 Binding Request,但是在这个 Binding Request 中会直接携带 USE_CANDIDATE 的标志位,Controlled 模式下的 Agent 收到了以后就接受这次提名。在激进提名模式下,能节约一次握手过程,但是当多个 Pair 同时接受提名时,会根据这些 Pair 各自的优先级进行选择,选择出优先级最高的 Pair 作为实际的信道。

真实案例:

Updating States When Nomination

原文参考

当一个新的提名产生时,会对 ICE 内部状态进行对应的变化。

当一端的 Binding Request 携带了 Use Candidate 的标志位时,则会产生一次提名(Nomination)。

不管 Controlling 或者 Controlled 模式下的 Agent,处理提名的状态更新规则建议如下:

  • 如果没有提名的 Pair,则继续进行连通性检查的过程。

  • 如果至少有一个有效的提名:

    • Agent 必须删除该 Component 下的所有 Waiting 状态和 Frozen 状态的 Pair。
    • 对于 In Progress 状态下的 Pair,优先级低于当前提名 Pair 优先级的,停止重传(取消)。
  • 当某一个 Stream 的所有 Compont 都至少拥有一个提名时,且检查仍然在进行时:

    • Agent 必须将该 Stream 标记为已完成。
    • Agent 可以开始传输媒体流。
    • Agent 必须持续响应收到的消息。
    • Agent 必须重传当前仍然在 In Progress 的 Pair(优先级高于当前提名的,不然已经被删除或者取消)。
  • 当检查列表中的所有 Pair 都完成时:

    • ICE 完成。
    • Controlling Agent 根据优先级更新 Offer(貌似 WebRTC 没有这一步)。
  • 当检查列表检查有失败时:

    • 所有 Pair 都失败时,关闭 ICE。
    • 当有某个流的检查成功时,Controlling Agent 移出失败的 Pair,并更新 Offer。
    • 如果有些检查没有完成,则 ICE 继续。

Scheduling Checks

在描述提名时,还会涉及 ICE 对 Pair 的调度(当有效 Candidate 还在 In Progress 的时候但是其他 Candidate 的 Pair 已经收到 Binding Request)。

这里只讨论 Full,先不描述 Lite 模式。

ICE 的 Checks 分成两种,Ordinary Checks And Triggered Checks。

  • Ordinary Checks 是常规的 Pair 的检查,表示这些 Pair 的检查是从正常流程中切换过来的状态的检查。
  • Triggered Check 是被动触发的检查,当这些 Pair 虽然还处在不可以开始检查的状态,但是这时候收到了对端的连通性检查,这时候会对这个 Pair 进行提速,将其直接放入调度列表。

当 ICE 建立一个 Check List (每个 Stream 一个)后,会对每个 Check List 添加一个定时器,当定时器到来时,会进行如下调度:

注:这里有点不能理解,整个流程看起来是串行的,激活速度有点慢。

  • 首先调度 Triggered Check 并执行。
  • 若无,调度优先级最高的 Waiting 状态的 Pair,发送 Request,同时将状态置为 In Progress。
  • 若无,则从 Check List 中找出优先级最高的 Frozen 状态的 Pair,Unfreeze 之,并发送 Request,状态设置为 In Progress。
  • 若无,终止调度。

Case Analyzed

简单了解了 ICE 的流程后,我们回归最开始的 Case。

首先看 Add Candidate,三个 Remote Candidate 添加顺序不同,依次为 50219,50218,50220,注意,此时 50219 收到了对端的 Binding Request,激进提名,携带 USE_CANDIDATE,因此很快执行 Create Permission 并完成,这时候可以开始发送 Binding Request 了,属于 Triggered Checks 优先调度,发送 Binding Request,并进入 In Progress 状态。

注:这里除了本地 Relay 的 Pair,还有和 Turn 通信的本地 Host 类型的 Candidate。

接着在 50219 在其他两个 Create Permission 还没完成时候以迅雷不及掩耳之势完成了 Check,根据 rfc 8.1.2 中的描述,对于不是在 In Progress 状态的 Pair,都删除,并不参考其优先级,故最后选择了 50219 这个优先级最低的 Pair。

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

WebRTC ICE 状态与提名处理的更多相关文章

  1. WebRTC 之ICE浅谈

    前言 ICE全称Interactive Connectivity Establishment:交互式连通建立方式. ICE参照RFC5245建议实现,是一组基于offer/answer模式解决NAT穿 ...

  2. Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键?

    本文主要介绍WebRTC端到端监控(我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信I ...

  3. 【Webkit Blog翻译】深入研究WebRTC | 内有福利

    本文译自 A Closer Look Into WebRTC” 我们在最近的一篇 WebKit博客中宣布了对High Sierra平台和iOS中Safari的WebRTC支持.现在,我们希望能够带领大 ...

  4. WebRTC音频通话升级为视频通话

    我们有时候在音频通话过程中,想要改成视频通话.如果挂断当前通话再重新发起视频通话就会显得比较麻烦. 因此很多app提供了将音频通话升级成视频通话的功能,同时也有将视频通话降为音频通话的功能. 本文演示 ...

  5. Android WebRTC 音视频开发总结(一)

    本系列文章主要总结和分享WebRTC开发过程中的一些经验,转载请说明出处(博客园RTC.Blacker),更多交流与合作请看页面上方的子标题! 一.WebRTC是什么? 可能您还不知道WebRTC是什 ...

  6. 【转】Android WebRTC 音视频开发总结(一)

    http://www.cnblogs.com/lingyunhu/p/3578218.html 本系列文章主要总结和分享WebRTC开发过程中的一些经验,转载请说明出处(博客园RTC.Blacker) ...

  7. webrtc进阶-信令篇-之三:信令、stun、turn、ice

    webRTC支持点对点通讯,但是webRTC仍然需要服务端:  . 协调通讯过程中客户端之间需要交换元数据,    如一个客户端找到另一个客户端以及通知另一个客户端开始通讯.  . 需要处理NAT(网 ...

  8. Android IOS WebRTC 音视频开发总结(三十)-- ice协议异同

    本文主要介绍ICE与SDP交互过程中的一些知识,支持原创,文章来博客园RTC.Blacker,转载请说明出处. 用过libjingle模块的同学都知道连接过程中candidate的获取与连接流程,一边 ...

  9. android中webrtc的几个关键的状态

    在android层使用webrtc的时候,都是通过native层回调的形式来触发ui的改变,比如在什么时候绘出对方的视频窗口,什么时候表示双方连接已经建立等等... 我现在把我知道的列出来用于备忘. ...

随机推荐

  1. 轮廓检测论文解读 | 整体嵌套边缘检测HED | CVPR | 2015

    主题列表:juejin, github, smartblue, cyanosis, channing-cyan, fancy, hydrogen, condensed-night-purple, gr ...

  2. CSS-backgroound和radial-giadient的常见用法

    前言 这里主要介绍下css中background和radial-giadient径向渐变的使用,工作中用到的地方可能也不太多,但是每次用到了都需要查阅官网,查资料就比较麻烦,这里记录一下我自己整理的常 ...

  3. 最短路径——BFS算法

    最短路径--BFS算法 单源最短路径问题 每对顶点间的最短路径 BFS求无权图的单源最短路径 bool visited[MAX_VERTEX_NUM]; //访问标记数组 //广度优先遍历 void ...

  4. Android全面解析之Activity生命周期

    前言 很高兴遇见你~ 欢迎阅读我的文章. 关于Activity生命周期的文章,网络上真的很多,有很多的博客也都讲得相当不错,可见Activity的重要性是非常高的.事实上,我猜测每个android开发 ...

  5. C++将整型值转换为字符串

    最简单的方法是使用一个字符串流(stringstream):#include<iostream>#include<string>#include<sstream>u ...

  6. AWT02-ContainerAPI

    1.体系 Object -Component -Container Window:窗口容器 Frame:创建窗口 Dialog:创建对话框 Panel:内嵌容器 Applet ScrollPane:含 ...

  7. JavaSE15-集合·其二

    1.Set集合 1.1 Set集合概述和特点 Set集合的特点 元素存取无序 没有索引.只能通过迭代器或增强for循环遍历 不能存储重复元素 1.2 哈希值 哈希值简介 是JDK根据对象的地址或者字符 ...

  8. JavaSE03-运算符&分支语句

    1.运算符 1.1 算术运算符 1.1.1 运算符和表达式 运算符:对常量或者变量进行操作的符号 表达式:用运算符把常量或者变量连接起来符合java语法的式子就可以称为表达式. 不同运算符连接的表达式 ...

  9. js上 二.JavaScript基本语法

    1.JavaScript词法结构 所谓词法结构是指一套基础性规则,用来描述如何使用这门语言来编写程序,包括如下几项: ü 字符集unicode ü 区分大小写 (true和TRUE) ü 忽略空白字符 ...

  10. kepler.gl 2.4.0重要更新

    1 简介 kepler.gl作为开源地理空间数据可视化神器,也一直处于活跃的迭代开发状态下.而在前不久,kepler.gl正式发布了其2.4.0版本,下面我们就来对其重要的新特性进行介绍: 图1 2 ...