WebRTC 在创建点对点(P2P)的连接之前,会先通过信令服务器交换两端的 SDP 和 ICE Candidate,取两者的交集,决定最终的音视频参数、传输协议、NAT 打洞方式等信息 。
在完成媒体协商,并且两端网络连通之后,就可以开始传输数据了 。
本文示例代码已上传至 Github,有需要的可以随意下载 。
一、术语在实现一个简单的视频通话之前,还需要了解一些相关术语 。
1)SDP
SDP(Session Description Protocal)是一个描述会话元数据(Session Metadata)、网络(Network)、流(Stream)、安全(Security)和服务质量(Qos,Grouping)的 WebRTC协议,下图是 SDP 各语义和字段之间的包含关系 。
换句话说,它就是一个用文本描述各端能力的协议,这些能力包括支持的音视频编解码器、传输协议、编解码器参数(例如音频通道数 , 采样率等)等信息 。
文章插图
下面是一个典型的 SDP 信息示例,其中 RTP(Real-time Transport Protocol)是一种网络协议,描述了如何以实时方式将各种媒体从一端传输到另一端 。
=================会话描述======================v=0o=alice 2890844526 2890844526 IN IP4 host.anywhere.coms=-=================网络描述======================c=IN IP4 host.anywhere.comt=0 0================音频流描述=====================m=audio 49170 RTP/AVP 0a=rtpmap:0 PCMU/8000================视频流描述=====================m=video 51372 RTP/AVP 31a=rtpmap:31 H261/900002)ICE Candidate
ICE 候选者描述了 WebRTC 能够与远程设备通信所需的协议、IP、端口、优先级、候选者类型(包括 host、srflx 和 relay)等连接信息 。
host 是本机候选者 , srflx 是从 STUN 服务器获得的候选者,relay 是从 TURN 服务器获得的中继候选者 。
在每一端都会提供许多候选者,例如有两块网卡,那么每块网卡的不同端口都是一个候选者 。
WebRTC 会按照优先级倒序的进行连通性测试,当连通性测试成功后,通信的双方就建立起了连接 。
3)NAT打洞
在收集到候选者信息后,WebRTC 会判断两端是否在同一个局域网中,若是,则可以直接建立链接 。
若不是,那么 WebRTC 就会尝试 NAT 打洞 。WebRTC 将 NAT 分为 4 种类型:完全锥型、IP 限制型、端口限制型和对称型 。
前文候选者类型中曾提到 STUN 和 TURN 两种协议,接下来会对它们做简单的说明 。
STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,允许位于 NAT 后的客户端找出自己的公网地址,当前 NAT 类型和 NAT 为某一个本地端口所绑定的公网端口 。
这些信息让两个同时处于 NAT 路由器之后的主机之间建立 UDP 通信,STUN 是一种 Client/Server 的协议 , 也是一种 Request/Response 的协议 。
下图描绘了通过 STUN 服务器获取公网的 IP 地址 , 以及通过信令服务器完成媒体协商的简易过程 。
文章插图
TURN(Traversal Using Relay NAT,通过 Relay 方式穿越 NAT),是一种数据传输协议,允许通过 TCP 或 UDP 穿透 NAT 。
TURN 也是一个 Client/Server 协议,其穿透方法与 STUN 类似 , 但终端必须在通讯开始前与 TURN 服务器进行交互 。
下图描绘了通过 TURN 服务器实现 P2P 数据传输 。
文章插图
CoTurn 是一款免费开源的 TURN 和 STUN 服务器,可以到 GitHub 上下载源码编译安装 。
二、信令服务器通信双方彼此是不知道对方的,但是它们可以先与信令服务器(Signal Server)连接 , 然后通过它来互传信息 。
可以将信令服务器想象成一个中间人 , 由他来安排两端进入一个房间中 , 然后在房间中可以他们就能随意的交换手上的情报了 。
本文会通过 Node.js 和 socket.io 实现一个简单的信令服务器,完成的功能仅仅是用于实验,保存在 server.js 文件中 。
如果对 socket.io 不是很熟悉,可以参考我之前分享的一篇博文,对其有比较完整的说明 。
1)HTTP 服务器
为了实现视频通话的功能,需要先搭建一个简易的 HTTP 服务器,挂载静态页面 。
注意,在实际场景中,这块可以在另一个项目中执行,本处只是为了方便演示 。
const http = require('http');const fs = require('fs');const { Server } = require("socket.io");// HTTP服务器const server = http.createServer((req, res) => {// 实例化 URL 类const url = new URL(req.url, 'http://localhost:1234');const { pathname } = url;// 路由if(pathname === '/') {res.writeHead(200, { 'Content-Type': 'text/html' });res.end(fs.readFileSync('./index.html'));}else if(pathname === '/socket.io.js') {res.writeHead(200, { 'Content-Type': 'application/javascript' });res.end(fs.readFileSync('./socket.io.js'));}else if(pathname === '/client.js') {res.writeHead(200, { 'Content-Type': 'application/javascript' });res.end(fs.readFileSync('./client.js'));}});// 监控端口server.listen(1234);
推荐阅读
- 从 Wepy 到 UniApp 变形记
- 之六 2流高手速成记:从SpringBoot到SpringCloudAlibaba
- Windows下自动云备份思源笔记到Gitee
- 2 我的牙套日记
- 电脑开不了机怎么办简单方法(笔记本电脑开不了机)
- windows启动不了开不了机怎么办(笔记本无法启动windows)
- 记录在linux上单机elasticsearch8和kibana8
- 电脑运行了但开不了机怎么办(笔记本电脑冻了一晚开不了机)
- 神仙记事录司铎线怎么选择
- 神仙记事录程煌线怎么选择