1、WebRTC入门
1、以下内容来自 零声学院 ,把PDF放到博客上面来,方便以后检察
1.1 什么是WebRTC
WebRTC(Web RealTime Communication)是 Google于 2010 以 6829 万美元从 Global IP Solutions 公司购买,并于2011 年将其开源,旨在创建一个互联网浏览器间的实时通讯的平台,让 WebRTC技能成为 H5标准之一。我们看 官网 的介绍
从官网上的描述我们可以知道,WebRTC是一个免费的开放项目,它通过简单的API为浏览器和移动应用步调提供实时通讯(RTC)功能。
1.2 WebRTC框架
上图的框架对于不同的开发人员关注点不同:
( 1 )紫色部门是Web应用开发者API层
( 2 )蓝色实线部门是面向浏览器厂商的API层
( 3 )蓝色虚线部门浏览器厂商可以自界说实现
特别是图中的 PeerConnection 为 Web 开发人员提供了一个抽象,从复杂的内部结构中抽象出来。我们只需要关注PeerConnection这个对象即可以开发音视频通话应用内。
WebRTC架构组件介绍
- Your Web App
Web开发者开发的步调,Web开发者可以基于集成WebRTC的浏览器提供的web API开发基于视频、音频的实时通讯应用。
- Web API
面向第三方开发者的WebRTC标准API(Javascript),使开发者能够容易地开发出类似于网络视频谈天的web应用,
最新的标准化历程可以检察这里。
- WebRTC Native C++ API
本地C++ API层,使浏览器厂商容易实现WebRTC标准的Web API,抽象地对数字信号过程举行处理。
- Transport / Session
传输/会话层
会话层组件采取了libjingle库的部门组件实现,无须使用xmpp/jingle协议
- VoiceEngine
音频引擎是包罗一系列音频多媒体处理的框架。
PS:VoiceEngine是WebRTC极具价值的技能之一,是Google收购GIPS公司后开源的。在VoIP上,技能业界领先。
Opus:支持从6 kbit/s到510 kbit/s的恒定和可变比特率编码,帧巨细从2.5 ms到60 ms,各种采样率从8 kHz(4 kHz带宽)到48 kHz(20 kHz带宽,可复制人类听觉系统的整个听力范围)。由IETF RFC 6176界说。NetEQ模块是Webrtc语音引擎中的核心模块 ,一种动态抖动缓冲和错误埋伏算法,用于埋伏网络抖动和数据包丢失的负面影响。保持尽大概低的延迟,同时保持最高的语音质量。
- VideoEngine
WebRTC视频处理引擎VideoEngine是包罗一系列视频处理的团体框架,从摄像头收罗视频到视频信息网络传输再到视频表现整个完整过程的解决方案。
VP8 视频图像编解码器,是WebRTC视频引擎的默认的编解码器
VP8适合实时通讯应用场景,因为它重要是针对低延时而计划的编解码器。
1.2.1 WebRTC发展远景
WebRTC虽然冠以“web”之名,但并不受限于传统互联网应用或浏览器的终端运行情况。实际上无论终端运行情况是浏览器、桌面应用、移动设备(Android或iOS)还是IoT设备,只要IP毗连可到达且符合WebRTC规范就可以互通。
这一点开释了大量智能终端(或运行在智能终端上的app)的实时通讯本领,打开了许多对于实时交互性要求较高的应用场景的想象空间,譬如在线教育、视频集会、视频交际、长途协助、长途操控等等都是其合适的应用范畴。
环球领先的技能研究和咨询公司Technavio最近发布了题为“环球网络实时通讯(WebRTC)市场,20172021”的陈诉。陈诉表现,20172021年期间,环球网络实时通讯(WebRTC)市场将以34.37%的年均复合增长率增长,增长非常迅速。增长重要来自北美、欧洲及亚太地区。
1.2.2 国内方案厂商
声网、即构科技、环信、融云等公司都在基于WebRTC二次开发本身的音视频通话方案。
- 声网 https://www.agora.io/cn/
- 即构科技 https://www.zego.im/
1.2.3 WebRTC通话原理
起首思索的问题:两个不同网络情况的(具备摄像头/麦克风多媒体设备的)浏览器,要实现点对点 的实时音视频对话,难点在那里?
比如:PeerA端可支持VP8、H264多种编码格式,而PeerB端支持VP9、H264,要保证二端都正确的编解码,最简单的办法就是取它们的交集H264
注:有一个专门的协议 ,称为Session Description Protocol (SDP),可用于描述上述这类信息,在WebRTC中,到场
视频通讯的双方必须先互换SDP信息,这样双方才能知根知底,而互换SDP的过程,也称为"媒体协商"。
- 网络协商
彼此要相识对方的网络情况,这样才有大概找到一条相互通讯的链路
先说结论:(1)获取外网IP地址映射;( 2 )通过信令服务器(signal server)互换"网络信息"
理想的网络情况是每个浏览器的电脑都是私有公网IP,可以直接举行点对点毗连。
实际情况是:我们的电脑和电脑之前或大或小都是在某个局域网中,需要NAT(Network Address Translation,网络地址转换),表现情况如下图:
在解决WebRTC使用过程中的上述问题的时间,我们需要用到STUN和TURN。
1.2.4 STUN
STUN(Session Traversal Utilities for NAT,NAT会话穿越应用步调)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出本身的公网地址,查出本身位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。这些信息被用来在两个同时处于NAT路由器之后的主机之间创建UDP通讯。该协议由RFC 5389界说。
在遇到上述情况的时间,我们可以创建一个STUN服务器,这个服务器做什么用的呢?重要是给无法在公网情况下的视频通话设备分配公网IP用的。这样两台电脑就可以在公网IP中举行通话。
使用一句话说明STUN做的变乱就是:告诉我你的公网IP地址+端口是什么。搭建STUN服务器很简单,媒体流传输是按照P2P的方式。
那么问题来了,STUN并不是每次都能成功的为需要NAT的通话设备分配IP地址的,P2P在传输媒体流时,使用的本地带宽,在多人视频通话的过程中,通话质量的优劣往往需要根据使用者本地的带宽确定。那么怎么办?TURN可以很好的解决这个问题。
1.2.5 TURN
TURN的全称为Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,重要添加了Relay功能。如果终端在NAT之后, 那么在特定的景象下,有大概使得终端无法和其对等端(peer)举行直接的通讯,这时就需要公网的服务器作为一个中继, 对来往的数据举行转发。这个转发的协议就被界说为TURN。
在上图的底子上,再架设几台TURN服务器:
在STUN分配公网IP失败后,可以通过TURN服务器请求公网IP地址作为中继地址。这种方式的带宽由服务器端负担,在多人视频谈天的时间,本地带宽压力较小,而且,根据Google的说明,TURN协议可以使用在所有的情况中。(单向数据200kbps 一对一通话)
以上是WebRTC中常常用到的 2 个协议,STUN和TURN服务器我们使用coturn开源项目来搭建。
补充:ICE跟STUN和TURN不一样,ICE不是一种协议,而是一个框架(Framework),它整合了STUN和TURN。coturn开源项目集成了STUN和TURN的功能。
1.2.6 STUN&TURN 概括
STUN(Session Traversal Utilities for NAT)和 TURN(Traversal Using Relays around NAT)是两种用于解决网络地址转换(NAT)情况下通讯问题的协议。
一、STUN
- 作用:
- STUN 的重要目的是帮助位于 NAT 反面的客户端发现本身的公网 IP 地址和端口号。这对于创建直接的点对点通讯非常紧张,尤其是在使用实时通讯协议如 WebRTC 时。
- 通过向 STUN 服务器发送请求,客户端可以获取到本身在公网中的可看法址信息,然后将这些信息分享给通讯的另一方,以便实验直接创建毗连。
- 工作原理:
- 客户端向 STUN 服务器发送请求消息,其中包罗一些特定的信息,如客户端的内网 IP 地址和端口号等。
- STUN 服务器收到请求后,会复兴一个响应消息,其中包罗客户端的公网 IP 地址和端口号,以及一些其他的属性信息,如 NAT 的类型等。
- 客户端根据收到的响应消息,确定本身的公网地址信息,并可以实验与其他客户端创建直接毗连。
- 应用场景:
- 在 WebRTC 应用中,STUN 服务器通常被用于帮助客户端发现本身的公网地址,以便举行点对点通讯。如果两个客户端位于不同的 NAT 反面,但它们的 NAT 类型允许直接创建毗连,那么就可以通过 STUN 发现的公网地址举行通讯,无需经过中间服务器转发。
- 对于一些简单的 NAT 情况,STUN 大概足以解决通讯问题。但在某些情况下,如 NAT 类型限制或网络限制,仅靠 STUN 大概无法实现直接通讯。
二、TURN
- 作用:
- 当直接的点对点毗连无法创建时,TURN 服务器可以作为中继,转发通讯双方的数据。这在 NAT 情况非常严格或者存在防火墙等限制的情况下非常有用。
- TURN 服务器接收来自一个客户端的数据,然后将其转发给另一个客户端,确保通讯的持续举行。
- 工作原理:
- 客户端起首实验通过 STUN 发现本身的公网地址并实验直接创建毗连。如果直接毗连失败,客户端可以向 TURN 服务器申请中继服务。
- 客户端将数据发送到 TURN 服务器指定的端口,TURN 服务器收到数据后,根据目标地址将其转发给另一个客户端。同样,另一个客户端也将数据发送到 TURN 服务器,由服务器转发给第一个客户端。
- TURN 服务器在转发数据的过程中,通常会对数据举行一些处理,如封装、加密等,以确保数据的安全和可靠传输。
- 应用场景:
- 在复杂的网络情况中,如企业网络、移动网络等,TURN 服务器可以作为一种可靠的通讯解决方案。当直接毗连不可行时,通过 TURN 服务器的中继服务,仍然可以实现实时通讯。
- 对于一些对通讯质量要求较高的应用,如视频集会、在线游戏等,TURN 服务器可以提供稳固的通讯路径,确保数据的及时传输。
三、STUN 和 TURN 的关系
- 通常情况下,在实验创建通讯时,会先使用 STUN 服务器来发现公网地址并实验直接毗连。如果直接毗连失败,再使用 TURN 服务器作为中继。
- STUN 和 TURN 可以结合使用,为不同的网络情况提供灵活的通讯解决方案。比方,在 WebRTC 中,通常会同时配置 STUN 和 TURN 服务器,以确保在各种情况下都能实现通讯。
- 两者都是为相识决 NAT 带来的通讯问题,但 STUN 更侧重于发现公网地址和实验直接毗连,而 TURN 则是在直接毗连不可行时提供可靠的中继服务。
总之,STUN 和 TURN 是在 NAT 情况下实现通讯的紧张协议,它们为各种实时通讯应用提供了必要的技能支持。
1.3、 媒体协商+网络协商数据的互换通道
在WebRTC中用来描述 网络信息的术语叫candidate。
从上面1/2点我们知道了 2 个客户端协商媒体信息和网络信息,那怎么去互换?是不是需要一个中间商去做互换?以是我们需要一个信令服务器(Signal server)转发彼此的媒体信息和网络信息。
如上图,我们在基于WebRTC API开发应用(APP)时,可以将彼此的APP毗连到信令服务器(Signal Server,一般搭建在公网,或者两端都可以访问到的局域网),借助信令服务器,就可以实现上面提到的SDP媒体信息及Candidate网络信息互换。
信令服务器不只是交互 媒体信息sdp和网络信息candidate,比如:
1.3.1、WebRTC APIs
- MediaStream — MediaStream用来表示一个媒体数据流(通过getUserMedia接口获取),允许你访问输入设备,如麦克风和 Web摄像机,该 API 允许从其中任意一个获取媒体流。
- RTCPeerConnection — RTCPeerConnection 对象允许用户在两个浏览器之间直接通讯 ,你可以通过网络将捕获的音频和视频流实时发送到另一个 WebRTC 端点。使用这些 Api,你可以在本地机器和长途对等点之间创建毗连。它提供了毗连到长途对等点、维护和监督毗连以及在不再需要毗连时关闭毗连的方法。
1.3.2、 一对一通话
在一对一通话场景中,每个 Peer均创建有一个 PeerConnection 对象,由一方主动发 Offer SDP,另一方则应答AnswerSDP,最后双方互换 ICE Candidate 从而完成通话链路的创建。但是在中国的网络情况中,据一些统计数据表现,至少 1 半的网络是无法直接穿透打通,这种情况下只能借助TURN服务器中转。
1.3.3、 NAT知识补充
具体NAT打洞的知识在本课程不做进一步的讲解,这里提供些链接给大家做参考:
- P2P技能详解(一):NAT详解——详细原理、P2P简介 https://www.cnblogs.com/mlgjb/p/8243646.htm
- P2P技能详解(二):P2P中的NAT穿越(打洞)方案详解 https://www.jianshu.com/p/9bfbcbee0abb
- P2P技能详解(三):P2P技能之STUN、TURN、ICE详解 https://www.jianshu.com/p/258e7d8be2ba
- 详解P2P技能中的NAT穿透原理 https://www.jianshu.com/p/f71707892eb
2、WebRTC开发情况
1、安装vscode或者idea,等等开发工具
2、安装 nodejs
2.1、第一个nodejs教程
nodejs教程:https://www.runoob.com/nodejs/nodejstutorial.html
- # 查看是否安装,安装正常则打印版本号
- node ‐v
- npm ‐v
复制代码
以上代码我们完成了一个可以工作的 HTTP 服务器。使用 node 下令执行以上的代码:接下来,打开浏览器访问 http://127.0.0.1:8888/,你会看到一个写着 "Hello World"的网页。
分析Node.js 的 HTTP 服务器:
第一行请求(require)Node.js 自带的 http 模块,而且把它赋值给 http 变量。
接下来我们调用 http 模块提供的函数: createServer 。这个函数会返回 一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。
2.2、coturn穿透和转发服务器
1、这部门直接参考 官网就好了,也可以使用docker安装
cotun github
2.3、分别测试stun和turn
Coturn是集成了stun+turn协议。
测试网址: 在线测试地址
3、音视频收罗和播放
有三个案例:
- 打开摄像头并将画面表现到页面;
- 打开麦克风并在页面播放捕获的声音;
- 同时打开摄像头和麦克风,并在页面表现画面和播放捕获的声音
3.1、 打开摄像头
实战:打开摄像头并将画面表现到页面,效果展示
3.1.1、代码流程
- 初始化button、video控件
- 绑定“打开摄像头”响应变乱onOpenCamera
- 如果要打开摄像头则点击 “打开摄像头”按钮,以触发onOpenCamera变乱的调用
- 当触发onOpenCamera调用时
a. 设置束缚条件,即是getUserMedia函数的入参
b. getUserMedia有两种情况,一种是正常打开摄像头,使用handleSuccess处理;一种是打开摄像头失败,使用handleError处理
c. 当正常打开摄像头时,则将getUserMedia返回的stream对象赋值给video控件的srcObject即可将视频表现出来
3.1.2、示例代码
3.2、打开麦克风
实战:打开麦克风并在页面播放捕获的声音,效果展示
3.2.1、代码流程
- 初始化button、audio控件
- 绑定“打开麦克风”响应变乱onOpenMicrophone
- 如果要打开麦克风则点击 “打开麦克风”按钮,以触发onOpenMicrophone变乱的调用
- 当触发onOpenCamera调用时
a. 设置束缚条件,即是getUserMedia函数的入参
b. getUserMedia有两种情况,一种是正常打开麦克风,使用handleSuccess处理;一种是打开麦克风失败,使用handleError处理
c. 当正常打开麦克风时,则将getUserMedia返回的stream对象赋值给audio控件的srcObject即可将声音播放出来
3.2.2、 示例代码
3.3、打开摄像头和麦克风
同时打开摄像头和麦克风,范例可以参考3.1,只是在束缚条件中把
改为
3.3.1、具体代码
3.4、补充讲解
3.4.1、getUserMedia API简介
HTML5的getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。
getUserMedia API最初是navigator.getUserMedia,目前已被最新Web标准废除,变更为navigator.mediaDevices.getUserMedia(),但浏览器支持情况不如旧版API普及。
MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,比方相机或屏幕共享和/或麦克风。如果用户给予许可,就返回一个Promise对象,MediaStream对象作为此Promise对象的Resolved[成功]状态的回调函数参数,相应的,如果用户拒绝了许可,或者没有媒体可用的情况下PermissionDeniedError或者NotFoundError作为此Promise的Rejected[失败]状态的回调函数参数。注意,由于用户不会被要求必须作出允许或者拒绝的选择,以是
返回的Promise对象大概既不会触发resolve也不会触发 reject。
3.4.2、浏览器兼容性
3.4.3、语法&参数
成功回调函数seccessCallback的参数stream:stream是MediaStream的对象,表示媒体内容的数据流,可以通过URL.createObjectURL转换后设置为Video或Audio元素的src属性来使用,部门较新的浏览器也可以直接设置为srcObject属性来使用(Darren注:目前大部门浏览器都是使用srcObject)。
失败回调函数errorCallback的参数error,大概的异常有:
- AbortError:硬件问题
- NotAllowedError:用户拒绝了当前的浏览器实例的访问请求;或者用户拒绝了当前会话的访问;或者用户在全局范围内拒绝了所有媒体访问请求。
- NotFoundError:找不到满足请求参数的媒体类型。
- NotReadableError:操作系统上某个硬件、浏览器或者网页层面发生的错误导致设备无法被访问。
- OverConstrainedError:指定的要求无法被设备满足。
- SecurityError:安全错误,在getUserMedia() 被调用的 Document上面,使用设备媒体被克制。这个机制是否开启或者关闭取决于单个用户的偏好设置。TypeError:类型错误,constraints对象未设置[空],或者都被设置为false。
3.4.4、HTML 5调用媒体设备摄像头
这个例子中,请求访问用户硬件设备的摄像头,并把视频流畅过Video元素表现出来。网页中提供一个"照相"的按钮,
通过Canvas将Video的画面截取并绘制,核心代码如下:
3.4.5、WebRTC检测音视频设备
1、API说明
webrtc获取电脑所有音视频设备的API:enumerateDevices。获取成功后走then的方法,获取失败走catch的方法。
获取到的音视频设备信息包括:
2、代码示例完整代码范例
4、WebRTC底子前站
1、该章节重要是对WebRTC相关的底子知识做补充。
2、一般情况下,在实时音视频通话传输音视频数据流时,我们并不直接将音视频数据流交给 UDP 传输,而是先 给音视频数据加个 RTP 头,然后再交给 UDP 举行传输。为什么要这样做呢?
3、我们以视频帧为例,一个 I 帧的数据量黑白常大的,最少也要几十 K。而以太网的最大传输单位是多少呢?1.5K,以是要传输一个 I 帧需要几十个包。而且这几十个包传到对端后,还要重新组装成 I 帧,这样才能举行解码还原出一幅幅的图像。如果是我们本身实现的话,要完成这样的过程,至少需要以下几个标识。
- 序号:用于标识传输包的序号,这样就可以知道这个包是第几个分片了。
- 起始标记:记录分帧的第一个 UDP 包。
- 竣事标记:记录分帧的最后一个 UDP 包。
有了上面这几个标识字段,我们就可以在发送端举行拆包,在接收端将视频帧重新再组装起来了。
4.1、 RTP 协议
其实,这样的需求在很早之前就已经有了。因此,人们专门界说了一套规范,它就是RTP协议。下面让我们来详细看一下 RTP 协议吧。
如图所示,RTP 协议非常简单,我这里按字段的紧张性从高往低的次序讲解一下。
- sequence number:序号,用于记录包的次序。这与上面我们本身实现拆包、组包是同样的原理。
- imestamp:时间戳,同一个帧的不同分片的时间戳是雷同的。这样就省去了前面所讲的起始标记和竣事标记。肯定要记着,不同帧的时间戳肯定是不一样的。
- PT:Payload Type,数据的负载类型。音频流的 PT 值与视频的 PT 值是不同的,通过它就可以知道这个包存放的是什么类型的数据。
- …
这里,我并没有将 RTP 协议头中的所有字段的详细说明都列在这儿,如果你想相识所有字段的寄义,可以到参考一节检察其他字段的寄义。需要注意的是,这里没有将它们列出来并不代表它们不紧张。恰恰相反,如果 你想做音视频传输相关的工作,RTP 头中的每个字段的寄义你都必须全部清楚。
知道了上面这些字段的寄义后,下面我们还是来看一个具体的例子吧!假设你从网上接收到一组音视频数据,如下:
假设 PT=98 是视频数据,PT=111 是音频数据,那么按照上面的规则你是不是很容易就能将视频帧组装起来呢?
4.1.1、字段详解
RTP 协议头:
RTP有效负载(载荷)类型,RTP Payload Type具体见: 《RTP有效负载(载荷)类型,RTP PayloadType》https://blog.csdn.net/caoshangpa/article/details/53008018
PT从 96 到 127 是动态值,有些负载类型由于诞生的较晚,没有具体的PT值,只能使用动态(dynamic)PT值。
4.2、RTCP 协议
在使用 RTP 包传输数据时,难免会发生丢包、乱序、抖动等问题,下面我们来看一下使用的网络一般都会在什么情况下出现问题:
- 网络线路质量问题引起丢包率高;
- 传输的数据凌驾了带宽的负载引起的丢包问题;
- 信号干扰(信号弱)引起的丢包问题;
- 跨运营商引入的丢包问题 ;
- …
WebRTC 对这些问题在底层都有相应的处理战略,但在处理这些问题之前,它起重要让各端都知道它们本身的网络
质量到底是怎样的,这就是 RTCP 的作用。
RTCP 有两个最紧张的报文:RR(Reciever Report)和 SR(Sender Report)。通过这两个报文的互换,各端就知道本身的网络质量到底如何了。
RTCP 支持的所有报文及其寄义可以检察文章最后所附的参考一节。这里我们以SR 报文为例,看看 SR 报文中都包括哪些信息。
下面我就简要说明一下该报文中字段的寄义:
- V=2,指报文的版本。
- P,表示添补位,如果该位置 1 ,则在 RTCP 报文的最后会有添补字节(内容是按字节对齐的)。
- RC,全称 Report Count,指 RTCP 报文中接收陈诉的报文块个数。
- PT=200,Payload Type,也就是说 SR 的值为 200 。
- …
与 RTP 协议头一样,上面只介绍了 RTCP 头字段的寄义,至于其他每个字段的寄义请检察参考一节。同样的,对于RTCP 头中的每个字段也必须都非常清楚,只有这样以后你在看 WebRTC 带宽评估相关的代码时,才不至于晕头转向。
从上图中我们可以相识到,SR 报文分成三部门:Header、Sender info和Report block。在 NTP 时间戳之上的部门为 SR 报文的 Header 部门,SSRC_1 字段之上到 Header 之间的部门为 Sender info 部门,剩下的就是一个一个的Report Block 了。那这每一部门是用于干什么的呢?
- Header 部门用于标识该报文的类型,比如是 SR 还是 RR。
- Sender info 部门用于指明作为发送方,到底发了多少包。
- Report block 部门指明发送方作为接收方时,它从各个 SSRC 接收包的情况。
通过以上的分析,你可以发现SR 报文并不但是指发送方发了多少数据,它还陈诉了作为接收方,它接收到的数据的情况。当发送端收到对端的接收陈诉时,它就可以根据接收陈诉来评估它与对端之间的网络质量了,随后再根据网络质量做传输战略的调整。
SR 报文与RR 报文无疑是 RTCP 协议中最紧张的两个报文,不过 RTCP 中的其他报文也都非常紧张的,如果你想学好 WebRTC ,那么 RTCP 中的每个报文你都必须掌握。
比如,RTCP 类型为 206 、子类型为 4 的 FIR 报文,其寄义是 Full Intra Request (FIR) Command,即完整帧请求下令。它起什么作用?又在什么时间使用呢?
该报文也是一个特别关键的报文,我为什么这么说呢?试想一下,在一个房间里有 3 个人举行音视频谈天,然后又有一个人参加到房间里,这时如果不做任何处理的话,那么第四个人进入到房间后,在一段时间内很难直接看到其他三个人的视频画面了,这是为什么呢?
原因就在于解码器在解码时有一个上下文。在该上下文中,必须先拿到一个 IDR 帧之后才能将其反面的 P 帧、B 帧举行解码。也就是说,在没有 IDR 帧的情况下,对于收到的 P 帧、B 帧解码器只能干瞪眼了。
如何解决这个问题呢?这就引出了 FIR 报文。当第四个人参加到房间后,它起首发送 FIR 报文,当其他端收到该报文后,便立即产生各自的 IDR 帧发送给新参加的人,这样当新参加的人拿到房间中其他的 IDR 帧后,它的解码器就会解码成功,于是其他人的画面也就一下子全部展示出来了。以是你说它是不是很紧张呢?
4.3、媒体协商之sdp
比如:PeerA端可支持VP8、H264多种编码格式,而Peer-B端支持VP9、H264,要保证二端都正确的编解码,最简单的办法就是取它们的交集H264
注:有一个专门的协议 ,称为Session Description Protocol (SDP),可用于描述上述这类信息,在WebRTC中,到场视频通讯的双方必须先互换SDP信息,这样双方才能知根知底,而互换SDP的过程,也称为"媒体协商"。
SDP(Session Description Protocal)以文本描述各端(PC 端、Mac 端、Android 端、iOS 端等)的本领,这里的本领指的是各端所支持的:
- 音频编解码器是什么,这些编解码器设定的参数是什么
- 使用的传输协议是什么
- 以及包括的音视频媒体是什么等等。
一个sdp片断举例
如上面的 SDP 片断所示,该 SDP 中描述了一起音频流,即m=audio,该音频支持的 Payload ( 即数据负载 ),类型包括 111 、 103 、 104 等等。
在该 SDP 片断中又进一步对 111 、 103 、 104 等 Payload 类型做了更详细的描述,如 a=rtpmap:111,opus/48000/2 表示 Payload 类型为 111 的数据是 OPUS 编码的音频数据,而且它的采样率是 48000 ,使用双声道。以此类推,你也就可以知道 a=rtpmap:104 ISAC/32000 的寄义是音频数据使用 ISAC 编码,采样频率是 32000 ,使用单声道。
互换 SDP 信息,下面是 1 对 1 WebRTC 处理过程图:
如上图所示,两个客户端 / 浏览器举行 1 对 1 通话时,起重要举行信令交互,而交互的一个紧张信息就是SDP 的互换。
互换 SDP 的目的是为了让对方知道彼此具有哪些本领,然后根据双方各自的本领举行协商,协商出大家承认的音视频编解码器、编解码器相关的参数(如音频通道数,采样率等)、传输协议等信息。
如上图所示,Amy 与 Bob举行通讯,它们先各安闲 SDP 中记录本身支持的音频参数、视频参数、传输协议等信息,然后再将本身的 SDP 信息通过信令服务器发送给对方。当一方收到对端传来的 SDP 信息后,它会将接收到的 SDP 与本身的 SDP 举行比力,并取出它们之间的交集,这个交集就是它们协商的结果,也就是它们最终使用的音视频参数及传输协议了。
4.3.1、标准 SDP 规范
相识了 SDP 是什么,接下来我们看一下 SDP 规范。其实单论 SDP 规范它并不复杂,但 WebRTC 使用时又对其做了不少修改,以是当你初见完整的 WebRTC 的 SDP 时,大概会一脸茫然。
标准 SDP 规范重要包括SDP 描述格式和SDP 结构,而 SDP 结构由会话描述和媒体信息描述两个部门组成。其中,媒体信息描述是整个 SDP 规范中最紧张的知识,它又包括了:
- 媒体类型
- 媒体格式
- 传输协议
- 传输的 IP 和端口
下面我们就以上这些知识逐一举行讲解。
1、SDP 的格式
SDP 是由多个 = 这样的表达式组成的。其中,是一个字符,是一个字符串。需要特别注意的是,“=” 两边是不能有空格的。如下所示:
SDP 由一个会话级描述(session level description)和多个媒体级描述(media level description)组成。
- 会话级(session level)的作用域是整个会话,其位置是从 v= 行开始到第一个媒体描述为止。
- 媒体级(media level)是对单个的媒体流举行描述,其位置是从 m= 行开始到下一个媒体描述(即下一个m=)为止。
另外,除非媒体部门重新对会话级的值做界说,否则会话级的值就是各个媒体的缺省默认值。让我们看个例子吧。
面是一个特别简单的例子,每一行都是以一个字符开头,反面紧跟着即是号(=),即是号反面是一串字符。
从“v=”开始一直到“m=audio”,这之间的描述是会话级的;而反面的两个“m=”为媒体级。从中可以看出,在该SDP 描述中有两个媒体流,一个是音频流,另一个是视频流。
4.3.2、SDP 的结构
相识了 SDP 的格式,下面我们来看一下 SDP 的结构,它由会话描述和媒体描述两部门组成。
4.3.2.1、会话描述
会话描述的字段比力多,下面四个字段比力紧张,我们来重点介绍一下。
第一个,v=(protocol version,必选)。例子:v=0 ,表示 SDP 的版本号,但不包括次版本号。
第二个,o=(owner/creator and session identifier,必选)。例子:o = <username> <session id><version> <network type> <address type> <address>,该例子是对一个会话发起者的描述。其中,
- o= 表示的是对会话发起者的描述;
- <username>:用户名,当不关心用户名时,可以用 “-” 代替 ;
- <session id> :数字串,在整个会话中,必须是唯一的,发起使用 NTP 时间戳;
- <version>:版本号,每次会话数据修改后,该版本值会递增;
- <network type> :网络类型,一般为“IN”,表示“internet”;
- <address type>:地址类型,一般为 IP4;
- <address>:IP 地址。
第三个,Session Name(必选)。例子:s=<session name>,该例子表示一个会话,在整个 SDP 中有且只 有一个会话,也就是只有一个 s=。
第四个,t=(time the session is active,必选)。例子:t=<start time> <stop time>,该例子描述了会话的开始时间和竣事时间。其中, <start time> 和<stop time> 为 NTP 时间,单位是秒;当<start time>和 <stop time>均为零时,表示持久会话。
4.3.2.2、媒体描述
从上面的例子中,你可以清楚地看到在这段 SDP 片断里包括会话信息与媒体信息。在媒体信息中又包括了音频流信息和视频流信息。
在音频流和视频流信息中,通过 rtpmap 属性对它们做了进一步的说明。如音频流支持 OPUS 和 ISAC 编码,OPUS 编码的采样率是 48000 ,双声道,而 ISAC 编码的采样率可以是 16000 或 32000 , 它们都是单声道。
视频流支持 VP8,采样率是 90000 (实质是指时钟信息) 。
4.3.3、 WebRTC 中的 SDP
WebRTC 对标准 SDP 规范做了一些调整,更详细的信息可以看这里,它将 SDP 按功能分成几大块:
- Session Metadata,会话元数据
- Network Description,网络描述
- Stream Description,流描述
- Security Descriptions,安全描述
- Qos Grouping Descriptions, 服务质量描述
下面这张图清晰地表达了它们之间的关系:
通过上图我们可以看出,WebRTC 按功能将 SDP 划分成了五部门,即会话元数据、网络描述、流描述、安全 描述以及服务质量描述。WebRTC SDP 中的会话元数据(Session Metadata)其实就是 SDP 标准规范中的 会话层描述;流描述、网络描述与 SDP 标准规范中的媒体层描述是一致的;而安全描述与服务质量描述都是新增的一些属性描述。下图我们来看一个具体的例子:
上面的 SDP 片断是摘取的 WebRTC SDP 中的安全描述与服务质量描述,这两块描述在标准 SDP 规范中没有明确界说,它更多属于 WebRTC 业务的范畴。
其中,安全描述起到两方面的作用,一方面是举行网络连通性检测时,对用户身份举行认证;另一方面是收发数据时,对用户身份的认证,以免受到对方的攻击。从中可以看出 WebRTC 对安全有多器重了服务质量描述指明启动哪些功能以保证音视频的质量,如启动带宽评估,当用户发送数据量太大凌驾评估的带宽时,要及时减少数据包的发送;启动防拥塞功能,当猜测到要发生拥塞时,通过低沉流量的方式防止拥塞的发生等等,这些都属于服务质量描述的范畴。
为便于你更好地明确和使用 SDP,接下来我再分享一个真实的例子。
下面这段 SDP 是我从一个真实的 1 对 1 场景中截取出来的 WebRTC SDP 的片断。并对 SDP 上做了详细的解释,通过上面知识的学习,现在你应该也可以看懂这段 SDP 的内容了。
从上面这段 SDP 中你应该可以总结出:SDP 是由一个会话层和多个媒体层组成的;而对于每个媒体层,WebRTC 又将其细划为四部门,即媒体流、网络描述、安全描述和服务质量描述。而且在上面的例子中有两个媒体层——音频媒体层和视频媒体层,而对于每个媒体层,也都有对应的媒体流描述、网络描述、安全描述及服务质量描述
补充引申
RFC3551(RTP/AVP)在RFC3550的底子上针对RTP档次举行补充形成RTP/APVP档次,被用在具有最小会话控制的音视频集会中,是其它扩展档次的底子。该档次在没有参数协商和成员控制的会话中非常有用。该档次也为音视频界说一系列编码和负载格式。对于具体的流媒体负载格式,IETF也界说一系列协议详细描述,如VP8视频负载格式和H264视频负载格式,等等
4.4、Candidate
在讲解 WebRTC 创建毗连的过程之前,你有必要先相识一个基本概念,即 ICE Candidate (ICE 候选者)。
它表示 WebRTC 与远端通讯时使用的协议、IP 地址和端口,一般由以下字段组成:
- 本地 IP 地址
- 本地端口号
- 候选者类型,包括 host、srflx 和 relay
- 优先级
- 传输协议
- 访问服务的用户名
- …
如果用一个结构表示,那么它就如下面所示的样子:
其中,候选者类型中的:
- host 表示本机候选者
- srflx 表示内网主机映射的外网的地址和端口
- relay 表示中继候选者。
当 WebRTC 通讯双方彼此要举行毗连时,每一端都会提供许多候选者,比如你的主机有两块网卡,那么每块网卡的不同端口都是一个候选者。
WebRTC 会按照上面描述的格式对候选者举行排序,然后按优先级从高到低的次序举行连通性测试,当连通性测试成功后,通讯的双方就创建起了毗连。
在众多候选者中,host 类型的候选者优先级是最高的。在 WebRTC 中,起首对 host 类型的候选者举行连通性检测,如果它们之间可以互通,则直接创建毗连。其实,host 类型之间的连通性检测就是内网之间的连通性检测。WebRTC 就是通过这种方式巧妙地解决了大家以为很困难的问题。
同样的原理,如果 host 类型候选者之间无法创建毗连,那么 WebRTC 则会实验次优先级的候选者,即 srflx类型的候选者。也就是实验让通讯双方直接通过 P2P 举行毗连,如果毗连成功就使用 P2P 传输数据;如果失败,就最后实验使用 relay 方式创建毗连。
4.4.1、收集 Candidate
相识了什么是 Candidate 之后,接下来,我们再来看一下端对端的毗连是如何创建的吧。
实际上,端对端的创建更重要的工作是Candidate 的收集。WebRTC 将 Candidate 分为三种类型:
- host 类型,即本机内网的 IP 和端口;
- srflx 类型, 即本机 NAT 映射后的外网的 IP 和端口;
- relay 类型,即中继服务器的 IP 和端口。
其中,host 类型优先级最高,srflx 次之,relay 最低(前面我们已经说明过了)。在以上三种 Candidate 类型中,host 类型的 Candidate 是最容易收集的,因为它们都是本机的 IP 地址和端口。对于 host 类型的 Candidate 这里就不做过多讲解了,下面我们重要讲解一下 srflx 和 relay 这两种类型的 Candidate 的收集。
4.4.1.1、STUN 协议
srflx 类型的 Candidate 实际上就是内网地址和端口经NAT映射后的外网地址和端口。如下图所示:
你应该知道,如果主机没有公网地址,是无论如何都无法访问公网上的资源的。比方你要通过百度搜刮一些信息,如
果你的主机没有公网地址的话,百度搜刮到的结果怎么传给你呢?
而一般情况下,主机都只有内网 IP 和端口,那它是如何访问外网资源的呢?实际上,在内网的网关上都有 NAT (Net Address Transport) 功能,NAT 的作用就是举行表里网的地址转换。这样当你要访问公网上的资源时,NAT 起首会将该主机的内网地址转换成外网地址,然后才会将请求发送给要访问的服务器;服务器处理好后将结果返回给主机的公网地址和端口,再通过 NAT 最终中转给内网的主机。
知道了上面的原理,你要想让内网主机获得它的外网 IP 地址也就好办了,只需要在公网上架设一台服务器,并向这台服务器发个请求说: “Hi!伙计,你看我是谁?”对方回: “你不是那 xxxx 吗?”这样你就可以知道本身的公网 IP了,是不是很简单?
实际上,上面的描述已经被界说成了一套规范,即 RFC5389 ,也就是 STUN 协议,我们只要遵守这个协议就可以拿到本身的公网 IP 了。
这里我们举个例子,看看通过 STUN 协议,主机是如何获取到本身的外网 IP 地址和端口的。
- 起首在外网搭建一个 STUN 服务器,现在比力流行的 STUN 服务器是coturn,你可以到 GitHub 上本身下载源码编译安装。
- 当 STUN 服务器安装好后,从内网主机发送一个 binding request 的 STUN 消息到 STUN 服务器。
- STUN 服务器收到该请求后,会将请求的 IP 地址和端口添补到 binding response 消息中,然后顺原路将该消息返回给内网主机。此时,收到 binding response 消息的内网主机就可以剖析 binding response 消息了,并可以从中得到本身的外网 IP 和端口。
4.4.1.2、TURN 协议
这里需要说明一点,relay 服务是通过 TURN 协议实现的。以是我们常常说的 relay 服务器或 TURN 服务器它们是同一个意思,都是指中继服务器。
咱们言归正转,知道了内网主机如何通过 STUN 协议获取到 srflx 类型的候选者后,那么中继类型候选者,即 relay
型的 Candidate 又是如何获取的呢?下面我们就来看一下。
起首你要清楚,relay 型候选者的优先级与其他类型相比是最低的,但在其他候选者都无法连通的情况下,relay 候选者就成了最好的选择。因为它的连通率是所有候选者中连通率最高的。
其实,relay 型候选者的获取也是通过 STUN 协议完成的,只不过它使用的 STUN 消息类型与获取 srflx 型候选者的STUN 消息的类型不一样而已。
RFC5766 的 TURN 协议描述了如何获取 relay 服务器(即 TURN 服务器)的 Candidate 过程。其中最重要的是Allocation 指令。通过向 TURN 服务器发送 Allocation 指令,relay 服务就会在服务器端分配一个新的 relay 端口,用于中转 UDP 数据报。
不过这里我只是简要描述了下,如果你对这块感爱好的话,可以直接检察 RFC5766 以相识更多的细节。
4.4.2、NAT 打洞 /P2P 穿越
当收集到 Candidate 后,WebRTC 就开始按优先级次序举行连通性检测了。它起首会判定两台主机是否处于同一个局域网内,如果双方确实是在同一局域网内,那么就直接在它们之间创建一条毗连。
但如果两台主机不在同一个内网,WebRTC 将实验NAT 打洞,即 P2P 穿越。在 WebRTC 中,NAT 打洞是极其复杂的过程,它起首需要对 NAT 类型做判定,检测出其类型后,才能判定出是否可以打洞成功,只有存在打洞成功的大概性时才会真正实验打洞。
WebRTC 将 NAT 分类为 4 种类型,分别是:
- 完全锥型 NAT
- IP 限制型 NAT
- 端口限制型 NAT
- 对称型 NAT
而每种不同类型的 NAT 的详细介绍我们将在下一篇关于 NAT 穿越原理一文中举行讲解,现在你只要知道 NAT 分这 4 种类型就好了。另外,需要记着的是,对称型 NAT 与对称型 NAT 是无法举行 P2P 穿越的;而对称型 NAT 与端口限制型 NAT 也是无法举行 P2P 毗连的。
4.4.3、ICE
相识了上面的知识后,你再来看 ICE 就比力简单了。其实 ICE 就是上面所讲的获取各种类型 Candidate 的过程,也就是:
- 在本机收集所有的 host 类型的 Candidate
- 通过 STUN 协议收集 srflx 类型的 Candidate
- 通过 TURN 协议收集 relay 类型的 Candidate
在整个过程中,WebRTC 使用优先级的方法去创建毗连,即局域网内的优先级最高,其次是 NAT 穿越,再次是通过中继服务器举行中转,这样就巧妙地实现了“既要高效传输,又能保证连通率”这个目标。
5、 实现音视频一对一通话
5.1、一对一通话原理
对于我们WebRTC应用开发人员而言,重要是关注RTCPeerConnection类,我们以( 1 )信令计划;( 2 )媒体协商;( 3 )参加Stream/Track;( 4 )网络协商 四大块继承讲解通话原理
5.2、信令协议计划
采取json封装格式
- join 参加房间
- respjoin 当join房间后发现房间已经存在另一个人时则返回另一个人的uid;如果只有本身则不返回
- leave 离开房间,服务器收到leave信令则检查同一房间是否有其他人,如果有其他人则关照他有人离开
- newpeer 服务器关照客户端有新人参加,收到newpeer则发起毗连请求
- peerleave 服务器关照客户端有人离开
- offer 转发offer sdp
- answer 转发answer sdp
- candidate 转发candidate sdp
5.3、媒体协商
起首,呼唤方创建 Offer 类型的 SDP 消息。创建完成后,调用 setLocalDescriptoin 方法将该 Offer 保存到本地 Local 域,然后通过信令将 Offer 发送给被呼唤方。
被呼唤方收到 Offer 类型的 SDP 消息后,调用 setRemoteDescription 方法将 Offer 保存到它的 Remote 域。作为应答,被呼唤方要创建 Answer 类型的 SDP 消息,Answer 消息创建成功后,再调用 setLocalDescription方法将 Answer 类型的 SDP 消息保存到本地的 Local 域。最后,被呼唤方将 Answer 消息通过信令发送给呼唤方。至此,被呼唤方的工作就完部完成了。
接下来是呼唤方的收尾工作,呼唤方收到 Answer 类型的消息后,调用 RTCPeerConnecton 对象的setRemoteDescription 方法,将 Answer 保存到它的 Remote 域。
至此,整个媒体协商过程处理完毕。
当通讯双方拿到彼此的 SDP 信息后,就可以举行媒体协商了。媒体协商的具体过程是在 WebRTC 内部实现的,我们就不去细讲了。你只需要记着本地的 SDP 和远端的 SDP 都设置好后,协商就算成功了。
createOffer 创建Offer
表现远端媒体流
5.4、RTCPeerConnection补充
5.5、实现WebRTC音视频通话
这篇博客已经完成了,大家可以参考一下 websocket 局域网 webrtc 一对一 多对多 视频通话 的示例
上图的下令是
- # sar 命令在 sysstat 包下
- yum install sysstat -y
- sar -n DEV 1
复制代码 5.6、关于只能使用 localhots或者127.0.0.1问题
1、直接参考 关于使用通过ip访问网站无法使用多媒体,MediaDevices.getUserMedia()为undefined的解决方案–(亲测可用)。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |