跳到主要内容

WebRTC

WebRTC 标准概括介绍了两种不同的技术:媒体捕获设备和点对点连接。

媒体捕获设备包括摄像机和麦克风,还包括屏幕捕获设备。对于摄像头和麦克风,我们使用navigator.mediaDevices.getUserMedia()来捕获 MediaStreams。对于屏幕录制,我们改为使用 navigator.mediaDevices.getDisplayMedia()

点对点连接由 RTCPeerConnection 接口处理。这是在 WebRTC 中两个对等方之间建立和控制连接的中心点。

WebRTC处理过程

WebRTC1对1音视频实时通话过程示意图

从上图看出可以分为4个部分。两个WebRTC终端,一个Signal服务器和一个STUN/TURN服务器。

  • WebRTC终端,负责音视频采集、编解码、NAT穿越、音视频数据传输
  • Signal服务器,负责信令处理,如加入房间、离开房间、媒体协商消息的传递等
  • STUN/TURN服务器,负责获取WebRTC终端在公网的IP地址,已经NAT穿越失败后的数据中转

音视频采集

getUserMedia() MDN w3c

打开摄像头和麦克风
const MediaStreamConstraints = {
video: true
audio: true
}

navigator.mediaDevices.getUserMedia(MediaStreamConstraints).then(stream => {
video.srcObject = stream
}).catch(err => {
console.log(err);
})
提示

getUserMedia()第一次请求访问摄像头和输入设备,浏览器会像用户提示窗口,是否允许访问摄像头和输入设备。如果用户不同意,则直接走失败回调NotAllowedErrorPermissionDeniedError

RTP/RTCP

一般情况下,在实时音视频通话传输音视频数据流时,我们并不是直接将音视频数据流交给UDO传输,而是先给音视频数据加个RTP头,在交给UDP进行传输。

RTCP有两个重要的报文:RR和SR。通过这两个报文的交换,各端就知道自己的网络质量如何

SDP

SDP以本文描述各端(PC、MAC、Android、IOS)的能力。

  1. 音频编解码器是什么?这个编解码器设定的参数是什么?
  2. 使用的传输协议是什么?
  3. 已经包括的音视频媒体是什么?

SDP是由一个会话层和多个媒体层组成的,而对于每个媒体层,WebRTC又将细划为四部分,即媒体流、网络描述、安全描述和服务质量描述。

媒体协商

媒体协商的作用就是让双方找到共同支持的媒体能力,如双方都支持的编解码器,从而最终实现彼此之间的音视频通信。

  1. 通信双方将它们各自的媒体信息,如编解码器、媒体流的SSRC、传输协议、IP地址和端口等,按SDP格式整理好
  2. 通信双方通过信令服务器交换SDP信息,并彼此拿到对方的SDP信息后,找到它们共同支持的媒体能力
  3. 双方按照协商好的媒体能力开始音视频通信

RTCPeerConnection

端到端之间建立的连接

创建RTCPeerConnection实例
const pcConfig = null
const pc = new RTCPeerConnection(pcConfig)

在通讯双方都创建好RTCPeerConnection对象后,它们就可以开始进行媒体协商了。不过在进行媒体协商之前,有两个重要的概念,即OfferAnswer.

Offer: 呼叫方发送的SDP消息成为Offer
Answer: 被呼叫方发送的SDP消息成为Answer

呼叫方创建Offer类型的SDP消息。创建完成后,调用setLocalDescription方法,将该Offer保存到本地Local域,然后通过信令将Offer发送给被呼叫方
被呼叫收到Offer类型的SDP消息后,调用setRemoteDescription方法将Offer保存到它的Remote域。作为应答,被呼叫方要创建Answer类型的SDP消息,Answer消息创建成功后,在调用setLocalDescription方法将Answer类型的SDP消息保存到本地的Local域。最后,被呼叫方将Answer消息通过信令发送给呼叫方。至此,被呼叫方的工作就全部完成了
呼叫方收到Answer类型的消息后,调用RTCPeerConnection对象的setRemoteDescription方法,将Answer保存到它的Remote域

建立连接

在WebRTC建立连接的过程之前,需要ICE Candidate(ICE 候选者)。它表示WebRTC与远端通信时使用的协议、IP地址和端口,一般由以下字段组成:

{
IP: xxx.xxx.xxx.xxx, // 本地ip地址
port: number, // 本地端口号
type: host/srflx/relay, // 候选者类型 包括host/srflx/relay
priority: number, // 优先级
protocol: UDP/TCP, // 传输协议
usernameFragment: string // 访问服务的用户名
//...
}

