关于前端:音视频WebRTC

38次阅读

共计 9143 个字符,预计需要花费 23 分钟才能阅读完成。


何为 WebRTC?预计有很多同学曾经听过相干名词,然而也只是云里雾里懵逼状态。说到 WebRTC 的利用场景,可能大略就会晓得 WebRTC 能够用来做什么事件,例如近几年比拟炽热的直播 & 带货、视频会议、网课,或多或少在技术实现上都避不开应用 WebRTC 的相干技术。

本文将向大家介绍 WebRTC 相干技术内容,置信看完后,能对 WebRTC 有一个新的意识。

什么是 WebRTC?

WebRTC (Web Real­Time Communication,网页实时通信)是谷歌的开源我的项目,提供了一套规范 API,使 Web 利用在不须要借助任何插件的状况下能够间接提供实时音视频通信性能。同时,也毋庸关注音视频通信相干的技术,例如视频采集、编解码、网络实时传输等内容,能够不便的基于 JavaScript 疾速实现音视频通信利用。

WebRTC 由 IETF (Internet Engineering Task Force,互联网工程工作组) 和 W3C (World Wide Web Consortium,万维网联盟) 联结负责其标准化;

  • IETF 定制 WebRTC 的互联网根底协定规范,该规范也被称为 RTC Web (Real-Time Communication in Web-browsers);
  • W3C 则负责定制 WebRTC 的客户端 JavaScript API 接口的规范;

    历史

  1. 它是谷歌 2010 年 5 月收买领有编解码、回声打消等技术的 Global IP Solutions 公司而取得的一项技术,后改名为 WebRTC;
  2. 2011 年 5 月凋谢了工程的源代码,与相干机构 IETF 和 W3C 制订行业标准,组成了现有的 WebRTC 我的项目,在行业内失去了宽泛的反对和利用,成为下一代视频通话的规范;
  3. 2012 年 1 月,谷歌曾经将这项技术集成到 Chrome 浏览器中;
  4. 2013 年 6 月,Mozilla Firefox 公布 22.0 版本正式集成及反对 WebRTC;
  5. 2017 年 11 月,W3C WebRTC 1.0 草案正式定稿;
  6. 2021 年 1 月,WebRTC 被 W3C 和 IETF 公布为正式规范;

WebRTC 利用场景

WebRTC 作为反对跨平台的音视频通信技术,通过简略的形式实现单点或者多点之间的通信互通,可能使用在很多场景:

  • 社交平台,如视频聊天室利用
  • 近程实时监控
  • 在线教育、在线培训
  • 会议零碎
  • Web IM
  • 会议和分割核心之间的合作,如客户服务、呼叫核心
  • 游戏娱乐,如双人对战游戏(如象棋这种双人对战游戏,每一步的数据服务器时不关怀的,所以齐全能够点对点发送)
  • 屏幕共享
  • 人脸检测辨认

WebRTC 框架介绍

从技术实现的角度讲,在浏览器之间进行实时通信须要应用很多技术,如音视频编解码、网络连接治理、媒体数据实时传输等,还须要提供一组易用的 API 给开发者应用。这些技术组合在一起,就是 WebRTC 框架,如下图:

阐明

尽管作为下层开发者,对于音视频底层的技术可能难以接触和学习,然而还是有必要理解一下底层在音视频通信上都有哪些解决。
从上图能够看到,WebRTC 能够大抵分为三类层级,面向的用户或者开发者也不尽相同:

1. Web API

此层级面向 Web 开发者的 APIs,框架包含了 JavaScript、通过 W3C 认证的一套 API 规范。API 提供三个性能接口,别离是 MediaStream、RTCPeerConnection 和 RTCDataChannel,通过此 APIs 能够疾速实现一个点对点的视频通话利用;

  • MediaStream:用于浏览器采集或贮存输出设备的实时音视频流(蕴含音频 / 视频数据),不便疾速进行视频流的采集的渲染,是罕用的 API 之一;
  • RTCPeerConnection:此接口是 WebRTC 的外围接口,用来解决设施和设施之间稳固的连贯和数据流通信;
  • RTCDataChannel:此接口是 WebRTC 用于连贯数据传输的通道,不仅仅是音 / 视频数据,还能够是任意的文本 / 文件等数据;

