WebRTC 可以实现浏览器之间点对点的连接,而不需要经过服务器传输,所以从安全性及隐私性,以及数据传输速度都是更好的解决方案,当然单纯传输速度来讲并不一定提高,因为用户网络环境复杂,大的通讯商可以借助专有骨干网络通讯,而点对点可能需要一层层中转。
Preview
预览效果如下图(高糊,反正陌生人认不出,认识的一眼就认识),左侧横向的是电脑,右边纵向的是手机。
Connect Method
众所周知,网络环境非常复杂,很难通过一个 IP 定位到设备,尤其是国内各种 NAT 映射到城域网,根本不可能通过 IP 找到,所以就需要一些协议来发现设备,点击此链接查看所有协议。
这里介绍一种比较通用的 STUN 协议,STUN Server 一般被称为信令服务器,帮助设备之间的互相发现,信令服务器代码很简单,所以资源消耗也很低,可以采用公开的服务,也可以自己搭建,类似于一个 DNS 解析器。
How Work
如图中,A 和 B 用户去问 STUN Server 我在哪里?分别得到了在哪里的信息后,就可以进行点对点的连接了,啊当然这里肯定是经过一个普通的 API Server 去中转的,不然就是黑盒了。
就像战斗机飞行员,先要通过指挥中心得到前线部队的通讯编号,然后才能通过无线电加入前线部队频道。
Establish connection
Initial Client
const socketInfo = io.connect("https://note.lilonghe.net", {
path: "/test/webrtc/api/socket.io/"
});
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: "stun:stun.l.google.com:19302",
},
],
});
Connect Camera And Listen Remote
navigator.mediaDevices.getUserMedia({ audio: false, video: true }).then(stream => {
stream.getTracks().forEach(track => {
peerConnection.value.addTrack(track, stream);
});
});
peerConnection.ontrack = (ev) => {
if (remoteVideoElement) {
remoteVideoElement.srcObject = ev.streams[0];
}
};
Initiate A Communication
这里代码中的 SDP 即会话的协议描述,里面包含很多信息,通过这个 SDP 就可以得到连接对方的协议及加密算法,用于后续连接时怎么处理对方的数据。
const sdp = await peerConnection.value.createOffer({
offerToReceiveAudio: true,
offerToReceiveVideo: true,
});
await peerConnection.value.setLocalDescription(new RTCSessionDescription(sdp));
socketInfo.emit("offer", sdp);
Answer Communication
await peerConnection.setRemoteDescription(new RTCSessionDescription(sdp));
const mySdp = await peerConnection.createAnswer({
offerToReceiveVideo: true,
offerToReceiveAudio: true,
});
await peerConnection.setLocalDescription(new RTCSessionDescription(mySdp));
socketInfo.emit("answer", mySdp);
Establish Communication
一个是己方准备完毕发送出去,一个是监听对方准备完毕
peerConnection.onicecandidate = (e) => {
if (e.candidate) {
socketInfo.emit("candidate", e.candidate);
}
};
socketInfo.on("getCandidate", async candidate => {
await peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
});
可以很明显的看到,其中包含了寻址信息。
Communication Establishment Process
这里展示发起方和应答方和 API Server 沟通的过程。
发起方
应答方
Deploy
至此,通讯创建完成,接着就是部署到服务器上,因为用到了 WebSocket,所以需要配置 Nginx。开发时如果是本机 IP,比如 localhost 是可以调试的,但如果不是本机 IP,就需要支持 HTTPS 的服务器。
以下是简单配置支持,正式部署还需要根据环境进行优化。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location /test/webrtc/api/ {
proxy_pass http://localhost:8088/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}