基于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实现信令服务器,敬请期待吧。

相关推荐
q***38513 小时前
SpringBoot + vue 管理系统
vue.js·spring boot·后端
喵个咪3 小时前
go-kratos-admin 快速上手指南:从环境搭建到启动服务(Windows/macOS/Linux 通用)
vue.js·go
用户841794814564 小时前
vxe-gantt table 甘特图如何设置任务视图每一行的背景色
vue.js
小章鱼学前端4 小时前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js
涔溪4 小时前
实现将 Vue3 项目作为子应用,通过无界(Wujie)微前端框架接入到 Vue2 主应用中(Vue2 为主应用,Vue3 为子应用)
vue.js·前端框架·wujie
源码技术栈7 小时前
什么是云门诊系统、云诊所系统?
java·vue.js·spring boot·源码·门诊·云门诊
lcc1877 小时前
Vue3 ref函数和reactive函数
前端·vue.js
艾小码7 小时前
还在为组件通信头疼?defineExpose让你彻底告别传值烦恼
前端·javascript·vue.js
带只拖鞋去流浪7 小时前
迎接2026,重新认识Vue CLI (v5.x)
前端·vue.js·webpack
Coder-coco7 小时前
游戏助手|游戏攻略|基于SprinBoot+vue的游戏攻略系统小程序(源码+数据库+文档)
java·vue.js·spring boot·游戏·小程序·论文·游戏助手