浅谈WebRTC技术原理与应用

avatar
前端工程师 @公众号:ELab团队

一、技术背景

自2010年至今,WebRTC的出现和发展简要背景

  • 根据 Cisco 预测指数显示,到 2022 年,视频将占所有 IP 流量的 82%,高于目前的 75%。在疫情背景下,线上实时音视频交互已经是当下和未来重要的交互途径之一了,比如在线视频会议。

(线上实时音视频交互)

  • WebRTC(Web Real-Time Communication),即网页即时通信。 是一个支持网页浏览器进行实时语音对话或视频对话的技术方案。从前端技术开发的视角来看,是一组可调用的API标准。

  • 在WebRTC发布之前,开发实时音视频交互应用的成本是非常昂贵,需要考虑的技术问题很多,如音视频的编解码问题,数据传输问题,延时、丢包、抖动、回音的处理和消除等,如果要兼容浏览器端的实时音视频通信,还需要额外安装插件。
  • 2010年5月,Google以6820万美元收购VoIP软件开发商Global IP Solutions的GIPS引擎,并改为名为“WebRTC”。旨在建立一个互联网浏览器间的实时通信的平台,让 WebRTC技术成为 H5标准之一。
  • 2012年1月,谷歌已经把这款软件集成到Chrome浏览器中,Opera初步集成WebRTC。
  • 2013年6月,Mozilla Firefox发布22.0版本正式集成及支持WebRTC。
  • 2017 年 11 月 ,W3C WebRTC 1.0 草案正式定稿。

