引言
在之前一篇文章写了webrtc实现基本的本地1对1视频通讯,这一篇文章则实现现实网络中一对一视频聊天。
目标
思考
- webrtc实现点对点通信的基础是目标和自己之间能够建立网络链接,那么如何建立链接呢?
- 本地点对点视频为何无需交换所谓的信令能够直接实现视频通信?
解答
webrtc 之所以能够实现一个浏览器到另一个远程浏览器的通讯,最基本的还是要靠所谓的
信息交换服务器
在上一节中是实现本地视频通信时因为我直接将交换的信息赋值给另一个变量,但是在远程网络链接中是不行的,一个用户发出的信号是一定要通过
中间商
发送到另一个用户浏览器然后赋值的。
代码实现步骤
概述
首先要通信那就得满足通信的基础,我选择和目标放通信,前提就是我通过一定的条件将自己和目标建立链接,然后再将自己的通信信息交给目标,目标也同时将自己的信息发给我。
基础流程
-
选择视频通话对象,同时打开本地自己的摄像头(目的是本地创建视频流,这个视频流是要发送给对方的)
-
初始化双方链接的基础
PeerConnection
-
开始创建链接基础信息,这一步就开始正式建立和对方的通信基础(创建完成后本地保存一份
offer
) -
目标对象通过服务器接收到远程发送的
offer
,并在目标方创建应答answer
,本地保存应答
后发送给原来发offer
的用户 -
本地接受到目标返回的
应答
,并添加到本地远程描述中 -
监听ICE候选信息(这个过程是在发送
offer
和创建应答之间的)
步骤代码
- 选择视频通话对象,同时打开本地自己的摄像头(目的是本地创建视频流,这个视频流是要发送给对方的)
async createMedia() {
const that = this;
let streamTep = null;
console.log("start prepare localStream origin")
if( !navigator.mediaDevices || !navigator.mediaDevices.getUserMedia ){
that.$message.error("设备不支持")
console.log('getUserMedia is not support!')
}
await navigator.mediaDevices.getUserMedia({audio: true, video: true})
.then(function (mediaStream) {
console.log("mediaStream",mediaStream)
// //eslint-disable-next-line no-debugger
// debugger
streamTep = mediaStream;
}).catch(error=>{
console.log("获取媒体设备异常",error)
that.$message.warning("获取媒体设备异常")
})
return streamTep;
},
- 初始化双方链接的基础
PeerConnection
//初始化 PeerConnection
initPeer(){
const that = this;
that.pc = new PeerConnection(this.iceServers);
that.pc.addStream(this.localStream);
that.pc.onicecandidate = function(event) {
console.log("监听ice候选信息",event.candidate)
if (event.candidate) {
//通过服务器将ICE候选信息发送到视频通话目标对象)
let params ={username:that.username,target:that.remoteAccount,candidate:event.candidate}
console.log("info",params)
that.socket.emit("candidate",params)
}else{
console.log("ICE收集已经完成")
}
};
that.pc.onaddstream = (event) => {
console.log("监听到视频加入 onaddstream",event)
//将视频流赋值到某个video标签中(这里就是监听到的对方的视频流,这也就是为什么第一步要创建本地视频流的原因)
that.createEleVideo(event.stream,that.remoteAccount)
};
},
- 开始创建链接,这一步就开始正式建立和对方的通信基础(创建完成后本地保存一份
offer
)
async onCreateOffer() {
const that = this;
//创建offer
let offer_tep = await that.pc.createOffer(this.offerOption);
console.log("呼叫端 offer",offer_tep)
//设置本地描述
await that.pc.setLocalDescription(offer_tep)
//远程发送到服务器
let params = {username:that.username,target:that.remoteAccount,offer:offer_tep}
that.socket.emit("offer",params)
},
- 目标对象通过服务器接收到远程发送的
offer
,并在目标方创建应答answer
,本地保存应答
后发送给给自己发offer
的用户
//监听远端offer
async onOffer(data) {
const that = this;
await that.pc.setRemoteDescription(data.offer)
// 接收端创建 answer
let answer = await that.pc.createAnswer();
// 接收端设置本地 answer 描述
await that.pc.setLocalDescription(answer);
//发送到呼叫端 answer
let params = {username:that.username,target:that.remoteAccount,answer:answer}
that.socket.emit("answer",params)
},
- 本地接受到目标返回的
应答
,并添加到本地远程描述中
//监听远程响应
async onAnswer(data) {
const that = this;
// 发送端 设置远程 answer 描述
await that.pc.setRemoteDescription(data.answer);
},
- 监听ICE候选信息(这个过程是在发送offer和创建应答之间的),引用MDN上的话
ICE候选人描述了WebRTC能够与远程设备进行通信所需的协议和路由。在开始WebRTC对等连接时,通常在连接的每一端都建议多个候选对象,直到他们彼此同意描述他们认为最好的连接的候选对象为止。然后,WebRTC使用该候选人的详细信息来发起连接。
上述代码流程中具体执行实际演示
- 发送端即呼叫方流程:
- 目标方执行演示
后续
- 本文是webrtc实现群聊系列文章的第二篇,持续更新中
- 关注我的公众号及时获取最新文章更新