ToB企服应用市场:ToB评测及商务社交产业平台

标题: vue项目基于WebRTC实现一对一音视频通话 [打印本页]

作者: 熊熊出没    时间: 2024-7-10 22:18
标题: vue项目基于WebRTC实现一对一音视频通话
效果


前端代码

  1. <template>
  2.   <div class="flex items-center flex-col text-center p-12 h-screen">
  3.     <div class="relative h-full mb-4 fBox">
  4.       <video id="localVideo"></video>
  5.       <video id="remoteVideo"></video>
  6.       <div v-if="caller && calling">
  7.         <p class="mb-4 text-white">等待对方接听...</p>
  8.         <img style="width: 60px;" @click="hangUp" src="@/assets/guaDuang.png" alt="">
  9.       </div>
  10.       <div v-if="called && calling">
  11.         <p>收到视频邀请...</p>
  12.         <div class="flex">
  13.           <img style="width: 60px" @click="hangUp" src="@/assets/guaDuang.png" alt="">
  14.           <img style="width: 60px" @click="acceptCall" src="@/assets/jieTing.png" alt="">
  15.         </div>
  16.       </div>
  17.     </div>
  18.     <div>
  19.       <button @click="callRemote" style="margin-right: 10px">发起视频</button>
  20.       <button @click="hangUp" style="margin-left: 10px">挂断视频</button>
  21.     </div>
  22.   </div>
  23. </template>
复制代码
  1. <script>
  2. import { io, Socket } from "socket.io-client";
  3. let roomId = '001';
  4. export default {
  5.   name: 'HelloWorld',
  6.   props: {
  7.     msg: String
  8.   },
  9.   data(){
  10.     return{
  11.       wsSocket:null,//实例
  12.       called:false,// 是否是接收方
  13.       caller:false,// 是否是发起方
  14.       calling:false,// 呼叫中
  15.       communicating:false,// 视频通话中
  16.       localVideo:null,// video标签实例,播放本人的视频
  17.       remoteVideo:null,// video标签实例,播放对方的视频
  18.       peer:null,
  19.       localStream:null,
  20.     }
  21.   },
  22.   methods:{
  23.     // 发起方发起视频请求
  24.     async callRemote(){
  25.       let that = this;
  26.       console.log('发起视频');
  27.       that.caller = true;
  28.       that.calling = true;
  29.       // await getLocalStream()
  30.       // 向信令服务器发送发起请求的事件
  31.       await that.getLocalStream();
  32.       that.wsSocket.emit('callRemote', roomId)
  33.     },
  34.     // 接收方同意视频请求
  35.     acceptCall(){
  36.       console.log('同意视频邀请');
  37.       this.wsSocket.emit('acceptCall', roomId)
  38.     },
  39.     // 挂断视频
  40.     hangUp(){
  41.       this.wsSocket.emit('hangUp', roomId)
  42.     },
  43.     reset(){
  44.       this.called = false;
  45.       this.caller = false;
  46.       this.calling = false;
  47.       this.communicating = false;
  48.       this.peer = null;
  49.       this.localVideo.srcObject = null;
  50.       this.remoteVideo.srcObject = null;
  51.       this.localStream = undefined;
  52.       console.log('挂断结束视频-------')
  53.     },
  54.     // 获取本地音视频流
  55.     async getLocalStream(){
  56.       let that = this;
  57.       let obj = { audio: true, video: true };
  58.       const stream = await navigator.mediaDevices.getUserMedia(obj); // 获取音视频流
  59.       that.localVideo.srcObject = stream;
  60.       that.localVideo.play();
  61.       that.localStream = stream;
  62.       return stream;
  63.     }
  64.   },
  65.   mounted() {
  66.     let that = this;
  67.     that.$nextTick(()=>{
  68.       that.localVideo = document.getElementById('localVideo');
  69.       that.remoteVideo = document.getElementById('remoteVideo');
  70.     })
  71.     let sock = io('localhost:3000'); // 对应服务的端口
  72.     // 连接成功
  73.     sock.on('connectionSuccess', (sock) => {
  74.       console.log('连接成功:');
  75.     });
  76.     sock.emit('joinRoom', roomId) // 前端发送加入房间事件
  77.     sock.on('callRemote', (sock) => {
  78.       // 如果是发送方自己收到这个事件就不用管
  79.       if (!that.caller){ // 不是发送方(用户A)
  80.         that.called = true; // 接听方
  81.         that.calling = true; // 视频通话中
  82.       }
  83.     });
  84.     sock.on('acceptCall',async ()=>{
  85.       if (that.caller){
  86.         // 用户A收到用户B同意视频的请求
  87.         that.peer = new RTCPeerConnection();
  88.         // 添加本地音视频流
  89.         that.peer.addStream && that.peer.addStream(that.localStream);
  90.         // 通过监听onicecandidate事件获取candidate信息
  91.         that.peer.onicecandidate = (event) => {
  92.           if (event.candidate) {
  93.             console.log('用户A获取candidate信息', event.candidate);
  94.             // 通过信令服务器发送candidate信息给用户B
  95.             sock.emit('sendCandidate', {roomId, candidate: event.candidate})
  96.           }
  97.         }
  98.         // 接下来用户A和用户B就可以进行P2P通信流
  99.         // 监听onaddstream来获取对方的音视频流
  100.         that.peer.onaddstream = (event) => {
  101.           console.log('用户A收到用户B的stream',event.stream);
  102.           that.calling = false;
  103.           that.communicating = true;
  104.           that.remoteVideo.srcObject = event.stream;
  105.           that.remoteVideo.play();
  106.         }
  107.         // 生成offer
  108.         let offer = await that.peer.createOffer({
  109.           offerToReceiveAudio: 1,
  110.           offerToReceiveVideo: 1
  111.         })
  112.         console.log('offer', offer);
  113.         // 设置本地描述的offer
  114.         await that.peer.setLocalDescription(offer);
  115.         // 通过信令服务器将offer发送给用户B
  116.         sock.emit('sendOffer', { offer, roomId })
  117.       }
  118.     })
  119.     // 收到offer
  120.     sock.on('sendOffer',async (offer) => {
  121.       if (that.called){ // 接收方 - 用户B
  122.         console.log('收到offer',offer);
  123.         // 创建自己的RTCPeerConnection
  124.         that.peer = new RTCPeerConnection();
  125.         // 添加本地音视频流
  126.         const stream = await that.getLocalStream();
  127.         that.peer.addStream && that.peer.addStream(stream);
  128.         // 通过监听onicecandidate事件获取candidate信息
  129.         that.peer.onicecandidate = (event) => {
  130.           if (event.candidate) {
  131.             console.log('用户B获取candidate信息', event.candidate);
  132.             // 通过信令服务器发送candidate信息给用户A
  133.             sock.emit('sendCandidate', {roomId, candidate: event.candidate})
  134.           }
  135.         }
  136.         // 接下来用户A和用户B就可以进行P2P通信流
  137.         // 监听onaddstream来获取对方的音视频流
  138.         that.peer.onaddstream = (event) => {
  139.           console.log('用户B收到用户A的stream',event.stream);
  140.           that.calling = false;
  141.           that.communicating = true;
  142.           that.remoteVideo.srcObject = event.stream;
  143.           that.remoteVideo.play();
  144.         }
  145.         // 设置远端描述信息
  146.         await that.peer.setRemoteDescription(offer);
  147.         let answer = await that.peer.createAnswer();
  148.         console.log('用户B生成answer',answer);
  149.         await that.peer.setLocalDescription(answer);
  150.         // 发送answer给信令服务器
  151.         sock.emit('sendAnswer', { answer, roomId })
  152.       }
  153.     })
  154.     // 用户A收到answer
  155.     sock.on('sendAnswer',async (answer) => {
  156.       if (that.caller){ // 接收方 - 用户A   判断是否是发送方
  157.         // console.log('用户A收到answer',answer);
  158.         await that.peer.setRemoteDescription(answer);
  159.       }
  160.     })
  161.     // 收到candidate信息
  162.     sock.on('sendCandidate',async (candidate) => {
  163.       console.log('收到candidate信息',candidate);
  164.       // await that.peer.addIceCandidate(candidate) // 用户A和用户B分别收到candidate后,都添加到自己的peer对象上
  165.       // await that.peer.addCandidate(candidate)
  166.       await that.peer.addIceCandidate(candidate)
  167.     })
  168.     // 挂断
  169.     sock.on('hangUp',()=>{
  170.       that.reset()
  171.     })
  172.     that.wsSocket = sock;
  173.   }
  174. }
  175. </script>