候选者类型:

  • host 表示本机候选者
  • srflx 内网主机映射的外网的地址和端口
  • relay 中继候选者

当 WebRTC 通信双方彼此要进行连接时,每一端都会提供许多候选者,比如你的主机有两块网卡,那么每块网卡的不同端口都是一个候选者。

WebRTC 会按照上面描述的格式对候选者进行排序,然后按优先级从高到低的顺序进行连通性测试,当连通性测试成功后,通信的双方就建立起了连接。

在众多候选者中,host 类型的候选者优先级是最高的。在 WebRTC 中,首先对 host 类型的候选者进行连通性检测,如果它们之间可以互通,则直接建立连接。其实,host 类型之间的连通性检测就是内网之间的连通性检测。WebRTC 就是通过这种方式巧妙地解决了大家认为很困难的问题。

同样的道理,如果 host 类型候选者之间无法建立连接,那么 WebRTC 则会尝试次优先级的候选者,即 srflx类型的候选者。也就是尝试让通信双方直接通过 P2P 进行连接,如果连接成功就使用P2P 传输数据;如果失败,就最后尝试使用 relay 方式建立连接。

实际上,端对端的建立更主要的工作是Candidate的收集。WebRTC将Candidate分为三中类型:

  • host: 本机内网的IP和端口
  • srflx: 本机NAT映射后的外网的IP和端口
  • relay: 中级服务器的IP和端口

STUN协议

srflx类型的Candidate实际上就是内网地址和端口经NAT映射后的外网地址和端口。

TURN协议

relay 服务是通过 TURN 协议实现的。所以我们经常说的 relay 服务器或 TURN 服务器它们是同一个意思,都是指中继服务器

relay 型候选者的优先级与其他类型相比是最低的,但在其他候选者都无法连通的情况下,relay 候选者就成了最好的选择。因为它的连通率是所有候选者中连通率最高的。 其实,relay 型候选者的获取也是通过 STUN 协议完成的,只不过它使用的 STUN 消息类型与获取 srflx 型候选者的 STUN 消息的类型不一样而已。

RFC5766 的 TURN 协议描述了如何获取 relay 服务器(即 TURN 服务器)的 Candidate过程。其中最主要的是 Allocation 指令。通过向 TURN 服务器发送 Allocation 指令,relay 服务就会在服务器端分配一个新的 relay 端口,用于中转 UDP 数据报。

NAT打洞/P2P穿越

当收集到 Candidate 后,WebRTC 就开始按优先级顺序进行连通性检测了。它首先会判断两台主机是否处于同一个局域网内,如果双方确实是在同一局域网内,那么就直接在它们之间建立一条连接。

但如果两台主机不在同一个内网,WebRTC 将尝试NAT 打洞,即 P2P 穿越。在 WebRTC中,NAT 打洞是极其复杂的过程,它首先需要对 NAT 类型做判断,检测出其类型后,才能判断出是否可以打洞成功,只有存在打洞成功的可能性时才会真正尝试打洞。

WebRTC 将 NAT 分类为 4 种类型,分别是:

  • 完全锥型 NAT
  • IP限制型 NAT
  • 端口限制型 NAT
  • 对称型 NAT

ICE

了解上面的知识后,你再来看ICE就比较简单了。其实ICE就是上面所讲的获取各种类型Candidate的过程,也就是:在本机收集所有的host类型的Candidate,通过STUN协议收集srflx类型的Candidate,使用TURN协议手机relay类型的Candidate。

小结

在WebRTC 中,它首先会尝试 NAT 穿越,即尝试端到端直连。如果能够穿越成功,那双方就通过直连的方式传输数据,这是最高效的。但如果 NAT 穿越失败,为了保障通信双方的连通性,WebRTC 会使用中继方式,当然使用这种方式传输效率会低一些。

在整个过程中,WebRTC 使用优先级的方法去建立连接,即局域网内的优先级最高,其次是 NAT 穿越,再次是通过中继服务器进行中转,这样就巧妙地实现了“既要高效传输,又能保证连通率”这个目标。

WebRTC回声、重音

对本地的video/audio,要设置一个 muted 属性,这里的意思是指将本地视频流播放时静音,否则,就会出现本地视频流的声音又一次作为音频输入源的循环中。

调试

HTTP协议下如何调试?

第一步:在Chrome地址栏访问chrome://flags/#unsafely-treat-insecure-origin-as-secure

第二步:在文本框中填写您要访问的HTTP地址,多个地址请用英文逗号分隔。

第三步:将该设置的Disabled改为Enabled,重启Chrome。Chrome访问第二步的http地址就是https的效果。

参考资料

webRTC简介 从 0 打造音视频直播系统