8┃音视频直播系统之 WebRTC 信令系统实现以及通讯核心并实现视频通话
一、信令系统
-
信令系统主要用来进行信令的交换
-
在通信双方彼此连接、传输媒体数据之前,它们要通过信令服务器交换一些信息,如规范协商
-
若 A 与 B 要进行音视频通信,那么 A 要知道 B 已经上线了,同样,B 也要知道 A 在等着与它通信呢
-
只有双方都知道彼此存在,才能由一方向另一方发起音视频通信请求,并最终实现音视频通话
-
客户端代码如下:
-
第一步:首先弹出一个输入框,要求用户写入要加入的房间
-
第二步:通过
io.connect()
建立与服务端的连接 -
第三步:再根据
socket
返回的消息做不同的处理
信令系统
-
服务端代码如下:
-
需要通过
npm install socket.io
安装socket模块 -
需要通过
npm install node-static
安装socket模块,使服务器具有发布静态文件的功能 -
服务端侦听 2022 这个端口,对不同的消息做相应的处理
const static = require('node-static');
const http = require('http');
const file = new (static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2022);
// 侦听 2022
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// convenience function to log server messages to the client
function log() {
const array = ['>>> Message from server: '];
for (var i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
// 收到 message 时,进行广播
log('Got message:', message);
// for a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message); // 在真实的应用中,应该只在房间内广播
});
socket.on('create or join', (room) => {
// 收到 “create or join” 消息
var clientsInRoom = io.sockets.adapter.rooms[room];
var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0) {
// 如果房间里没人
socket.join(room);
// 发送 "created" 消息
socket.emit('created', room);
} else if (numClients === 1) {
// 如果房间里有一个人
io.sockets.in(room).emit('join', room);
socket.join(room);
// 发送 “joined”消息
socket.emit('joined', room);
} else {
// max two clients
// 发送 "full" 消息
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id + ' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id + ' joined room ' + room);
});
});
二、RTCPeerConnection
-
RTCPeerConnection
类是在浏览器下使用 WebRTC 实现 1 对 1 实时互动音视频系统最核心的类 -
它是WebRTC传输音视频和交换数据的API
-
RTCPeerConnection
就与普通的 socket 一样,在通话的每一端都至少有一个RTCPeerConnection 对象。在 WebRTC 中它负责与各端建立连接,接收、发送音视频数据,并保障音视频的服务质量
三、实现视频通话
-
为连接的每个端创建一个
RTCPeerConnection
对象,并且给RTCPeerConnection
对象添加一个本地流,该流是从getUserMedia()
获取的 -
获取本地媒体描述信息,即 SDP 信息,并与对端进行交换
-
获得网络信息,即
Candidate(IP 地址和端口)
,并与远端进行交换
实现视频通话
四、视频通话流程详解
-
视频通话本是不同的端与端连接,上面的代码在同一个浏览器中模拟多端连接的情况,可以通过开两个标签页,来模拟pc1端和pc2端
-
所以大家会看到两个视频是一摸一样的,但是它的整个底层都是从本机自己IO的那个逻辑网卡转过来的
-
当调用 call 的时候就会调用双方的
RTCPeerConnection
-
当这个两个
PeerConnection
创建完成之后,它们会作协商处理 -
协商处理完成之后进行
Candidate
采集,也就是说有效地址的采集 -
采集完了之后进行交换,然后形成这个
Candidate pair
再进行排序 -
然后再进行连接性检测,最终找到最有效的那个链路
-
之后就将 localVideo 展示的这个数据通过
PeerConnection
传送到另一端 -
另一端收集到数据之后会触发
onAddStream
或者onTrack
就是说明我收到数据了,那当收到这个事件之后 -
我们再将它设置到这个
remoteVideo
里面去 -
这样远端的这个
video
就展示出来了,显示出我们本地采集的数据了