WebRTC是个啥

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

什么是WebRTC

WebRTC 即 Web browsers with Real-Time Communications 是一个由Google发起的实时通讯解决方案,其中包含视频音频采集,编解码,数据传输,音视频展示等功能,我们可以通过技术快速地构建出一个音视频通讯应用。 虽然其名为WebRTC,但是实际上它不光支持Web之间的音视频通讯,还支持Android以及IOS端,此外由于该项目是开源的,我们也可以通过编译C++代码,从而达到全平台的互通。

download_image.png Web API层:面向开发者提供标准API(javascirpt),前端应用通过这一层接入使用WebRTC能力。

C++ API层:面向浏览器开发者,使浏览器制造商能够轻松地实现Web API方案。

音频引擎(VoiceEngine) :音频引擎是一系列音频多媒体处理的框架,包括从视频采集卡到网络传输端等整个解决方案。

  1. iSAC/iLBC/Opus等编解码。
  2. NetEQ语音信号处理。
  3. 回声消除和降噪。

视频引擎(VideoEngine) :是一系列视频处理的整体框架,从摄像头采集视频、视频信息网络传输到视频显示整个完整过程的解决方案。

  1. VP8编解码。
  2. jitter buffer:动态抖动缓冲。
  3. Image enhancements:图像增益。

传输(Transport) :传输 / 会话层,会话协商 + NAT穿透组件。

  1. RTP 实时协议。
  2. P2P传输 STUN+TRUN+ICE实现的网络穿越。

硬件模块:音视频的硬件捕获以及NetWork IO相关。

WebRTC 传输基本点

NAT

网络地址转换协议Network Address Translation (NAT) 用来给你的(私网)设备映射一个公网的IP地址的协议。一般情况下,路由器的WAN口有一个公网IP,所有连接这个路由器LAN口的设备会分配一个私有网段的IP地址(例如192.168.1.3)。私网设备的IP被映射成路由器的公网IP和唯一的端口,通过这种方式不需要为每一个私网设备分配不同的公网IP,但是依然能被外网设备发现。

一些路由器严格地限定了部分私网设备的对外连接。这种情况下,即使STUN服务器识别了该私网设备的公网IP和端口的映射,依然无法和这个私网设备建立连接。这种情况下就需要转向TURN协议。

NAT 产生的原因

  • ipv4 地址不够
  • 出于网络安全的原因

NAT 种类

  • Full Cone NAT:

完全锥形NAT,所有从同一内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号,并且任何一个外网主机都可以通过这个映射的外网IP和端口号向这台内网主机发送包。

  • Restricted Cone NAT:

限制锥形NAT,它也是所有从同一个内网IP和端口号发送的过来的请求都会被映射成同一个外网IP和端口号。与完全锥形不同的是,外网主机只能够向先前已经向它发送过数据包的内网主机发送包。

  • 端口限制锥形NAT:

端口限制锥形NAT,与限制锥形NAT很相似,只不过它包括端口号。也就是说,一台IP地址X和端口P的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个IP地址X和端口号P发送过数据包。

  • Symmertic NAT:

对称NAT,所有从同一个内网IP和端口号发送到一个特定目的IP和端口号的请求,都会被映射到同一个IP和端口号,如果同一台主机使用相同的源地址和端口号发送包,但是发往不同的目的地,NAT将会使用不同的映射。此外,只有收到的数据的外网主机才可以反过来向内网主机发送包。

STUN

NAT的会话穿越功能Session Traversal Utilities for NAT (STUN) (缩略语的最后一个字母是NAT的首字母)是一个允许位于NAT后的客户端找出自己的公网地址,判断出路由器阻止直连的限制方法的协议。

客户端通过给公网的STUN服务器发送请求获得自己的公网地址信息,以及是否能够被(穿过路由器)访问。参考地址

202f43cc-8262-436d-9d7d-86981a1df8a3.png

TURN

一些路由器使用一种“对称型NAT”的NAT模型。这意味着路由器只接受和对端先前建立的连接(就是下一次请求建立新的连接映射)。

NAT的中继穿越方式Traversal Using Relays around NAT (TURN) 通过TURN服务器中继所有数据的方式来绕过“对称型NAT”。你需要在TURN服务器上创建一个连接,然后告诉所有对端设备发包到服务器上,TURN服务器再把包转发给你。很显然这种方式是开销很大的,所以只有在没得选择的情况下采用。

image.png

ICE架构

交互式连接设施Interactive Connectivity Establishment (ICE) 是一个允许你的浏览器和对端浏览器建立连接的协议框架。在实际的网络当中,有很多原因能导致简单的从A端到B端直连不能如愿完成。这需要绕过阻止建立连接的防火墙,给你的设备分配一个唯一可见的地址(通常情况下我们的大部分设备没有一个固定的公网地址),如果路由器不允许主机直连,还得通过一台服务器转发数据。ICE通过使用上面多种技术完成上述工作。

SDP

会话描述协议Session Description Protocol (SDP) 是一个描述多媒体连接内容的协议,例如分辨率,格式,编码,加密算法等。所以在数据传输时两端都能够理解彼此的数据。本质上,这些描述内容的元数据并不是媒体流本身。

