WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。
在WebRTC的API中,有三个核心知识点,分别为:
1. MediaStream:获取音频和视频流
2. RTCPeerConnection:音频和视频数据流
3. RTCDataChannel:任意应用数据通信
1、视频会议首先得采集本地摄像头和麦的媒体数据,也就是MediaStream。方法非常简单,直接使用浏览器api:
2、获取到了本地的音视频流接下来的事情就是如何将本地的音视频流与对方的音视频流进行交换传输了。这时我们就需要使用到RTCPeerConnection了,与传统的client与server连接不同,他专门负责帮咱们建立client与client之间的连接,因为咱们是即时通信,重在即时上,如果client与client之间视频聊天,中间还夹个server,那不就不即时了吗,沟通岂能畅快。但是问题来了,一般我们的server是带公网IP的,可以直接与其进行连接,但是client与client建立连接难点在于我怎么知道对方的公网IP呢,这里就需要解决NAT穿透问题了。如果不解决你会发现你的视频会议只能在局域网中进行,一出局域网就废了,如果限定在局域网内那还开啥视频会议,直接去会议室开会不更香吗。
3、解决NAT穿透问题,需要了解三个新成员:ICE,STUN和TURN。
ICE:(Interactive Connectivity Establishment)交互连接建立,由于client与client之间存在防火墙和NAT设备阻隔,因为我们需要一种机制来收集两端之间的公共线路IP,这就是ICE专门做的事情。
STUN服务器:专门获取内网设备所映射的公网IP和端口,所以ICE首先会先查询STUN服务器,看能不能通过获取到client对应的公网IP及端口来直接建立连接,如果可以连接就搞定收工。
TURN服务器:当STUN服务器获取的公网IP和端口无法建立连接时,这种情况多出现在电信,移动,联通这些运营商NAT策略不同,导致获取到的公网IP和端口是实时变化的,从而无法建立端对端的连接,此时兜底的方法就是使用TURN服务器进行媒体数据转发。
综上所述,我们了解到:STUN和TURN必须是部署在外网服务器上,客户端必须能直接访问到。如果只部署了STUN,有可能出现移动用户无法与联通用户进行视频聊天等跨运营商的连接问题。
了解了基本的知识点后,我们看一下整个WebRTC的原理图:
1、连接双方(Peer也就是RTCPeerConnection)通过第三方服务器来交换各自的SessionDescription数据(这个数据可以理解为Peer的身份证信息)
2、连接双方(Peer)通过STUN服务器那里获取到自己NAT穿透结构,子网IP和公网IP及端口等信息,这里的统称为:ICE Candidate
3、连接双方(Peer)通过第三方服务器交换ICE Candidate,这样双方各自就都有对方的公网IP和端口了,此时就可以建立连接了
4、如果上面获取到的ICE Candidate无法建立连接,也就是前面提到的跨运营商问题,那么ICE就会去找TURN服务器帮忙,让TURN服务器帮我们转发媒体流。
通过知识点简单中的第1步我们已经获取到了本地的音视频流了。接下来我们看一下是如何通过WebRTC的API来进行视频聊天了。
1、本地创建一个RTCPeerConnection实例,准备和对方建立连接:
let rtcPeerConnection = new RTCPeerConnection({
"iceServers":[{
"url": "stun:stun.l.google.com:19302"
},{
"url": "turn:服务器IP",
"credential":"密码",
"username":"账号"
}]
});
//监听stun返回的NAT穿透信息:ICECandidate
rtcPeerConnection.onicecandidate = (event) => {
//如果获取到了我的NAT穿透消息,则立马通过websocket将event.candidate传送到对方。一旦双方通过candidate成功建立连接,就会通过下面这个监听进行音视频流的传输。
wx.send(event.candidate)
}
//监听传输轨道的传输数据
rtcPeerConnection.ontrack = (event) => {
//通过event.streams就能获取到对方传送过来的音视频流,将他再添加到另一个video标签上,就是可以看到对方的画面啦
let remoteVideo = document.getElementById("对方video标签的id");
remoteVideo.srcObject = event.streams[0];
remoteVideo.play();
}
//这里的localVideo是知识点解析的第1步获取到的本地音视频video标签,将他的流加入到传输轨道,连接一旦建立就立马触发ontrack事件,将本地的音视频流传到对方。
for (const track of localVideo.stream.getTracks()) {
rtcPeerConnection.addTrack(track, this.videos[0].stream);
}
2、有了peer后,我们就可以邀请对方进行视频会议了,也就是向对方发起offer
rtcPeerConnection.createOffer({iceRestart: true, offerToReceiveAudio: true, offerToReceiveVideo: true}).then(
(sessionDescription) => {
rtcPeerConnection.setLocalDescription(sessionDescription)
//这里还需要将sessionDescription通过websocket发送给对方,对方才能收到视频邀请
wx.send(sessionDescription)
}
)
3、如果对方收到了offer,那么就设置对方sessionDescription,并回传一个应答answer
//这里的sessionDescription是通过offer传过来的
rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(sessionDescription));
rtcPeerConnection.createAnswer({iceRestart: true, offerToReceiveAudio: true, offerToReceiveVideo: true}).then(
(sessionDescription) => {
rtcPeerConnection.setLocalDescription(sessionDescription)
//这里将sessionDescription通过websocket回传给邀请方
wx.send(sessionDescription)
}
)
4、发送方收到了answer应答后也同样设置对方sessionDescription
//这里的sessionDescription是通过应答传过来的
rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(sessionDescription));
5、当STUN服务器获取到icecandidate后并通过websocket传过来了,我们就需要将对方candidate设置一下,对应第一步的onicecandidate监听事件
rtcPeerConnection.addIceCandidate(candidate)
到这里,我们的视频聊天前端部分功能就搭建完成了。效果如下图,获取完整代码或在线体验可以下载app
最大的问题就是跨运营商NAT穿透问题,那么我们就来搭建自己的STUN和TURN服务器。既然WebRTC是谷歌开源的,那么同样,他也开源了STUN和TURN服务程序,下载地址,选择最新版本下载即可。
1、下载后解压执行编译安装
# wget http://turnserver.open-sys.org/downloads/v4.5.1.3/turnserver-4.5.1.3.tar.gz
# tar -xvf turnserver-4.5.1.3.tar.gz
# cd turnserver-4.5.1.3
# yum install -y libevent libevent-devel
# ./configure
# make && make install
2、安装成功后,配置文件的目录在:/usr/local/share/examples/turnserver/etc
我们需要修改配置文件:turnserver.conf
listening-ip=0.0.0.0
relay-ip=0.0.0.0
external-ip=公网ip
cli-ip=0.0.0.0
userdb=/var/db/turndb #在此文件中添加账号密码格式:admin:123456
no-tcp
no-tls
3、启动turn服务命令
# cd turnserver下载解压的bin目录下
# turnserver -v -r 公网IP:3478 -a -o -c /usr/local/share/examples/turnserver/etc/turnserver.conf
4、如果使用的云服务器,记录开放端口,否则就白折腾了
tcp 5766
udp 3478 5349 49152-65535
可以下载APP亲自体验一下哦: