当前位置: 首页 > news >正文

vue项目基于WebRTC实现一对一音视频通话

效果

前端代码

<template><div class="flex items-center flex-col text-center p-12 h-screen"><div class="relative h-full mb-4 fBox"><video id="localVideo"></video><video id="remoteVideo"></video><div v-if="caller && calling"><p class="mb-4 text-white">等待对方接听...</p><img style="width: 60px;" @click="hangUp" src="@/assets/guaDuang.png" alt=""></div><div v-if="called && calling"><p>收到视频邀请...</p><div class="flex"><img style="width: 60px" @click="hangUp" src="@/assets/guaDuang.png" alt=""><img style="width: 60px" @click="acceptCall" src="@/assets/jieTing.png" alt=""></div></div></div><div><button @click="callRemote" style="margin-right: 10px">发起视频</button><button @click="hangUp" style="margin-left: 10px">挂断视频</button></div></div>
</template>
<script>
import { io, Socket } from "socket.io-client";
let roomId = '001';
export default {name: 'HelloWorld',props: {msg: String},data(){return{wsSocket:null,//实例called:false,// 是否是接收方caller:false,// 是否是发起方calling:false,// 呼叫中communicating:false,// 视频通话中localVideo:null,// video标签实例,播放本人的视频remoteVideo:null,// video标签实例,播放对方的视频peer:null,localStream:null,}},methods:{// 发起方发起视频请求async callRemote(){let that = this;console.log('发起视频');that.caller = true;that.calling = true;// await getLocalStream()// 向信令服务器发送发起请求的事件await that.getLocalStream();that.wsSocket.emit('callRemote', roomId)},// 接收方同意视频请求acceptCall(){console.log('同意视频邀请');this.wsSocket.emit('acceptCall', roomId)},// 挂断视频hangUp(){this.wsSocket.emit('hangUp', roomId)},reset(){this.called = false;this.caller = false;this.calling = false;this.communicating = false;this.peer = null;this.localVideo.srcObject = null;this.remoteVideo.srcObject = null;this.localStream = undefined;console.log('挂断结束视频-------')},// 获取本地音视频流async getLocalStream(){let that = this;let obj = { audio: true, video: true };const stream = await navigator.mediaDevices.getUserMedia(obj); // 获取音视频流that.localVideo.srcObject = stream;that.localVideo.play();that.localStream = stream;return stream;}},mounted() {let that = this;that.$nextTick(()=>{that.localVideo = document.getElementById('localVideo');that.remoteVideo = document.getElementById('remoteVideo');})let sock = io('localhost:3000'); // 对应服务的端口// 连接成功sock.on('connectionSuccess', (sock) => {console.log('连接成功:');});sock.emit('joinRoom', roomId) // 前端发送加入房间事件sock.on('callRemote', (sock) => {// 如果是发送方自己收到这个事件就不用管if (!that.caller){ // 不是发送方(用户A)that.called = true; // 接听方that.calling = true; // 视频通话中}});sock.on('acceptCall',async ()=>{if (that.caller){// 用户A收到用户B同意视频的请求that.peer = new RTCPeerConnection();// 添加本地音视频流that.peer.addStream && that.peer.addStream(that.localStream);// 通过监听onicecandidate事件获取candidate信息that.peer.onicecandidate = (event) => {if (event.candidate) {console.log('用户A获取candidate信息', event.candidate);// 通过信令服务器发送candidate信息给用户Bsock.emit('sendCandidate', {roomId, candidate: event.candidate})}}// 接下来用户A和用户B就可以进行P2P通信流// 监听onaddstream来获取对方的音视频流that.peer.onaddstream = (event) => {console.log('用户A收到用户B的stream',event.stream);that.calling = false;that.communicating = true;that.remoteVideo.srcObject = event.stream;that.remoteVideo.play();}// 生成offerlet offer = await that.peer.createOffer({offerToReceiveAudio: 1,offerToReceiveVideo: 1})console.log('offer', offer);// 设置本地描述的offerawait that.peer.setLocalDescription(offer);// 通过信令服务器将offer发送给用户Bsock.emit('sendOffer', { offer, roomId })}})// 收到offersock.on('sendOffer',async (offer) => {if (that.called){ // 接收方 - 用户Bconsole.log('收到offer',offer);// 创建自己的RTCPeerConnectionthat.peer = new RTCPeerConnection();// 添加本地音视频流const stream = await that.getLocalStream();that.peer.addStream && that.peer.addStream(stream);// 通过监听onicecandidate事件获取candidate信息that.peer.onicecandidate = (event) => {if (event.candidate) {console.log('用户B获取candidate信息', event.candidate);// 通过信令服务器发送candidate信息给用户Asock.emit('sendCandidate', {roomId, candidate: event.candidate})}}// 接下来用户A和用户B就可以进行P2P通信流// 监听onaddstream来获取对方的音视频流that.peer.onaddstream = (event) => {console.log('用户B收到用户A的stream',event.stream);that.calling = false;that.communicating = true;that.remoteVideo.srcObject = event.stream;that.remoteVideo.play();}// 设置远端描述信息await that.peer.setRemoteDescription(offer);let answer = await that.peer.createAnswer();console.log('用户B生成answer',answer);await that.peer.setLocalDescription(answer);// 发送answer给信令服务器sock.emit('sendAnswer', { answer, roomId })}})// 用户A收到answersock.on('sendAnswer',async (answer) => {if (that.caller){ // 接收方 - 用户A   判断是否是发送方// console.log('用户A收到answer',answer);await that.peer.setRemoteDescription(answer);}})// 收到candidate信息sock.on('sendCandidate',async (candidate) => {console.log('收到candidate信息',candidate);// await that.peer.addIceCandidate(candidate) // 用户A和用户B分别收到candidate后,都添加到自己的peer对象上// await that.peer.addCandidate(candidate)await that.peer.addIceCandidate(candidate)})// 挂断sock.on('hangUp',()=>{that.reset()})that.wsSocket = sock;}
}
</script>

服务端代码

const socket = require('socket.io');
const http = require('http');const server = http.createServer()const io = socket(server, {cors: {origin: '*' // 配置跨域}
});io.on('connection', sock => {console.log('连接成功...')// 向客户端发送连接成功的消息sock.emit('connectionSuccess');sock.on('joinRoom',(roomId)=>{sock.join(roomId);console.log('joinRoom-房间ID:'+roomId);})// 广播有人加入到房间sock.on('callRemote',(roomId)=>{io.to(roomId).emit('callRemote')})// 广播同意接听视频sock.on('acceptCall',(roomId)=>{io.to(roomId).emit('acceptCall')})// 接收offersock.on('sendOffer',({offer,roomId})=>{io.to(roomId).emit('sendOffer',offer)})// 接收answersock.on('sendAnswer',({answer,roomId})=>{io.to(roomId).emit('sendAnswer',answer)})// 收到candidatesock.on('sendCandidate',({candidate,roomId})=>{io.to(roomId).emit('sendCandidate',candidate)})// 挂断结束视频sock.on('hangUp',(roomId)=>{io.to(roomId).emit('hangUp')})
})server.listen(3000, () => {console.log('服务器启动成功');
});

完整代码gitee地址: https://gitee.com/wade-nian/wdn-webrtc.git

参考文章:基于WebRTC实现音视频通话_npm create vite@latest webrtc-client -- --template-CSDN博客

http://www.lryc.cn/news/346865.html

相关文章:

  • web 基础之 HTTP 请求
  • 嵌入式 - GPIO编程简介
  • 8种区块链开发者必须知道的顶级编程语言!
  • 十三、Redis哨兵模式--Sentinel
  • [力扣题解]1005. K 次取反后最大化的数组和
  • Web UI自动化测试--PO模式
  • Python进阶之-反射机制详解
  • day05-面向对象内存原理和数组
  • 从头理解transformer,注意力机制(下)
  • ORA-609频繁出现在alert.log,如何解决?
  • JVM 类加载机制
  • 亲测-wordpress文章实时同步发布修改删除多个站点的WP2WP插件
  • npm无法安装node-sass 的问题
  • springboot 引入第三方bean
  • 安装Nginx
  • 爬虫工具you-get
  • hal_stm32_RTC函数
  • 【大数据·Hadoop】从词频统计由浅入深介绍MapReduce分布式计算的设计思想和原理
  • win10建立共享文件夹和ipad共享文件
  • 手机在网状态多方面重要性
  • Multitouch for Mac:手势自定义,提升工作效率
  • IDEA创建springboot项目时不能选择java 8或者java 11等等版本的问题,解决方案
  • SpringCloudAlibaba:4.3云原生网关higress的JWT 认证
  • 【机器学习】Reinforcement Learning-强化学习基本概念
  • vim编辑器---(1)vim编辑器介绍?
  • 解密 Unix 中的 “rc“ 后缀:自定义你的工作环境
  • Java使用csv导出多字段大数据文件(无需写实体映射,自动遍历)
  • Redis 本机无法访问
  • 【论文笔记】Training language models to follow instructions with human feedback B部分
  • stm32——OLED篇