一、引言
最近一段时间在学习前端内容时,需要手写一个视频语音通话功能,在了解到WebRTC可以满足我的需求时,我学习了此技术,并做了简单实现(未使用socket.io等信令交互实现,可以期待我接下来的文章哦~),本篇不会介绍WebRTC的架构,只做简单实现。
二、效果预览
三、什么是WebRTC?
WebRTC (Web Real-Time Communications)是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。具体可查看MDN WebRTC API - Web API 接口参考 | MDN (mozilla.org)
大白话意思就是,我们可以该技术快速地构建出一个音视频通讯的应用。虽然它叫WebRTC,但是实际上它不光支持Web之间的音视频通讯,还支持Android以及IOS端,开源支持,这里不做过多赘述,详情可以前往官网了解。
四、如何实现?(实现思路)
1.初始化本地流媒体 2.实例化两个RTCPeerConnection
对象。
3.添加彼此为ICE candidates。
4.对本地对象(localVideo)使用createoffer
建立请求。
5.对两个对象设置本地/远程'描述'。
6.对第远程对象(remoteVideo)createAnswer
。
7.对两个对象设置远程/本地'描述'。
8.进行直接交流。
五、具体代码实现
知道思路之后下面就开始正式代码实现了~
前端实现
这里使用到的预处理器是Scss,组件库是Element Plus
网页骨架部分
html
<template lang="">
<!-- 视频通话组件 -->
<div class="video-set" v-if="showVideo">
//video标签中muted启用静音,playsinline启用视频将内联(inline)播放,即在元素的播放区域内。
//本地视频
<video
autoplay
ref="localVideo"
id="localVideo"
muted
playsinline
class="local"
></video>
//远端视频
<video
autoplay
ref="remoteVideo"
id="remoteVideo"
playsinline
class="remote"
></video>
</div>
<el-button @click="call">发起视频通话</el-button>
<el-button @click="cancel">挂断</el-button>
</template>
样式部分
css
<style lang="scss" scoped>
.video-set {
position: relative;
video {
width: 270px;
height: 202.5px;
background-color: #fff;
border-radius: 10px;
}
.local {
background-color: #fff;
width: 90px;
height: 120px;
position: absolute;
left: 7.5px;
top: 7.5px;
border: 2px solid gray;
object-fit: cover;
// background-color: transparent;
}
.remote {
}
}
</style>
逻辑实现
实例化两个RTCPeerConnection对象
js
import { ref } from "vue";
let localVideo = ref();
let remoteVideo = ref();
let localStream = ref(null);
//默认不显示视频通话(需拨通后显示)
let showVideo = ref(false);
初始化本地流
js
const initLocalStream = () => {
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true,
})
.then((stream) => {
startLink(stream);//获取成功后调用开始连接的函数
})
.catch((e) => {
alert("getUserMedia() error:" + e.name);
});
};
模拟信令交互过程
js
const startLink = (stream) => {
// console.log("获取stream成功!");
//本地画面预览
localVideo.value.srcObject = stream;
localStream.value = stream;
//为彼此添加ice candidate
localPc.onicecandidate = (e) => {
remotePc.addIceCandidate(e.candidate);
};
remotePc.onicecandidate = (e) => {
localPc.addIceCandidate(e.candidate);
};
//提供远端画面
remotePc.ontrack = (e) => {
remoteVideo.value.srcObject = e.streams[0];
// console.log('test success');
};
//将音视频逐一添加到本地流
localStream.value.getTracks().forEach((track) => {
localPc.addTrack(track, localStream.value);
// console.log('test success');
});
//设定offer选项
let offerOptions = {
offerToRecieveAudio: 1,
offerToRecieveVideo: 1,
};
//创建本地连接的offer,用于媒体协商
localPc.createOffer(offerOptions).then((desc) => {
//创建成功后会返回一个本地描述,并在这里设置本地描述
localPc.setLocalDescription(desc);
// console.log('send desc to signal');
// console.log('receive desc from signal');
// 设置远程描述
remotePc.setRemoteDescription(desc);
//创建远端描述回复
remotePc.createAnswer().then((desc) => {
//对两个对象设置远程/本地'描述'
remotePc.setLocalDescription(desc);
// console.log('send desc to signal');
// console.log('receive desc from signal');
localPc.setRemoteDescription(desc);
});
});
};
开始视频通话
js
const call = () => {
showVideo.value = true;
initLocalStream();
};
const cancel = () => {
localPc.close();
remotePc.close();
if (remoteVideo.value.srcObject) {
remoteVideo.value.srcObject.getTracks().forEach((track) => track.stop());
// console.log("关闭成功");
}
if (localVideo.value.srcObject) {
localVideo.value.srcObject.getTracks().forEach((track) => track.stop());
// console.log("关闭成功");
}
showVideo.value = false;
};
六、总结
本文为你介绍了如何基于 WebRTC 简单实现一个 1v1
本机内音视频通话demo。
请注意,本文介绍的只是WebRTC简化应用,若您需要更加复杂的使用场景,您可以进一步了解WebRTC。通过本教程,您应该对如何使用 WebRTC 构建 1v1 音视频通话系统有了更深入的了解。 到此,1v1本机内音视频通话系统我们已经实现完了,下一篇会介绍P2P音视频实现方案,主要使用到socket.io实现信令服务器,敬请期待吧。