(图引用自W3C重点报告,2021.10版

  • 根据全球领先的技术研究和咨询公司——Technavio的关于“全球网络实时通信(webrtc)市场”的研究报显示,自2017-2021年期间,全球网络实时通信(webrtc)市场,将以34.37%的年均复合增长率增长,可谓十分的迅速。

二、简要特征

WebRTC内容丰富,主要的技术特征包含以下几点:

1. 实时通讯

是一项实时通讯技术,允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。

2. 无依赖/插件

WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

3. 协议栈 众多

它并不是单一的协议,包含了媒体、加密、传输层等在内的多个协议标准以及一套基于 JavaScript 的 API,它包括了音视频的采集、编解码、网络传输、显示等功能。通过简单易用的 JavaScript API ,在不安装任何插件的情况下,让浏览器拥有了 P2P音视频和数据分享的能力。

(WebRTC依赖众多协议栈图)

相关协议介绍与作用
ICE、STUN、TURN用于内网穿透, 解决了获取与绑定公网映射地址
DTLS用于对传输内容进行加密
SRTP 、 SRTCP 对媒体数据的封装与传输控制协议

同时WebRTC 并不是一个孤立的协议,它拥有灵活的信令,可以便捷的对接现有的SIP 和电话网络的系统。

三、兼容覆盖

主流浏览器的兼容情况

  • 目前大部分主流浏览器都正常兼容,如下图

(浏览器兼容性覆盖图)

  • 主流浏览器都支持 WebRTC 标准 API ,因此也让浏览器之间无插件化的音视频互通成为可能, 大大降低了音视频开发的门槛,开发者只需要调用 WebRTC API 即可快速构建出音视频应用

四、技术框架

结合技术框架图来认知和理解官方技术框架的基本内容

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

(技术框架图)

  • 从图中可看到主要面向三类开发者的API设计,包括:

    a.对于Web开发者的API

    框架包含了基于 ****JavaScript 经过W3C认证了的一套API标准,使得web开发者可以基于这套API开发基于WebRTC的即时通讯应用。

    b.对于浏览器厂商的API

    框架同样包含了基于C++的底层WebRTC接口,对于浏览器厂商底层的接入十分友好。

    c.浏览器厂商可自定义的部分

    框架中还包含浏览器厂商可自定义的音视频截取等扩展部分。

    五、核心内容

从上述框架中看到,主要有音频、视频引擎和传输三部分主要内容,其中又包含众多的协议和方法等

  • WebRTC 主要组成:
  1. Voice Engine(音频引擎)

    1. Voice Engine包含iSAC/iLBC Codec(音频编解码器,前者是针对宽带和超宽带,后者是针对窄带)
    2. NetEQ for voice(处理网络抖动和语音包丢失)
    3. Echo Canceler(回声消除器)/ Noise Reduction(噪声抑制)
  1. Video Engine(视频引擎)

    1. VP8 Codec(视频图像编解码器)
    2. Video jitter buffer(视频抖动缓冲器,处理视频抖动和视频信息包丢失)
    3. Image enhancements(图像质量增强)
  1. Transport

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

    六、实现原理

不细致介绍音视频采集、编码和处理等内容,仅介绍实时通讯的建立过程原理的核心内容

1. 公网IP映射:明确网络定位信息

  • WebRTC是建立浏览器端到端的连接(P2P),由于不需要服务器中转,所以获取连接对象的网络地址的方式,是借助于ICE、STUN、TURN等辅助内网穿透技术(NAT)得到对应主机的公网网络地址和端口等网络定位信息。明确网络定位是建立端与端直接通讯的基础。

    (NAT原理图)

(STUN服务器用于辅助内网穿透得到对应主机的公网网络地址和端口信息图)

2. 信令服务器:网络协商与信息交换

  • 信令服务器的作用是基于双工通信来中转信息。中转信息包括公网IP映射后的网络定位信息(公网IP、端口和媒体数据流等。

(概念图)

(信令服务器信息交互过程图)

3. 会话描述协议SDP:统一的媒体协商方式

  • 不同端/浏览器对于媒体流数据的编码格式各异,如VP8、VP9等,参与会话的各个成员的能力不对等、用户环境与配置不一致等。
  • WebRTC 通讯还需要确定和交换本地和远程音频和视频媒体信息,例如分辨率和编解码器功能。 交换媒体配置信息的信令通过使用会话描述协议 (SDP) 交换Offer和Anwser来进行。
  • SDP的交换一定是先于音视频流交换的。其内容包括会话基本信息、媒体信息描述等。
//SDP的结构体
Session description(会话级别描述)
         v=  (protocol version)
         o=  (originator and session identifier)
         s=  (session name)
         c=* (connection information -- not required if included in all media)
         One or more Time descriptions ("t=" and "r=" lines; see below)
         a=* (zero or more session attribute lines)
         Zero or more Media descriptions

Time description
         t=  (time the session is active)

Media description(媒体级别描述), if present
         m=  (media name and transport address)
         c=* (connection information -- optional if included at session level)
         a=* (zero or more media 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/SAVPF 103 104 0 8 106 105 13 126 // ... 

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh81

4.一对一连接建立过程

以建立一对一的Web RTC连接过程为

(一对一过程图)

  • 简要过程

(简要过程图)

  • 交换SDP,获取各自媒体配置信息
  • STUN服务器交换网络地址和端口等网络信息
  • Turn中转音视频媒体流数据
  • 工作流

(工作流程图)

  1. A和B双方先调用 getUserMedia 打开本地摄像头,作为本地待输出媒体流;
  1. 向信令服务器发送加入房间请求;
  1. Peer B 接收到 Peer A 发送的 offer SDP 对象,并通过PeerConnection的SetLocalDescription方法保存 Answer SDP 对象并将它通过信令服务器发送给 Peer A。
  1. 在 SDP 信息的 offer/answer 流程中,Peer A 和 Peer B 已经根据 SDP 信息创建好相应的音频 Channel 和视频 Channel,并开启Candidate 数据的收集,Candidate数据(本地IP地址、公网IP地址、Relay服务端分配的地址)。
  1. 当 Peer A 收集到 Candidate 信息后通过信令服务器发送给 Peer B。同样的过程 Peer B 对 Peer A 也会再发送一次。

6. 多对多的建立

image.png

(多对多建立点到点连接概念图,以三个用户点对点的连接为例)

7. JavaScript主要接口

  • 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);
// 允许 RTC 服务器配置。
const server = { 
    "iceServers": 
            [{ "urls": "stun:stun.stunprotocol.org"}] 
};

// 创建本地连接
const localPeerConnection = new RTCPeerConnection(servers);

// 收集Candidate 数据
localPeerConnection.onicecandidate=function(event){
    ...
}
// 监听到媒体流接入时的操作
localPeerConnection.ontack=function(event){
    ...
}
  • RTCDataChannel:支持通用数据的点对点通信,常用于数据点到点的传输
const pc = new RTCPeerConnection();
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");
};

七、应用案例

多人视频案例为实践应用

1. 设计框架

image.png

(多人视频基本框架图)

2.关键代码

1.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=new RTCPeerConnection(iceServer);

1.2 网络协商

  • 创建对等连接,收集ICE候选,等待媒体流接入时挂载到dom

交互式连通性建立(Interactive Connectivity Establishment — ICE)是一个允许实时对等端发现对方并且彼此连接的框架。此技术允许对等方发现有关彼此拓扑的足够信息,从而有可能在彼此之间找到一条或多条通信路径。ICE 代理负责:收集本地IP,端口元组候选、在同级之间执行连接检查和发送连接保持活动

 // 发送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]
}

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(new RTCIceCandidate(signalMsg["data"].iceCandidate));
  • 效果

