乐趣区

关于音视频:实时音视频入门学习开源工程WebRTC的技术原理和使用浅析

本文由 ELab 技术团队分享,原题“浅谈 WebRTC 技术原理与利用”,有订正和改变。

1、根本介绍

WebRTC(全称 Web Real-Time Communication),即网页即时通信。是一个反对网页浏览器进行实时语音对话或视频对话的技术计划。从前端技术开发的视角来看,是一组可调用的 API 规范。

在 WebRTC 公布之前,开发实时音视频交互利用的老本是十分低廉,须要思考的技术问题很多,如音视频的编解码问题,数据传输问题,延时、丢包、抖动、回音的解决和打消等,如果要兼容浏览器端的实时音视频通信,还须要额定装置插件。

2010 年 5 月:Google 以 6820 万美元收买 VoIP 软件开发商 Global IP Solutions 的 GIPS 引擎,并改为名为“WebRTC”(见《了不起的 WebRTC:生态日趋完善,或将实时音视频技术白菜化》)。旨在建设一个互联网浏览器间的实时通信的平台,让 WebRTC 技术成为 H5 规范之一。

2012 年 1 月:谷歌曾经把这款软件集成到 Chrome 浏览器中,Opera 初步集成 WebRTC。

2013 年 6 月:Mozilla Firefox[5]公布 22.0 版本正式集成及反对 WebRTC。

2017 年 11 月:W3C WebRTC 1.0 草案正式定稿。

2021 年 1 月:WebRTC 被 W3C 和 IETF 公布为正式规范(见《WebRTC 1.0: Real-Time Communication Between Browsers》)。

(本文已同步公布于:http://www.52im.net/thread-38…)

2、重要意义

WebRTC 的呈现、倒退和被业内规范组织(如 W3C)等广泛认可,对于当下和将来大前端技术倒退具备重要的意义。

升高在 web 端的音视频交互开发门槛:

1)以往的音视频交互开发对于 Web 开发者而言具备肯定技术门槛;
2)当初借助于 WebRTC,Web 开发者通过调用 JS 接口,可疾速的实现音视频交互利用。

防止依赖、插件造成的次生问题:

1)以往的音视频交互利用构建依赖于各种插件、软件和服务器等;
2)当初借助于支流浏览器即可造成端到端的音视频交互。

统一化和标准化对传统音视频交互环境差异性的躲避:

1)以往音视频交互须要面对不同的 NAT、防火墙对媒体 P2P 的建设带来了很大的挑战;
2)当初 WebRTC 中有 P2P 打洞的开源我的项目 libjingle , 反对 STUN,TURN 等协定。

更高效优化的算法、技术对于音视频交互性能的晋升:

1)WebRTC 通过 NACK、FEC 技术,防止了通过服务端路由直达,缩小了提早和带宽耗费;
2)还有 TCC + SVC + PACER + JitterBuffer 等技术对于音视频流畅性进行了优化。

3、技术特色

WebRTC 内容丰盛,次要的技术特色蕴含以下几点。

1)实时通信:

WebRTC 是一项实时通信技术,容许网络应用或者站点,在不借助两头媒介的状况下,建设浏览器之间点对点(Peer-to-Peer)的连贯,实现视频流和(或)音频流或者其余任意数据的传输。

2)无依赖 / 插件:

WebRTC 蕴含的这些规范使用户在无需装置任何插件或者第三方的软件的状况下,创立点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

3)协定栈 泛滥:

WebRTC 并不是繁多的协定,蕴含了媒体、加密、传输层等在内的多个协定规范以及一套基于 JavaScript 的 API,它包含了音视频的采集、编解码、网络传输、显示等性能。通过简略易用的 JavaScript API,在不装置任何插件的状况下,让浏览器领有了 P2P 音视频和数据分享的能力。

WebRTC 依赖泛滥协定栈图:

同时 WebRTC 并不是一个孤立的协定,它领有灵便的信令,能够便捷的对接现有的 SIP 和电话网络的零碎。

4、兼容笼罩

目前大部分支流浏览器都失常兼容 WebRTC:

▲ 上图援用自《WebRTC 实时音视频技术的整体架构介绍》

