「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
什么是WebRTC
WebRTC 即 Web browsers with Real-Time Communications 是一个由Google发起的实时通讯解决方案,其中包含视频音频采集,编解码,数据传输,音视频展示等功能,我们可以通过技术快速地构建出一个音视频通讯应用。 虽然其名为WebRTC,但是实际上它不光支持Web之间的音视频通讯,还支持Android以及IOS端,此外由于该项目是开源的,我们也可以通过编译C++代码,从而达到全平台的互通。
Web API层:面向开发者提供标准API(javascirpt),前端应用通过这一层接入使用WebRTC能力。
C++ API层:面向浏览器开发者,使浏览器制造商能够轻松地实现Web API方案。
音频引擎(VoiceEngine) :音频引擎是一系列音频多媒体处理的框架,包括从视频采集卡到网络传输端等整个解决方案。
- iSAC/iLBC/Opus等编解码。
- NetEQ语音信号处理。
- 回声消除和降噪。
视频引擎(VideoEngine) :是一系列视频处理的整体框架,从摄像头采集视频、视频信息网络传输到视频显示整个完整过程的解决方案。
- VP8编解码。
- jitter buffer:动态抖动缓冲。
- Image enhancements:图像增益。
传输(Transport) :传输 / 会话层,会话协商 + NAT穿透组件。
- RTP 实时协议。
- 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服务器发送请求获得自己的公网地址信息,以及是否能够被(穿过路由器)访问。参考地址
TURN
一些路由器使用一种“对称型NAT”的NAT模型。这意味着路由器只接受和对端先前建立的连接(就是下一次请求建立新的连接映射)。
NAT的中继穿越方式Traversal Using Relays around NAT (TURN) 通过TURN服务器中继所有数据的方式来绕过“对称型NAT”。你需要在TURN服务器上创建一个连接,然后告诉所有对端设备发包到服务器上,TURN服务器再把包转发给你。很显然这种方式是开销很大的,所以只有在没得选择的情况下采用。
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。它主要的作用就是确保几个媒体轨道是同步播放。
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连接大致的原理及步骤如下:
- 发起收集ICE Canidate任务。
- 本机能收集host类型(内网IP端口)的candidate。
- 通过STUN服务器收集srflx类型(NAT映射到外网的IP端口)的candiate。
- 通过TUN服务器收集relay类型的(中继服务器的 IP 和端口)的candidate。
- 开始尝试NAT穿越,按照host类型、srflx类型、relay类型的优先级去连接。
以上,WebRTC便能找到一条传输质量最优的连接道路。当然实际情况并不是这么简单,整个过程包含着更复杂的底层细节。
总结
WebRTC的优点:
- 方便。对于用户来说,在WebRTC出现之前想要进行实时通信就需要安装插件和客户端,但是对于很多用户来说,插件的下载、软件的安装和更新这些操作是复杂而且容易出现问题的,现在WebRTC技术内置于浏览器中,用户不需要使用任何插件或者软件就能通过浏览器来实现实时通信。对于开发者来说,在Google将WebRTC开源之前,浏览器之间实现通信的技术是掌握在大企业手中,这项技术的开发是一个很困难的任务,现在开发者使用简单的HTML标签和JavaScript API就能够实现Web音/视频通信的功能。
- 免费。虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的code,但是Google对于这些技术不收取任何费用。
- 强大的打洞能力。WebRTC技术包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透技术,并支持代理。
WebRTC的缺点:
- 缺乏服务器方案的设计和部署。
- 传输质量难以保证。WebRTC的传输设计基于P2P,难以保障传输质量,优化手段也有限,只能做一些端到端的优化,难以应对复杂的互联网环境。比如对跨地区、跨运营商、低带宽、高丢包等场景下的传输质量基本是靠天吃饭,而这恰恰是国内互联网应用的典型场景。
- WebRTC比较适合一对一的单聊,虽然功能上可以扩展实现群聊,但是没有针对群聊,特别是超大群聊进行任何优化。
- 设备端适配,如回声、录音失败等问题层出不穷。这一点在安卓设备上尤为突出。由于安卓设备厂商众多,每个厂商都会在标准的安卓框架上进行定制化,导致很多可用性问题(访问麦克风失败)和质量问题(如回声、啸叫)。
- 对Native开发支持不够。WebRTC顾名思义,主要面向Web应用,虽然也可以用于Native开发,但是由于涉及到的领域知识(音视频采集、处理、编解码、实时传输等)较多,整个框架设计比较复杂,API粒度也比较细,导致连工程项目的编译都不是一件容易的事。
- 一开始各个浏览器厂商,都会实现自己的一套API,诸如
webkitRTCPeerConnection
和mozRTCPeerConnection
这样的差异,对于前端开发者当然是苦不堪言。
而adapter.js正是为了消除这种差异,帮助我们可以按照规范来写我们的WebRTC代码。可以参考 github.com/webrtcHacks…
可见,WebRTC是一个优缺点兼有的技术,在拥有诱人的优点的同时,其缺点也十分的严重。在进行WebRTC的开发之前,请根据自身的情况来决定是自主开发还是使用第三方SDK。
做的不错的视频服务商
声网 : www.agora.io/cn/