1 什么是 WebRTC
WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。
2 需要了解哪些基础知识
2.1 ICE
交互式连接设施 Interactive Connectivity Establishment (ICE) 是一个允许你的浏览器和对端浏览器建立连接的协议框架。一般用于支持 Voice over Internet Protocol (VoIP), peer-to-peer communications, video, 和 instant messaging。可以理解成实现全双工通信一种协议。
但是在实际的网络情况下,有很多原因会导致 A 端和 B 端无法直接连接到,比如 A 端在路由器内网环境没有做端口映射的情况下或者无法跨越防火墙,这个时候就需要一台中转服务器去转发数据。
2.2 NAT
网络地址转换协议 Network Address Translation (NAT) 用来给你的(私网)设备映射一个公网的 IP 地址的协议。一般情况下,路由器的 WAN 口有一个公网 IP,所有连接这个路由器 LAN 口的设备会分配一个私有网段的 IP 地址(例如 192.168.1.3)。私网设备的 IP 被映射成路由器的公网 IP 和唯一的端口,通过这种方式不需要为每一个私网设备分配不同的公网 IP,但是依然能被外网设备发现。
2.3 STUN
NAT 的会话穿越功能 Session Traversal Utilities for NAT (STUN) (缩略语的最后一个字母是 NAT 的首字母)是一个允许位于 NAT 后的客户端找出自己的公网地址,判断出路由器阻止直连的限制方法的协议。
客户端通过给公网的 STUN 服务器发送请求获得自己的公网地址信息,以及是否能够穿过路由器访问。
但是一些路由器严格地限定了部分私网设备的对外连接。这种情况下,即使 STUN 服务器识别了该私网设备的公网 IP 和端口的映射,依然无法和这个私网设备建立连接。这种情况下就需要转向 TURN 协议。
2.4 TURN
一些路由器使用一种“对称型 NAT”的 NAT 模型。这意味着路由器只接受和对端先前建立的连接(就是下一次请求建立新的连接映射)。
NAT 的中继穿越方式 Traversal Using Relays around NAT (TURN) 通过 TURN 服务器中继所有数据的方式来绕过“对称型 NAT”。你需要在 TURN 服务器上创建一个连接,然后告诉所有对端设备发包到服务器上,TURN 服务器再把包转发给你。很显然这种方式是开销很大的,所以只有在没得选择的情况下采用。
2.5 SDP
会话描述协议 Session Description Protocol (SDP) 是一个描述多媒体连接内容的协议,例如分辨率,格式,编码,加密算法等。所以在数据传输时两端都能够理解彼此的数据。本质上,这些描述内容的元数据并不是媒体流本身。
3 信令服务器
两个设备之间建立 WebRTC 连接需要一个信令服务器来实现双方通过网络进行连接。信令服务器的作用是作为一个中间人帮助双方在尽可能少的暴露隐私的情况下建立连接。WebRTC 并没有提供信令传递机制,你可以使用任何你喜欢的方式如 WebSocket 或者 XMLHttpRequest 等等,来交换彼此的令牌信息。
3.1 交换会话描述信息
开始处理信号的时候,用户的初始化操作会创建一个请求(offer,通过 PeerConnection 生成) ,根据 SDP 协议其中会包含一个 session 描述符,并且需要把这个发送到我们称之为接收者(callee)那里, 接受者需要返回一个包含描述符的应答(answer)信息。我们的服务器使用 WebSocket 来传递 "video-offer" "video-answer" 两种类型的消息数据。这些消息包含以下属性:
type:消息类型; "video-offer" 或 "video-answer"
name:发送者用户名
target:接受者的用户名(如果呼叫者正在发送消息,则指定被呼叫者,反之亦然)
sdp:描述连接本地端 SDP(Session Description Protocol)协议字符串(从接收者的角度来看,它描述远程端)
到此为止双方都知道使用什么样的代码和参数进行通信了。尽管如此他们仍然不知道自己该如何传递媒体数据。 Interactive Connectivity Establishment (ICE)协议该上场了。
3.2 交换 ICE 候选
两个节点需要交换 ICE 候选来协商他们自己具体如何连接。每一个 ICE 候选描述一个发送者使用的通信方法,每个节点按照他们被发现的顺序发送候选并且保持发送直到退出,即使媒体数据流已经开始传递也要如此。
每个 ICE 消息都建议提供一个通信协议(TCP 或 UDP)、IP 地址、端口号、连接类型(例如,指定的 IP 是对等机本身还是中继服务器),以及将两台计算机连接在一起所需的其他信息。这包括 NAT 或其他网络问题。
4 Show Me The Code
const video = document.getElementById("video");
const socket = new WebSocket();
const iceServers = [{ urls: "stun:stun.stunprotocol.org" }];
const myPeerConnection = new RTCPeerConnection({ iceServers });
// 监听socket数据返回
socket.on("message", data => {
if (data.type === "answer") {
myPeerConnection.setRemoteDescription(data); // SDP
} else if (data.type === "candidate") {
myPeerConnection.addIceCandidate(data);
}
});
// 监听myPeerConnection产生的icecandidate
myPeerConnection.addEventListener("icecandidate", ({ candidate }) => {
socket.publish(candidate);
});
// 监听myPeerConnection连接成功之后返回的streams
myPeerConnection.addEventListener("track", ({ streams }) => {
video.current.srcObject = streams[0];
});
navigator.mediaDevices
// 获取当前设备的数据
.getUserMedia({ audio: true, video: true })
// 将流传输给myPeerConnection
.then(localStream => myPeerConnection.addStream(localStream))
// 创建offer
.then(() => myPeerConnection.createOffer())
// 设置本地的offer
.then(offer => {
myPeerConnection.setLocalDescription(offer);
return offer;
})
// 通过socket发送offer
.then(offer => socket.publish(offer))
.catch(err => err);
下期介绍hlsjs以及视频加解密过程