基于WebRTC在Vue3中实现机内1v1机内视频通话

一、引言

最近一段时间在学习前端内容时,需要手写一个视频语音通话功能,在了解到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实现信令服务器,敬请期待吧。

相关推荐
四喜花露水34 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
程序员爱技术5 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
cs_dn_Jie10 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic10 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿11 小时前
webWorker基本用法
前端·javascript·vue.js
customer0811 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
getaxiosluo12 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v12 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
栈老师不回家13 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙13 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js