前面我们已经实现过,但是没有详细说HTTPS服务
首先需要引入了 express
库,它的功能非常强大,用它来实现 Web 服务器非常方便
同时还需要引入 HTTPS
服务,并让 Web 服务运行于 HTTPS 之上即可
var https = require('https');var express = require('express');var serveIndex = require('serve-index');// 使用 express 实现 WEB 服务var app = express(); app.use(serveIndex('./public'));app.use(express.static('./public'));//HTTPS 证书和密钥文件var options = { key : fs.readFileSync('./cert/www.autofelix.cn.key'), cert: fs.readFileSync('./cert/www.autofelix.cn.pem')}//https servervar https_server = https.createServer(options, app);var io = socketIo.listen(https_server);https_server.listen(443, '0.0.0.0');
信令系统超级重要,直播系统中,由谁来发起呼叫、什么时间发 SDP 等各种操作都是由信令控制的
客户端命令︰join
用户加入房间、leave
用户离开房间、message
端到端命令
服务端命令︰joined
用户已加入、leaved
用户已离开、other_joined
其他用户已加入、bye其他用户已离开、full
房间已满
在初始时,客户端处于 init/leaved
状态,在该状态下用户只能发送 join 消息
服务端收到 join 消息后,会返回 joined 消息,此时客户端为 joined 状态
如果用户离开房间,那客户端又回到了初始状态
如果客户端收到 second user join
消息,则切换到 joined_conn
状态,该状态下可以进行通话
如果客户端收到 second user leave
消息,则切换到 joined_unbind
状态,该状态与 joined 状态基本一致
其中最重要的 TURN 服务。它有两个作用,一是提供 STUN 服务,客户端可以通过 STUN 服务获取自己的外网地址;二是提供数据中继服务
目前最著名的 TURN 服务器是由 Google 发起的开源项目 coturn
︰https://github.com/coturn/coturn
coturn 的编译安装与部署步骤如下︰
// 下载源码git clone https://github.com/coturn/coturn.git// 编译, 生成 Makefile./configure --prefix=/usr/local/coturn// 安装make && make install// 关于 coturn 服务配置listening-port=3478 // 指定侦听的端口external-ip=147.104.34.27 // 指定云主机的公网ip地址user=username:password // 访问stun/turn服务的用户名和密码realm=stun.xxx.cn // 域名,这个必须设置
第一步通过 getUserMedia 就可以获取到音视频数据
以前是在浏览器显示页面时就开始采集,而现在则是在用户点击 Connect Sig Server
按钮时才开始采集音视频数据
信令系统建立好后,后面的逻辑都是围绕着信令系统建立起来的,RTCPeerConnection
对象也不例外
在客户端,用户要想与远端通话,首先要发送 join 消息,也就是要先进入房间,如果服务器判定用户是合法的,则会给客户端回 joined 消息
客户端收到 joined 消息后,就要创建 RTCPeerConnection 对象了,也就是要建立一条与远端通话的音视频数据传输通道
我们需要设置 TURN 服务器地址、用户名和密码,这样当 RTCPeerConnection 通过 P2P 建立连接失败时,就会使用 TURN 服务器进行数据中继
RTCPeerConnection
对象创建好后,我们要将前面获取的音视频数据与它绑定到一起,这样才能通过 RTCPeerConnection
对象将音视频数据传输出去
var pcConfig = { 'iceServers': [{ // 指定 ICE 服务器信令 'urls': 'turn:stun.al.learningrtc.cn:3478', //turn 服务器地址 'credential': "passwd", //turn 服务器密码,你要用自己的 'username': "username" //turn 服务器用户名,你要用自己的 }]};function createPeerConnection(){ if(!pc){ pc = new RTCPeerConnection(pcConfig); // 创建 peerconnection 对象 pc.ontrack = getRemoteStream; // 当远端的 track 到来时会触发该事件 }else { console.log('the pc have be created!'); } return;}// 将获取的音视频数据与 RTCPeerConnection 绑定到一起function bindTracks(){ //add all track into peer connection localStream.getTracks().forEach((track)=>{ pc.addTrack(track, localStream); // 将 track 与 peerconnection 绑定 });}
按照上面的步骤,音视频数据就可以被采集到了,RTCPeerConnection
对象也创建好了,通过信令服务器也可以将各端的 Candidate
交换完成了
此时在 WebRTC 的底层就会进行连通性检测,它首先判断通信的双方是否在同一个局域网内
如果在同一个局域网内,则让双方直接进行连接
如果不在同一局域网内,则尝试用P2P 连接
如果仍然不成功,则使用 TURN 服务进行数据中继
一旦数据连通后,数据就从一端源源不断地传到了远端,此时远端只需要将数据与播放器对接,就可以看到对端的视频、听到对方的声音了
当数据流过来的时候会触发 RTCPeerConnection
对象的 ontrack
事件
只要我们侦听该事件,并在回调函数中将收到的 track
与 <video>
标签绑定到一起即可
var remoteVideo = document.querySelector('video#remotevideo');pc = new RTCPeerConnection(pcConfig);pc.ontrack = getRemoteStrea // 当远端的 track 过来时触发该事件function getRemoteStream(e){ // 事件处理函数 remoteStream = e.streams[0]; // 保存远端的流 remoteVideo.srcObject = e.streams[0]; // 与 HTML 中的视频标签绑定}