稍后,将具体介绍此三项 APIs 的应用;

2. WebRTC C++ API

C++ API 提供给浏览器厂商、平台 SDK 开发者应用的 C++ API,不同的平台能够通过各自的 C++ 接口调用能力,对其进行下层封装以满足跨平台的需要;

3. 浏览器厂商

上图中虚线局部即框架中蕴含浏览器厂商可自定义的扩大内容,包含视音频的采集 / 渲染 / 网络 IO 局部,例如能够疾速实现浏览器视频截屏插件。

核心技术

上图能够看到分三层用户类别,但 C ++ API 将是外围的内容,是由视频、音频、和传输三局部组成,其中传输又蕴含了泛滥的协定和形式;

1. Voice Engine(音频引擎)

音频引擎,蕴含一系列音频多媒体解决的框架,包含 Audio Codecs、NetEQ for voice、Acoustic Echo Canceller (AEC) 和 Noise Reduction (NR);

  • Audio Codec:音频编解码器,目前反对的有:Opus、G.711 PCM (A-law)、G.711 PCM (µ-law)、G722、iLBC、iSAC,具体编码器个性详见 MDN 介绍;
  • NetEQ for voice:自适应抖动控制算法以及语音包失落暗藏算法,用于适应一直变动的网络环境,从而放弃尽可能低的提早,同时放弃最高的语音品质;
  • Acoustic Echo Canceller (AEC):回声消除器,用于实时打消麦克风采集到的回声;
  • Noise Reduction (NR):噪声抑制器,用于打消与相干 VoIP 的某些类型的背景乐音;

    2. Video Engine(视频引擎)

    视频解决引擎,蕴含一系列视频解决的整体框架,从摄像头采集视频到视频信息网络传输再到视频显示整个残缺过程的解决方案,包含 Video Codec、Video Jitter Buffer 和 Image Enhancement;

  • Video Codec:视频编解码器,目前常见的的有:VP8、VP9 和 H.264 编解码,此处做个阐明,支流的编解码器次要是 H.264,不同的浏览器端波及到版权影响,须要额定思考不同编码器所造成的兼容状况;
  • Video Jitter Buffer:视频抖动缓冲器,解决视频抖动和视频信息包失落等问题;
  • Image Enhancement:图像品质加强模块,用于对摄像头采集回来的图像进行解决,包含明暗度检测、色彩加强、降噪解决等;

    3. Transport(数据传输模块)

    数据传输模块,WebRTC 对音视频进行 P2P 传输的外围模块,包含 SRTP、Multiplexing 和 P2P;

  • SRTP:基于 UDP 的平安实时传输协定,用于音视频流传输;
  • Multiplexing:多路复用技术,采纳多路复用技术能把多个信号组合在一条物理信道上进行传输,缩小对传输线路的数量耗费;
  • P2P 是端对端传输技术,WebRTC 的 P2P 技术集成了 STUN、TURN 和 ICE,这些都是针对 UDP 的 NAT 的防火墙探测、穿梭形式,为了保障双向的连贯可能正确的获取对方的网络信息;

一对一通话根底

置信到这里,咱们大略对 WebRTC 的根底框架有一个简略的理解,晓得了 WebRTC 能够实现视频采集和传输,以及相干的偏底层的模块介绍。

接下来,再深刻了解一对一通话所波及到的几个要害专业名词和技术解释,帮忙咱们更好的为后续实现一对一通话打下基础。

信令服务器

信令服务器(Signal Server)是各个端可能实现会话信息共享的服务器,个别搭建在公网或者各个端都能互通的局域网中。