更具体的浏览器及版本兼容状况,能够看看下图:

▲ 上图援用自《https://caniuse.com/rtcpeerco…》

支流浏览器都反对 WebRTC 规范 API,因而也让浏览器之间无插件化的音视频互通成为可能,大大降低了音视频开发的门槛,开发者只须要调用 WebRTC API 即可疾速构建出音视频利用。

5、技术框架

如下图所示:的技术框架形容了 WebRTC 的核心内容和面向不同开发者的 API 设计。

WebRTC 技术框架图:

▲ 上图援用自《零根底入门:基于开源 WebRTC,从 0 到 1 实现实时音视频聊天性能》

从图中可看到,WebRTC 次要面向三类开发者的 API 设计:

1)对于 Web 开发者的 API:框架蕴含了基于 JavaScript、通过 W3C 认证了的一套 API 规范,使得 web 开发者能够基于这套 API 开发基于 WebRTC 的即时通讯利用;
2)对于浏览器厂商的 API:框架同样蕴含了基于 C ++ 的底层 WebRTC 接口,对于浏览器厂商底层的接入非常敌对;
3)浏览器厂商可自定义的局部:框架中还蕴含浏览器厂商可自定义的音视频截取等扩大局部。

6、技术外围

从上节框架中能够看到,WebRTC 次要有音频、视频引擎和传输三局部组成,其中又蕴含泛滥的协定和办法等。

1)Voice Engine(音频引擎):

a、Voice Engine 蕴含 iSAC/iLBC Codec(音频编解码器,前者是针对宽带和超宽带,后者是针对窄带);
b、NetEQ for voice(解决网络抖动和语音包失落);
c、Echo Canceler(回声消除器)/ Noise Reduction(噪声克制)。

2)Video Engine(视频引擎):

a、VP8 Codec(视频图像编解码器);
b、Video jitter buffer(视频抖动缓冲器,解决视频抖动和视频信息包失落);
c、Image enhancements(图像品质加强)。

3)Transport。

7、技术原理

7.1 根本状况
WebRTC 次要的技术特色:

1)SRTP:平安的实时传输协定,用于音视频流传输;
2)Multiplexing:多路复用;
3)P2P:STUN+TURN+ICE,用于 NAT 网络和防火墙穿梭;
4)DTLS:平安传输可能还会用到 DTLS(数据报平安传输),用于加密传输和密钥协商;
5)UDP:整个 WebRTC 通信是基于 UDP 的。

限于篇幅,本文以下章节将不粗疏介绍音视频采集、编码和解决等内容,仅介绍实时通信的建设过程原理的核心内容。

7.2 公网 IP 映射:明确网络定位信息
WebRTC 是基于浏览器端到端的连贯(P2P)实现的.

因为不须要服务器直达,所以获取连贯对象的网络地址的形式,是借助于 ICE、STUN、TURN 等辅助内网穿透技术(NAT)失去对应主机的公网网络地址和端口等网络定位信息。

明确网络定位是建设端与端间接通信的根底。

NAT 穿透原理图:

STUN 服务器用于辅助内网穿透失去对应主机的公网网络地址和端口信息图:

▲ 上图援用自《WebRTC 实时音视频技术的整体架构介绍》

7.3 信令服务器:网络协商与信息替换
信令服务器的作用是基于双工通信来直达信息。

直达信息包含公网 IP 映射后的网络定位信息,比方:公网 IP、端口和媒体数据流等。

概念图:

信令服务器信息交互过程图:

7.4 会话形容协定 SDP:对立的媒体协商形式
SDP 的作用:

1)不同端 / 浏览器对于媒体流数据的编码格局各异,如 VP8、VP9 等,参加会话的各个成员的能力不对等、用户环境与配置不统一等;
2)WebRTC 通信还须要确定和替换本地和近程音频和视频媒体信息,例如分辨率和编解码器性能。替换媒体配置信息的信令通过应用会话形容协定 (SDP) 替换 Offer 和 Anwser 来进行;
3)SDP 的替换肯定是先于音视频流替换的。其内容包含会话根本信息、媒体信息形容等。
//SDP 的构造体