从技术上讲,SDP并不是一个真正的协议,而是一种数据格式,用于描述在设备之间共享媒体的连接。

记录SDP远远超出了本文档的范围。参考链接

WebRTC重要的类和API

Network Stream API

MediaStream(媒体流)和 MediaStreamTrack(媒体轨道)

这个类并不完全属于WebRTC的范畴,但是在本地媒体流获取,及远端流传到vedio标签播放都与WebRTC相关。MS 由两部分构成:MediaStreamTrack 和 MediaStream。

  • MediaStreamTrack 媒体轨,代表一种单类型数据流,可以是音频轨或者视频轨。
  • MediaStream 是一个完整的音视频流。它可以包含 >=0 个 MediaStreamTrack。它主要的作用就是确保几个媒体轨道是同步播放。

image.png

Constraints 媒体约束

关于MediaStream,还有一个重要的概念叫做: Constraints(约束)。它是用来规范当前采集的数据是否符合需要,并可以通过参数来设置。

//基本
const constraint1 = {
  audio: true, // 是否捕获音频
  video: true, // 是否捕获视频
};

// 详细
const constraint2 = {
  audio: {
    sampleSize: 8,
    echoCancellation: true, //回声消除
  },
  video: {
    // 视频相关设置
    width: {
      min: "381", // 当前视频的最小宽度
      max: "640",
    },
    height: {
      min: "200", // 最小高度
      max: "480",
    },
    frameRate: {
      min: "28", // 最小帧率
      max: "10",
    },
  },
};

复制代码

获取设备本地音视频

var video = document.querySelector('video');
navigator.getUserMedia({
 audio : true,
 video : true
 }, function (stream) {
 //获取本地媒体流
 video.src = window.URL.creatObjectURL(stream);
 }, function (error) {
 console.log(error);
});
复制代码

getUserMedia的第一个参数就是Constraint,第二个参数传入回调函数拿到视频流。当然你可以使用如下Promise的写法:

navigator.mediaDevices.getUserMedia(constraints).

then(successCallback).catch(errorCallback);
复制代码

RTCPeerConnection

RTCPeerConnection,用于实现peer跟peer之间RTC连接,继而无需服务器就能传输音视频数据流的连接通道。(直播的实际生产中还是需要服务器)

这么说过于抽象,为了帮助理解,可以用一个不太恰当但有助于理解的比喻:就是一个高级且功能强大的用于传输音视频数据而建立类似Websocket链接通道,只不过它可以用来建立浏览器通道。

之所以说是高级且强大,是因为它作为WebRTC web层核心API,让你无须关注数据传输延迟抖动、音视频编解码,音画同步等问题。直接使用PeerConnection 就能用上这些浏览器提供的底层封装好的能力。

function init( createOffer, partnerName ) {

    pc[partnerName] = new RTCPeerConnection( h.getIceServer() );

 }
复制代码

h.getIceServer()

getIceServer() {

    return {

        iceServers: [

            {

                urls: ["stun:eu-turn4.xirsys.com"]

            },

            {

                username: "ml0jh0qMKZKd9P_9C0UIBY2G0nSQMCFBUXGlk6IXDJf8G2uiCymg9WwbEJTMwVeiAAAAAF2__hNSaW5vbGVl",

                credential: "4dd454a6-feee-11e9-b185-6adcafebbb45",

                urls: [

                    "turn:eu-turn4.xirsys.com:80?transport=udp",

                    "turn:eu-turn4.xirsys.com:3478?transport=tcp"

                ]

            }

        ]

    };

},
复制代码

Peer-to-peer Data API

RTCDataChannel可以建立浏览器之间的点对点通讯。常用的通讯方式有websocket, ajax和等方式。websocket虽然是双向通讯,但是无论是websocket还是ajax都是客户端和服务器之间的通讯,你必须配置服务器才可以进行通讯。

而由于RTCDATAChannel借助RTCPeerConnection无需经过服务器,就可以提供点对点之间的通讯,无需/(避免)服务器了这个中间件。但是一般不用,下面会说明原因

var pc = new RTCPeerConnection();

var dc = pc.createDataChannel("my channel");

dc.onmessage = function (event) {

 console.log("received: " + event.data);

};

dc.onopen = function () {

 console.log("datachannel open");

};

dc.onclose = function () {

 console.log("datachannel close");

};
复制代码

信令通道 Signaling Channel

我们说WebRTC的RTCPeerConnection是可以做到浏览器间(无服务)的通信。

但这里有个问题,当两个浏览器不通过服务器建立PeerConnection时,它们怎么知道彼此的存在呢?进一步讲,它们该怎么知道对方的网络连接位置(IP/端口等)呢?支持何种编解码器?甚至于什么时候开始媒体流传输、又该什么时候结束呢?

因此在建立WebRTC的RTCPeerConnection前,必须建立️另一条通道来交这些协商信息,这些需要即时协商的信息也被称为信令,这条通道成为信令通道(Signaling Channel)