同时,支流的信令服务架构上,也会承载如下内容:

  • 管制会话整个生命周期,包含不限于会话创立、管制(静音、设置会场主持人)、完结、鉴权等会议操作;
  • 解决会话谬误的音讯;
  • 传递网络信息、媒体协商信息、对方的公网 IP、端口、内网 IP 及端口信息,即如下所说的 SDP 协定报文;


实现形式 :实现信令服务器的形式有很多,例如通过 TCP、WebSocket、Socket.io 等形式实现信令服务器。
信令音讯(Signal Message):能够看作是各个端和服务器约定成俗的数据类型,一般来说,是对象数据格式,每个信令音讯蕴含本人的 Type 信息、根底信息、会须要替换的数据信息。例如:

{
        type: "answer",
        meetingId: "xxx",
        data: {sdp: "xxx",}
}

媒体协商(SDP:Session Description Protocol)

在 P2P 连贯时,须要进行发送 Offer 和 Answer 应答,其中应用 SDP 来形容会话的媒体信息、编解码器信息、根本信息等形容内容,参加音视频通信的单方必须替换此信息,这种替换过程咱们就能够了解为媒体协商;

为什么须要媒体协商?

不同端浏览器的媒体数据编解码数据格式不统一,为了让 Peer1 与 Peer2 进行视频互通,必须要保障两端都能正确的编解码,所以须要协商出统一的 H264 编解码器。

SDP 格局

Session description
         v=  (protocol version) 协定版本号
         o=  (originator and session identifier) 会话所有者无关的参数
         s=  (session name) 会话名称
         i=* (session information) 会话信息
         u=* (URI of description) 形容的 URI
         c=* (connection information -- not required if included in
              all media) 连贯信息 - 如果包含在内,则不须要所有媒体
         b=* (zero or more bandwidth information lines) 所有带宽信息
         One or more time descriptions ("t=" and "r=" lines; see below)
         z=* (time zone adjustments)  时区调整
         k=* (encryption key) 加密密钥
         a=* (zero or more session attribute lines) 零个或多个会话属性行
Time description
         t=  (time the session is active) 会话流动的工夫
         r=* (zero or more repeat times) 零次或多次重复次数
Media description, if present
         m=  (media name and transport address) 媒体名称和传输地址
         i=* (media title) 媒体 title
         c=* (connection information -- optional if included at
              session level)  连贯信息 - 可选,如果蕴含在会话级别
         b=* (zero or more bandwidth information lines) 带宽信息
         k=* (encryption key) 加密密钥
         a=* (zero or more media attribute lines) 媒体属性信息

SDP 例子

上面是展现 Safari 浏览器协商进去的 SDP 会话报文内容:

v=0 
s=-
t=0 0
a=group:BUNDLE 0 1
a=msid-semantic: WMS 88b1b161-a5b6-4b7e-8ba1-f8223f5eae8f
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 125 104
c=IN IP4
a=setup:actpass
a=mid:0
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=sendrecv
a=msid:88b1b161-a5b6-4b7e-8ba1-f8223f5eae8f db4ccf3c-14fe-495c-bee3-3ae55b2f83ea

受限文章篇幅,将在后续文章具体介绍 SDP 会话协定报文内容,此处只做简略的理解即可;

网络协商

下面说到,P2P 是端对端传输技术,所以为了连贯两个利用端,就须要晓得单方的网络信息,应用实在的公网 ip 进行 UDP 的连贯,从而进行数据流的疾速传递(留神和上文的信令服务器的区别)。
WebRTC P2P 技术集成了 STUN、TURN 和 ICE,这些都是针对 UDP 的 NAT 的防火墙探测、穿梭形式,为了保障获取到各自实在的网络信息。

NAT