(多人视频结果截图<本地模拟效果>)

1.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"],
                    }));
                }
            });
        }
    })
})

八、应用场景

WebRTC在当下和未来具有丰富的应用场景,此文档不再赘述,可见下面URL的内容

webrtcforthecurious.com/zh/docs/08-…

九、重要意义

WebRTC的出现、发展和被业内标准(如W3C)等普遍认可,对于当下和未来大前端技术发展具有重要的意义

  1. 降低在web端的音视频交互开发门槛

    1. 以往的音视频交互开发对于Web开发者而言具有一定技术门槛,
    2. 现在借助于WebRTC,Web开发者通过调用JS接口,可快速的实现音视频交互应用。
  1. 避免依赖、插件造成的次生问题

    1. 以往的音视频交互应用构建依赖于各种插件、软件和服务器等
    2. 现在借助于主流浏览器即可形成端到端的音视频交互
  1. 统一化和标准化对传统音视频交互环境差异性的规避

    1. 以往音视频交互需要面对不同的 NAT 、防火墙对媒体 P2P 的建立带来了很大的挑战
    2. 现在WebRTC 中有P2P 打洞的开源项目 libjingle ,支持 STUN,TURN 等协议
  1. 更高效优化的算法、技术对于音视频交互性能的提升

    1. WebRTC 通过NACK、FEC技术,避免了经过服务端路由中转,减少了延迟和带宽消耗。还有 TCC + SVC + PACER + JitterBuffer 等技术对于音视频流畅性进行了优化

十、参考

本文档相关内容参考自下面的众多文章、项目Markdown和代码等内容,在此一一列出

  1. github.com/Tinywan/Web…
  1. www.bookstack.cn/read/webrtc…
  1. www.html5rocks.com/en/tutorial…
  1. zh.wikipedia.org/wiki/WebRTC
  1. zhuanlan.zhihu.com/p/93107411
  1. github.com/muaz-khan/W…
  1. xie.infoq.cn/article/ddc…
  1. juejin.cn/post/696903…
  1. www.jianshu.com/p/24363820b…
  1. zhuanlan.zhihu.com/p/79489847
  1. www.researchandmarkets.com/reports/511…

十一、QA

  • Q:商业应用现状?商业应用时的安全性、数据传输的解决方案?

    • A:不太了解,目前成熟的商业应用比较少,我猜想成熟的商业应用会进步一进行包装,以满足商业应用中的安全性、数据传输等要求
    • A:WebRTC对于一对一单聊比较适用,但对于超多人聊天还是有优化空间toutiao.io/posts/48976…
  • Q:安卓应用兼容性不好

    • A:这个我没有经验,但现阶段的确有兼容性问题,该技术还有待进一步兼容性优化和成熟应用,我也去再了解了解。