复制代码
服务端代码

  1. const socket = require('socket.io');
  2. const http = require('http');
  3. const server = http.createServer()
  4. const io = socket(server, {
  5.     cors: {
  6.         origin: '*' // 配置跨域
  7.     }
  8. });
  9. io.on('connection', sock => {
  10.     console.log('连接成功...')
  11.     // 向客户端发送连接成功的消息
  12.     sock.emit('connectionSuccess');
  13.     sock.on('joinRoom',(roomId)=>{
  14.         sock.join(roomId);
  15.         console.log('joinRoom-房间ID:'+roomId);
  16.     })
  17.     // 广播有人加入到房间
  18.     sock.on('callRemote',(roomId)=>{
  19.         io.to(roomId).emit('callRemote')
  20.     })
  21.     // 广播同意接听视频
  22.     sock.on('acceptCall',(roomId)=>{
  23.         io.to(roomId).emit('acceptCall')
  24.     })
  25.     // 接收offer
  26.     sock.on('sendOffer',({offer,roomId})=>{
  27.         io.to(roomId).emit('sendOffer',offer)
  28.     })
  29.     // 接收answer
  30.     sock.on('sendAnswer',({answer,roomId})=>{
  31.         io.to(roomId).emit('sendAnswer',answer)
  32.     })
  33.     // 收到candidate
  34.     sock.on('sendCandidate',({candidate,roomId})=>{
  35.         io.to(roomId).emit('sendCandidate',candidate)
  36.     })
  37.     // 挂断结束视频
  38.     sock.on('hangUp',(roomId)=>{
  39.         io.to(roomId).emit('hangUp')
  40.     })
  41. })
  42. server.listen(3000, () => {
  43.     console.log('服务器启动成功');
  44. });
复制代码
完整代码gitee地址: https://gitee.com/wade-nian/wdn-webrtc.git
参考文章:基于WebRTC实现音视频通话_npm create vite@latest webrtc-client -- --template-CSDN博客y
要是在拨打电话过程中,无法打开摄像头大概麦克风,浏览器也没有弹出获取摄像头及麦克风的权限运行,这是需要进行浏览器安全源的设置,步骤如下:
1、在 chrome 中 输入 chrome://flags/#unsafely-treat-insecure-origin-as-secure
2、找到Insecure origins treated as secure
3、添加你服务器的地址 比方:http://192.168.1.10:8080
4、选择Enabled属性

5、点击右下角的Relaunch即可


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4