在事实网络环境中,大多数计算机主机都位于路由器、防火墙、NAT 之后,只有少部分终端可能间接接入网络。咱们心愿网络中的两台设施或利用可能间接进行通信,即所谓的 P2P 通信,而不须要其余公共服务器的直达。因为主机可能位于防火墙、NAT 之后,在进行 P2P 通信之前,咱们须要进行检测以确认它们之间是否进行 P2P 通信以及如何通信。这种技术通常称为 NAT 穿透(NAT Traversal)。最常见的 NAT 穿透是基于 UDP 的技术;

简略来说,NAT 能够将本地 IP 和端口的映射到公网 IP 和端口,在 NAT 进行转换时,须要应用到 STUN 和 TURN;

STUN(Simple Traversal of UDP Through NATs)

简略的用 UDP 穿透 NAT,是个轻量级的协定,基于 UDP 的残缺的穿透 NAT 的解决方案,它的作用是使位于 NAT 后的客户端找出本人的公网 IP 地址与端口号,不便进行端对端的 P2P 连贯。

WebRTC 应用 STUN 获取服务 IP 和端口具体流程在这里不做阐明,后续会在架构文章中解释整个探测的流程。此处咱们所要晓得的就是通过 STUN Server 咱们能够疾速获取外网 IP 进行 P2P 的端对端连贯;

TURN(Traversal Using Relays around NAT)

应用中继穿透 NAT,属于 STUN 的中继扩大。简略的说,TURN 是通过通信单方的“中间人”形式实现数据互通。

ICE(Interactive Connectivity Establishment)

翻译过去的意思是:互动式连贯建设。ICE 不是一种协定,它是一个框架,整合了 STUN 和 TURN,使各种 NAT 穿透技术能够实现对立。

ICE 会先尝试 STUN,查出本人本地 IP 和端口从而建设 UDP 连贯,如果失败了 ICE 就会再尝试 TCP(先尝试 HTTP,再尝试 HTTPS),如果依然失败就应用中继的 TURN 服务器。因而,ICE 能够实现在未知网络拓扑构造中的设施互连。

一对一通话流程

如上介绍了一对一通话根底波及的相干技术名词,有了肯定的了解后,咱们再来查看下图展现的一对一 WebRTC 呼叫的时序图:

解释一下下面的时序图:

  1. ClientA 通过信令服务器建设会议,ClientB 退出会议(Connect),造成连贯;
  2. ClientA 建设 Peer 连贯,并增加本地的画面流数据(addTracks);
  3. ClientA 建设 Offer,通过信令服务器发送 Offer SDP 报文,期待 Answer 响应;
  4. ClientB 接管到 Offer 后,触发 setLocalDescription,触发“候选网络链路”收集,并通过信令返回 ClientA Answer 应答;
  5. ClientA 接管到 STUN Server Candidate 信息(网络链路探测失去的内外网 IP 信息,端口等)后,通过信令服务器发送给 ClientB;
  6. ClientB 响应 Candidate 音讯,并返回 Clienta 替换网络信息;
  7. 如果两个网络信息达成统一,则整个 P2P 的连贯胜利;
  8. 单方通过 OnAddStream 事件,获取到 Peer 通道上的 MediaStream Track 数据展现并播放;

本文次要解说 WebRTC 根底内容,再接下来的文章中,咱们将逐渐实现一对一通话的代码。