Session description(会话级别形容)

     v=  (protocol version)

     o=  (originator and session identifier)

     s=  (session name)

     c=* (connection information -- not required ifincluded inall media)

     One or moreTime descriptions ("t="and "r="lines; see below)

     a=* (zero or moresession attribute lines)

     Zero or moreMedia descriptions


Time description

     t=  (timethe session is active)


Media description(媒体级别形容), ifpresent

     m=  (media name and transport address)

     c=* (connection information -- optional ifincluded at session level)

     a=* (zero or moremedia attribute lines)

一个 SDP 例子如下:

v=0 // 代表版本,目前个别是v=0.

o=- 3883943731 1 IN IP4 127.0.0.1

s=

t=0 0 // 会话处于活动状态的工夫

a=group:BUNDLE audio video //:形容服务质量,传输层复用相干信息

m=audio 1 RTP/SAVPF103 104 0 8 106 105 13 126 //…

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh81

7.5 一对一连贯建设过程
以建设一对一的 Web RTC 连贯过程为例来简要解说。

一对一过程图:

简要过程图:

如上图所示,解释一下:

1)替换 SDP,获取各自媒体配置信息;
2)STUN 服务器替换网络地址和端口等网络信息;
3)Turn 直达音视频媒体流数据。

工作流程图:

如上图所示,解释一下:

1)A 和 B 单方先调用 getUserMedia 关上本地摄像头,作为本地待输入媒体流;
2)向信令服务器发送退出房间申请;
3)Peer B 接管到 Peer A 发送的 offer SDP 对象,并通过 PeerConnection 的 SetLocalDescription 办法保留 Answer SDP 对象并将它通过信令服务器发送给 Peer A;
4)在 SDP 信息的 offer/answer 流程中,Peer A 和 Peer B 曾经依据 SDP 信息创立好相应的音频 Channel 和视频 Channel,并开启 Candidate 数据的收集,Candidate 数据(本地 IP 地址、公网 IP 地址、Relay 服务端调配的地址);
5)当 Peer A 收集到 Candidate 信息后通过信令服务器发送给 Peer B。同样的过程 Peer B 对 Peer A 也会再发送一次。

7.6 多对多的建设
多对多建设点到点连贯概念图,以三个用户点对点的连贯为例:

7.7 WebRTC 的次要 JavaScrip 接口
getUserMedia():拜访数据流,例如来自用户的相机和麦克风

// 申请媒体类型

const constraints = {

video: true

audio:true

};

const video = document.querySelector(‘video’);

// 挂载流到相应 dom 展现本地媒体流

function handleSuccess(stream) {

video.srcObject = stream;

}

function handleError(error) {

console.error(‘getUserMedia error: ‘, error);

}

// 利用摄像头捕捉多媒体流

navigator.mediaDevices.getUserMedia(constraints).

then(handleSuccess).catch(handleError);

RTCPeerConnection:通过加密和带宽管理工具启用音频或视频通话

// 容许 RTC 服务器配置。

const server = {

"iceServers":

        [{"urls": "stun:stun.stunprotocol.org"}]

};

// 创立本地连接

const localPeerConnection = newRTCPeerConnection(servers);

// 收集 Candidate 数据

localPeerConnection.onicecandidate=function(event){

...

}

// 监听到媒体流接入时的操作

localPeerConnection.ontack=function(event){

...

}

RTCDataChannel:反对通用数据的点对点通信,罕用于数据点到点的传输

const pc = newRTCPeerConnection();

const 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”);

};

8、利用案例

这里以 WebRTC 的多人视频案例为实际来大抵演示一下。

8.1 设计框架
多人视频根本框架图:

8.2 要害代码
8.2.1)媒体捕捉:

获取浏览器视频权限,捕捉本地视频媒体流,在 Video 元素中附加媒体流,显示本地视频后果。代码如下。

// 摄像头兼容性解决

navigator.getUserMedia = (navigator.getUserMedia ||

           navigator.webkitGetUserMedia ||

           navigator.mozGetUserMedia ||

           navigator.msGetUserMedia);

// 获取本地音频和视频流