两个客户端浏览器交换的信令具有以下功能:

  • 协商媒体功能和设置 (交换SDP对象中的信息:媒体类型、编解码器、带宽等元数据)
  • 标识和验证会话参与者的身份
  • 控制媒体会话、指示进度、更改会话、终止会话等

其中主要涉及offer/answer sdp会话描述协议 ,以及ICE candidate的交换。这个过程就是WebRTC协商

这里需要注意的一点:WebRTC标准本身没有规定信令交换的通讯方式,信令服务根据自身的情况实现。

在Web浏览器中,一般会使用websocket通道来做信令通道,比如可以基于socket.io来搭建信令服务。当然业界也有很多开源且稳定成熟的信令服务方案可供选择。

WebRTC建立连接的关键-ICE连接

在交换并设置SDP(offer/asnwer)后,webrtc就开始真正的连接来传输音视频数据。这个建立连接的过程相当复杂,原因是webrtc既要保证高效的传输性,又要保证稳定的连通性

由于浏览器客户端之间所处的位置往往是相当复杂的,可能处于同一个内网段内,也可能处于两个不同的位置,所处的NAT网关也可能很复杂。因此需要一种机制找到一条传输质量最优的道路,而WebRTC正具备这种能力。

首先简单了解以下三个概念。

  • ICE Canidate(ICE 候选者):包含远端通信时使用的协议、IP 地址和端口、候选者类型等信息。
  • STUN/TURN:STUN实现P2P型连接,TRUN实现中继型连接。两者实现均有标准协议。(参考下图)
  • NAT穿越:NAT即网络地址转换,由于客户端并不能分配到公网IP,需要内网IP与公网IP端口做映射才能与外网通信。而NAT穿越就是位于层层Nat网关背后的客户端之间发现对方并建立连接。

ICE连接大致的原理及步骤如下:

  1. 发起收集ICE Canidate任务。
  2. 本机能收集host类型(内网IP端口)的candidate。
  3. 通过STUN服务器收集srflx类型(NAT映射到外网的IP端口)的candiate。
  4. 通过TUN服务器收集relay类型的(中继服务器的 IP 和端口)的candidate。
  5. 开始尝试NAT穿越,按照host类型、srflx类型、relay类型的优先级去连接。

以上,WebRTC便能找到一条传输质量最优的连接道路。当然实际情况并不是这么简单,整个过程包含着更复杂的底层细节。

总结

WebRTC的优点:

  1. 方便。对于用户来说,在WebRTC出现之前想要进行实时通信就需要安装插件和客户端,但是对于很多用户来说,插件的下载、软件的安装和更新这些操作是复杂而且容易出现问题的,现在WebRTC技术内置于浏览器中,用户不需要使用任何插件或者软件就能通过浏览器来实现实时通信。对于开发者来说,在Google将WebRTC开源之前,浏览器之间实现通信的技术是掌握在大企业手中,这项技术的开发是一个很困难的任务,现在开发者使用简单的HTML标签和JavaScript API就能够实现Web音/视频通信的功能。
  2. 免费。虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的code,但是Google对于这些技术不收取任何费用。
  3. 强大的打洞能力。WebRTC技术包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透技术,并支持代理。

WebRTC的缺点:

  1. 缺乏服务器方案的设计和部署。
  2. 传输质量难以保证。WebRTC的传输设计基于P2P,难以保障传输质量,优化手段也有限,只能做一些端到端的优化,难以应对复杂的互联网环境。比如对跨地区、跨运营商、低带宽、高丢包等场景下的传输质量基本是靠天吃饭,而这恰恰是国内互联网应用的典型场景。
  3. WebRTC比较适合一对一的单聊,虽然功能上可以扩展实现群聊,但是没有针对群聊,特别是超大群聊进行任何优化。
  4. 设备端适配,如回声、录音失败等问题层出不穷。这一点在安卓设备上尤为突出。由于安卓设备厂商众多,每个厂商都会在标准的安卓框架上进行定制化,导致很多可用性问题(访问麦克风失败)和质量问题(如回声、啸叫)。
  5. 对Native开发支持不够。WebRTC顾名思义,主要面向Web应用,虽然也可以用于Native开发,但是由于涉及到的领域知识(音视频采集、处理、编解码、实时传输等)较多,整个框架设计比较复杂,API粒度也比较细,导致连工程项目的编译都不是一件容易的事。
  6. 一开始各个浏览器厂商,都会实现自己的一套API,诸如webkitRTCPeerConnectionmozRTCPeerConnection 这样的差异,对于前端开发者当然是苦不堪言。

而adapter.js正是为了消除这种差异,帮助我们可以按照规范来写我们的WebRTC代码。可以参考 github.com/webrtcHacks…

可见,WebRTC是一个优缺点兼有的技术,在拥有诱人的优点的同时,其缺点也十分的严重。在进行WebRTC的开发之前,请根据自身的情况来决定是自主开发还是使用第三方SDK。

做的不错的视频服务商

声网 : www.agora.io/cn/

www.showmebug.com/pads/MIFBHC

おすすめ

転載: juejin.im/post/7063111521408122911