要害 API 应用

  1. MediaStream
  2. RTCPeerConnection
  3. RTCDataChannel

    MediaStream

    MediaStream 是一个媒体内容的流,一个流蕴含几个轨道,比方视频和音频轨道。能够通过 getUserMedia 办法获取 MediaStream 媒体流;

    <!DOCTYPE html>
    <html lang="en">
      <head>
     <meta charset="UTF-8">
     <title>MeidaStream Play</title>
      </head>
    
      <body>
     <div>
       <button onclick="playVideo()"> 采集并播放 </button>
     </div>
     <video id="localVideo" autoplay playsinline controls="false" width="300" height="200"></video>
      </body>
    
      <script>
     const getUserMidia = async (constraints) => {return await navigator.mediaDevices.getUserMedia(constraints);
     }
     const playVideo = async () => {
       try {const stream = await getUserMidia({ video: true, audio: true});
         const videoElement = document.getElementById('localVideo');
    
         // 通过 Video 播放采集到的摄像头和麦克风数据流
         videoElement.srcObject = stream;
       } catch (error) {
         // 解决采集媒体流异常情况
         console.error('Error accessing media devices.', error);
       }
     }
      </script>
    </html>

    成果如下:

    RTCPeerConnection

    每个对等连贯由 RTCPeerConnection 对象解决。类的构造函数传递单个 RTCConfiguration 对象作为其参数。
    调用端:

    async function makeCall() {
     // 此处 signalingChannel 代表信令服务器通道,监听远端 message 音讯
     signalingChannel.addEventListener('message', async message => {if (message.answer) {
             // 接管到 Answer 音讯
             const remoteDesc = new RTCSessionDescription(message.answer);
             // 设置形容
             await peerConnection.setRemoteDescription(remoteDesc);
         }
     });
    
     // 配置 ICE STUN 服务器
     const configuration = {'iceServers': [{ 'urls': 'stun:stun.l.google.com:19302'}] }
     // 创立 PeerConnection
     const peerConnection = new RTCPeerConnection(configuration);
     // 创立 Offer 音讯
     const offer = await peerConnection.createOffer();
     // 将 Offer 设置到本地形容中
     await peerConnection.setLocalDescription(offer);
     // 通过信令服务区发送给接收端
     signalingChannel.send({'offer': offer});
    }

    接收端:

    // 创立 PeerConnection
    const peerConnection = new RTCPeerConnection(configuration);
    // 监听信令的 message 音讯
    signalingChannel.addEventListener('message', async message => {if (message.offer) {
         // 接管到 Offer 音讯,设置远端形容
         peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
         // 创立 Answer 音讯
         const answer = await peerConnection.createAnswer();
         // 设置到本地形容
         await peerConnection.setLocalDescription(answer);
         // 通过信令发送给发送端
         signalingChannel.send({'answer': answer});
     }
    });    

    ICE 探测:

    // 发送端
    peerConnection.addEventListener('icecandidate', event => {if (event.candidate) {signalingChannel.send({'new-ice-candidate': event.candidate});
     }
    });
    
    // 接收端
    signalingChannel.addEventListener('message', async message => {if (message.iceCandidate) {
         try {await peerConnection.addIceCandidate(message.iceCandidate);
         } catch (e) {console.error('Error adding received ice candidate', e);
         }
     }
    });

    RTCDataChannel

    通过 RTCDataChannel 能够发送任意数据,此处将演示根底的应用,在理论应用中,不倡议应用此数据通道,可能受低带宽影响,存在数据失落问题。

    // 发送端
    const peerConnection = new RTCPeerConnection(configuration);
    const dataChannel = peerConnection.createDataChannel();
    dataChannel.send("hello world");
    
    // 接收端
    const peerConnection = new RTCPeerConnection(configuration);
    peerConnection.addEventListener('datachannel', event => {const dataChannel = event.channel;});

    API 局部只是简略的应用演示,再接下来的文章中,咱们会具体的介绍每个 API 的具体应用形式。如果想提前自行学习理解,此处举荐查阅 MDN WebRTC 系列 API 内容;

结语

本篇具体介绍了 WebRTC 的根底框架介绍和实现一对一所波及到相干技术内容,一些技术细节可能须要大家自行了解和实际测试,毕竟纸上学来终觉浅,绝知此事要躬行。后续咱们也将具体介绍 WebRTC 如何实现一对一呼叫以及更为深刻的内容,欢送大家关注。

如有问题,可在评论区留言进行交换;

参考

  1. Get Started with WebRTC
  2. webrtc.org
  3. WebRTC MDN APIs
  4. MediaStream MDN
  5. 开源工程 WebRTC 的技术原理和应用浅析
  6. 百科 -WebRTC
  7. NAT 穿梭与 ICE

正文完
 0