navigator.mediaDevices.getUserMedia({

            "audio": false,

            "video": true

}).then((stream)=> {

// 显示本人的输入流,挂到页面 Video 元素上

document.getElementById("myVido").srcObject=stream

})

捕捉本地视频媒体流的显示后果截图:

为每个新的客户端连贯创立 RTCPeerConnection 对象:

// stun 和 turn 服务器 const iceServer = {

"iceServers": [{urls:"stun:stun.l.google.com:19302"}]

};

// 为点到点的连贯创立 RTCPeerConnection

const peerRTCConn=newRTCPeerConnection(iceServer);

8.2.2)网络协商:

次要工作就是:创立对等连贯,收集 ICE 候选,期待媒体流接入时挂载到 dom。

交互式连通性建设(Interactive Connectivity Establishment — ICE)是一个容许实时对等端发现对方并且彼此连贯的框架。此技术容许对等方发现无关彼此拓扑的足够信息,从而有可能在彼此之间找到一条或多条通信门路。ICE 代理负责:收集本地 IP,端口元组候选、在同级之间执行连贯检查和发送连贯放弃流动。(对于 ICE 的介绍,见《P2P 技术之 STUN、TURN、ICE 详解》)

// 发送 ICE 候选到其余客户端 peerRTCConn.onicecandidate = function(event){

if(event.candidate) {

    // 向信令服务器转发收集到的 ICE 候选          socket.send(JSON.stringify({

        "event": "relayICECandidate",

        "data": {

            'iceCandidate': {

                'sdpMLineIndex': event.candidate.sdpMLineIndex,

                'candidate': event.candidate.candidate

            }

        },

        "fromID":signalMsg['data']['peerId']

    }));

}

}

// 有媒体流染指就挂载 dom peerRTCConn.ontrack=function(event){

let v=document.createElement("video")

v.autoplay=true

v.style="width:200px"



document.getElementById("peer").appendChild(v)

v.srcObject=event.streams[0]

}

8.1.3)媒体协商:

发动时创立 Offer。peer 利用 setLocalDescription 办法将会话信息加到 RTCPeerConnection(),并由信令服务器直达。其余 Peer 会返回相应的 Answer。SDP 过程:

// 新退出节点发动 offer if(canOffer){

peerRTCConn.createOffer(function(localDescription) {

         peerRTCConn.setLocalDescription(localDescription,

            function() {

                // 发送形容信息给信令服务器                         socket.send(JSON.stringify({

                    "event":"relaySessionDescription",

                    "data":localDescription,

                    "fromID":peerId

                }))

             },

            function() { alert("offer failed"); }

        );

    },

    function(error) {console.log("error sending offer:", error);

    }

)

}

响应时创立 Answer。会话形容包含音视频信息等内容,当发起者向响应者收回 offer 类型的形容后,响应者会返回 answer 类型的形容:

// 创立 Answer 会话

peer.createAnswer(

function(_remoteDescription) {

 peer.setLocalDescription(_remoteDescription,

    function() {

           // 发送形容信息给信令服务器                  socket.send(JSON.stringify({

                "event":"relaySessionDescription",

                "data":_remoteDescription,

                "callerID":signalMsg['fromId'],

                "fromID":signalMsg['fromId']

            }))        },

    function() { alert("answer failed"); }

);

},

function(error) {

console.log("error creating answer:", error);

});

当收到 ICE 候选共享后,会把 ICE 候选增加到近程对等点形容中:

// 对应的 RTCPeerConnection

const peer = peers[signalMsg[“fromID”]];

//ICE 候选增加到近程对等点形容

peer.addIceCandidate(newRTCIceCandidate(signalMsg[“data”].iceCandidate));

多人视频后果截图 < 本地模仿成果 >:

8.2.4)信令直达:

信令服务局部要害代码:

wss.on(‘connection’, function(ws) {

ws.on('message', function(message) {let meeageObj=JSON.parse(message)

    // 替换 ICE 候选         if (meeageObj['event'] =='relayICECandidate') {wss.clients.forEach(function (client) {console.log("send iceCandidate")

                client.send(JSON.stringify({

                    "event": "iceCandidate",

                    "data": meeageObj['data'],

                    "fromID": meeageObj['fromID']

                }));         

        });

    }

    // 替换 SDP

     if (meeageObj['event'] =='relaySessionDescription') {console.log(meeageObj["fromID"],meeageObj["data"].type)

        wss.clients.forEach(function(client) {if(client!=ws) {

                client.send(JSON.stringify({

                    "event": "sessionDescription",

                    "fromId":meeageObj["fromID"],

                    "data": meeageObj["data"],

                }));

            }

        });

    }

})

})

9、小结一下

WebRTC 的长处次要是:

1)不便:对于用户来说,在 WebRTC 呈现之前想要进行实时通信就须要装置插件和客户端,然而对于很多用户来说,插件的下载、软件的装置和更新这些操作是简单而且容易呈现问题的,当初 WebRTC 技术内置于浏览器中,用户不须要应用任何插件或者软件就能通过浏览器来实现实时通信。对于开发者来说,在 Google 将 WebRTC 开源之前,浏览器之间实现通信的技术是把握在大企业手中,这项技术的开发是一个很艰难的工作,当初开发者应用简略的 HTML 标签和 JavaScript API 就可能实现 Web 音 / 视频通信的性能。

2)收费:尽管 WebRTC 技术曾经较为成熟,其集成了最佳的音 / 视频引擎,非常先进的 codec,然而 Google 对于这些技术不收取任何费用。

3)弱小的打洞能力:WebRTC 技术蕴含了应用 STUN、ICE、TURN、RTP-over-TCP 的要害 NAT 和防火墙穿透技术,并反对代理。

WebRTC 的毛病次要是:

1)不足服务器计划的设计和部署。

2)传输品质难以保障。WebRTC 的传输设计基于 P2P,难以保障传输品质,优化伎俩也无限,只能做一些端到端的优化,难以应答简单的互联网环境。比方对跨地区、跨运营商、低带宽、高丢包等场景下的传输品质根本是靠天吃饭,而这恰好是国内互联网利用的典型场景。

3)WebRTC 比拟适宜一对一的单聊,尽管性能上能够扩大实现群聊,然而没有针对群聊,特地是超大群聊进行任何优化。

4)设施端适配,如回声、录音失败等问题层出不穷。这一点在安卓设施上尤为突出。因为安卓设施厂商泛滥,每个厂商都会在规范的安卓框架上进行定制化,导致很多可用性问题(拜访麦克风失败)和品质问题(如回声、啸叫)。

5)对 Native 开发反对不够。WebRTC 顾名思义,次要面向 Web 利用,尽管也能够用于 Native 开发,然而因为波及到的畛域常识(音视频采集、解决、编解码、实时传输等)较多,整个框架设计比较复杂,API 粒度也比拟细,导致连工程项目的编译都不是一件容易的事。

10、参考资料

[1] 开源实时音视频技术 WebRTC 的现状
[2] 简述开源实时音视频技术 WebRTC 的优缺点
[3] 访谈 WebRTC 规范之父:WebRTC 的过来、当初和将来
[4] 良心分享:WebRTC 零根底开发者教程(中文)[附件下载]
[5] WebRTC 实时音视频技术的整体架构介绍
[6] 新手入门:到底什么是 WebRTC 服务器,以及它是如何联接通话的?
[7] WebRTC 实时音视频技术根底:根本架构和协定栈
[8] 浅谈开发实时视频直播平台的技术要点
[9] 基于开源 WebRTC 开发实时音视频靠谱吗?第 3 方 SDK 有哪些?
[10] 开源实时音视频技术 WebRTC 在 Windows 下的扼要编译教程
[11] 网页端实时音视频技术 WebRTC:看起来很美,但离生产利用还有多少坑要填?
[12] 了不起的 WebRTC:生态日趋完善,或将实时音视频技术白菜化
[13] 零根底入门:基于开源 WebRTC,从 0 到 1 实现实时音视频聊天性能
[14] P2P 技术详解(一):NAT 详解——具体原理、P2P 简介
[15] P2P 技术详解(二):P2P 中的 NAT 穿梭(打洞) 计划详解(基本原理篇)

(本文已同步公布于:http://www.52im.net/thread-38…)

退出移动版