【声网】实现web端与uniapp微信小程序端音视频互动

实现web端与uniapp微信小程序端音视频互动

利用声网实现音视频互动

开通声网服务

  1. 注册声网账号

  2. 进入Console

  3. 成功登录控制台后,按照以下步骤创建一个声网项目:

    1. 展开控制台左上角下拉框,点击创建项目按钮。

      在这里插入图片描述

    2. 在弹出的对话框内,依次选择项目类型,输入项目名称,选择场景标签鉴权机制。其中鉴权机制推荐选择安全模式(APPID + Token)调试模式的安全性较低。
      在这里插入图片描述

    3. 创建好项目之后可以获取APP ID,Token,和Channel。临时Token有效期为24小时
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

web端

技术栈:vite+vue3+vue-router+pinia

组件库:element plus

开发环境准备:

  • Windows 或 macOS 计算机,需满足以下要求:
    • 下载声网 Web SDK 支持的浏览器。声网强烈推荐使用最新稳定版 Google Chrome 浏览器
    • 具备物理音视频采集设备。
    • 可连接到互联网。如果你的网络环境部署了防火墙,请参考应用企业防火墙限制以正常使用声网服务。
    • 搭载 2.2 GHz Intel 第二代 i3/i5/i7 处理器或同等性能的其他处理器。
  • 安装 Node.js 及 npm
  • 有效的声网账户和声网项目,并且从声网控制台获取以下信息:
    • App ID:声网随机生成的字符串,用于识别你的 App。
    • 临时 Token:你的 App 客户端加入频道时会使用 Token 对用户进行鉴权。临时 Token 的有效期为 24 小时。
    • 频道名称:用于标识频道的字符串。

项目开发

  1. 项目初始化

    使用vite创建vue3项目,npm create vite@latest

    集成webSDK,npm install agora-rtc-sdk-ng@latest

    安装vue-routernpm install vue-router@4在src下创建router.js;

    //router.js
    import { createRouter, createWebHistory } from 'vue-router';
    
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: () => import("@/views/home/home.vue")
      },
      {
        path: '/video',
        name: 'Video',
        component: () => import("@/views/video/video.vue")
      },
      
    ];
    
    const router = createRouter({
      history: createWebHistory(),
      routes
    });
    
    export default router;
    

    安装Element Plusnpm install element-plus --save,并且设置组件自动导入,具体可以看官方文档

    安装Pinianpm install pinia

    在main.js中初始化pinia,并在主目录创建store目录,创建options.js文件

    //mian.js
    import { createSSRApp } from 'vue'
    import * as Pinia from 'pinia';
    export function createApp() {
      const app = createSSRApp(App)
      app.use(Pinia.createPinia());
      return {
        app,
        Pinia
      }
    }
    
    //options.js
    import { defineStore } from "pinia";
    import {reactive} from "vue";
    
    export const useOptionsStore = defineStore('options',() => {
      const options = reactive({
        appId: "Your APPID",
        token: "Your token",
      })
    
      return {options}
    })
    

    在main.js中引入所有安装的内容:

    import { createApp } from 'vue';
    import router from "./router";
    import { createPinia } from 'pinia';
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    import App from './App.vue';
    
    const app = createApp(App)
    app.use(router)
    app.use(ElementPlus)
    
    app.use(createPinia())
    app.mount('#app')
    
  2. 编写home.vue

​ 使用el-form el-form-item el-input 对用户的输入进行校验,校验通过后携带用户输入的参数进入到视频通话页面

<template>
  <div class="content">
    <el-form
      :model="form"
      label-width="auto"
      style="max-width: 600px"
      :rules="rules"
      ref="ruleFormRef"
    >
      <el-form-item label="房间号" prop="channel">
        <el-input v-model="form.channel" placeholder="请输入房间号"></el-input>
      </el-form-item>
      <el-form-item label="用户名" prop="uid">
        <el-input v-model="form.uid" placeholder="请输入用户名"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="joinChannel" style="width: 100%"
          >加入房间</el-button
        >
      </el-form-item>
    </el-form>
  </div>
</template>
<script setup>
import { reactive, ref } from "vue";
import { useRouter } from "vue-router";

const router = useRouter();

const form = reactive({
  channel: "",
  uid: "",
});

const ruleFormRef = ref(null);

const rules = reactive({
  channel: [{ required: true, message: "请输入房间号", trigger: "blur" }],
  uid: [{ required: true, message: "请输入用户名", trigger: "blur" }],
});

const joinChannel = async () => {
  await ruleFormRef.value.validate();
  router.push({
    name: "Video",
    query: { channel: form.channel, uid: form.uid },
  });
};
</script>
<style scoped>
.content {
  display: flex;
  flex-direction: column;
}
</style>
  1. 编写video.vue

    • 实现视频通话的步骤大致为:初始化客户端对象并创建本地客户端 -> 订阅远端流 -> 加入频道 -> 创建并发布本地音视频轨道-> (通话) ->退出关闭本地流
    1. 初始化客户端对象并创建本地客户端

      导入声网组件,import AgoraRTC from "agora-rtc-sdk-ng";

      初始化客户端对象,let client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" }); 注意:与微信小程序通信codec为h264。与其他端使用的是vp8。并且此client不能写成响应式数据,要保证全局使用的本地客户端对象为唯一的。

      要保证客户端对象可以在最一开始就可以进行初始化,并且可以全局使用,所以都写入setup中。

import AgoraRTC from "agora-rtc-sdk-ng";
let client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" });
  1. 订阅远端流

    当远端流发布到频道时,会触发 user-published 事件,需要通过 client.on 监听该事件并在回调中订阅新加入的远端流。当远端用户取消发布流或退出频道时,触发user-unpublished事件,关闭及移除对应的流。为了用户能够在进入页面的时候及时监听到远端流,所以将监听事件放入onMounted中。

    handleUserPublished函数中编写远端用户加入事件,远端用户加入事件中需要做的事情是通过调用client.subscribe(远端加入的用户user对象,连接方式)方法获取到远端用户对象和连接方式(分为video,audio),区别不同的连接方式,调用包含在user中不同的方法。如果是video,就先需要在先创建dom,将user的视频放入到dom中,并且该dom要有宽高。如果是audio则不用。

    handleUserUnpublished函数中编写远端用户退出事件,就将remoteUserRef的值置为null,使其不再显示页面上。

<template>
   <!-- 使用ref获取dom -->
    远程用户:
    <div
      class="remote-user"
      ref="remoteUserRef"
    ></div>
</template>
      import AgoraRTC from "agora-rtc-sdk-ng";
      import {ref} from "vue";
      let client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" });
      
      
      const remoteUserRef = ref(null)
      const handleUserPublished = async (user, mediaType) => {
        await client.subscribe(user, mediaType);
      
        // 如果是视频轨道,则添加到远程用户列表
        if (mediaType === "video") {
          user.videoTrack.play(remoteUserRef.value);
        }
        // 如果是音频轨道,直接播放
        if (mediaType === "audio") {
          user.audioTrack.play();
        }
      };
      
      const handleUserUnpublished = () => {
        // 移除远程用户
        remoteUserRef.value = null;
      };
      
      onMounted(async () => {
        // 监听远程用户发布事件
        client.on("user-published", handleUserPublished);
        client.on("user-unpublished", handleUserUnpublished);
      });
 .remote-user {
   width: 640px;
   height: 480px;
 }
  1. 加入频道

    调用 client.join(appId, channel, token, uid) 方法加入一个 RTC 频道,需要在该方法中传入 app ID 、用户 ID、Token、频道名称。

    appId,token都可以通过pinia取出,channel和uid通过路由参数取出。client.join是一个异步方法,返回一个promise,使用async,await。

    import { useOptionsStore } from "../store/options";
    import {  useRoute } from "vue-router";
    const route = useRoute();
    const store = useOptionsStore();
    
    const {options} = store;
    
    const { uid , channel} = route.query
    
    const joinChannel = async () => {
      await client.join(
        options.appId,
        channel,
        options.token,
        uid
      );
    };
    
    onMounted(async () => {
      // 监听远程用户发布事件
      client.on("user-published", handleUserPublished);
      client.on("user-unpublished", handleUserUnpublished);
      await joinChannel();
    });
    
  2. 创建并发布本地音视频轨道

调用 AgoraRTC.createMicrophoneAudioTrack() 通过麦克风采集的音频创建本地音频轨道对象,调用 AgoraRTC.createCameraVideoTrack()通过摄像头采集的视频创建本地视频轨道对象;然后调用 client.publish 方法,将这些本地音视频轨道对象当作参数即可将音视频发布到频道中。并且创建一个容器用于播放本地视频轨道。

<template>
    <div
      class="local-player"
      ref="localPlayerRef"
    ></div>
...
</template>
 import { ref , reactive} from "vue";
 ...
 const localUser = reactive({
   videoTrack: null,
   audioTrack: null,
 });
 const localPlayerRef = ref(null);
 const createTrack = async () => {
   localUser.audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
   localUser.videoTrack = await AgoraRTC.createCameraVideoTrack();
   await client.publish([localUser.audioTrack, localUser.videoTrack]);
   localUser.videoTrack.play(localPlayerRef.value);
 }
 
 onMounted(async () => {
   // 监听远程用户发布事件
   client.on("user-published", handleUserPublished);
   client.on("user-unpublished", handleUserUnpublished);
   await joinChannel();
   await createTrack();
 });
 .local-player {
   width: 640px;
   height: 480px;
 }
 </style>
  1. 离开频道
const leaveChannel = async () => {
  localUser.audioTrack && localUser.audioTrack.close();
  localUser.videoTrack && localUser.videoTrack.close();

  // 离开频道
  if (client) {
    await client.leave();
    client = null;
  }

  // 返回首页
  localPlayerRef.value = null;
  remoteUserRef.value = null;
  router.push({ name: "Home" });
};

onBeforeUnmount(() => {
  leaveChannel();
});

整体代码:

 <template>
       <!-- 创建本地视频容器 start-->
       <div>
         本地用户: 
         <div
           class="local-player"
           ref="localPlayerRef"
         ></div>
       </div>
       <!-- 创建本地视频容器 end -->
 
       <!-- 使用 v-for 循环遍历所有远程用户并为每个用户创建一个视频容器 -->
       <div>
         远程用户:
         <div
           class="remote-user"
           ref="remoteUserRef"
         ></div>
       </div>
     </div>
 
     <button @click="leaveChannel" style="margin-top: 20px; display: block">
       退出
     </button>
 </template>
 import {
   ref,
   onMounted,
   onBeforeUnmount,
 } from "vue";
 import AgoraRTC from "agora-rtc-sdk-ng";
 import { useOptionsStore } from "@/store/options";
 import { useRouter, useRoute } from "vue-router";
 
 const router = useRouter();
 
 const route = useRoute();
 
 const localUser = reactive({
   videoTrack: null,
   audioTrack: null,
 });
 
 let client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" });
 
 const localPlayerRef = ref(null);
 const remoteUserRef = ref(null);
 
 const store = useOptionsStore();
 
 const { options } = store;
 
 onBeforeUnmount(() => {
   leaveChannel();
 });
 
 const joinChannel = async () => {
   await client.join(
     options.appId,
     channel,
     options.token,
     uid
   );
 
 };
     
 const createTrack = () => {
       // 创建并发布本地音频和视频轨道
   localUser.audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
   localUser.videoTrack = await AgoraRTC.createCameraVideoTrack();
   await client.publish([localUser.audioTrack, localUser.videoTrack]);
   localUser.videoTrack.play(localPlayerRef.value);
 }
 
 const leaveChannel = async () => {
   localUser.audioTrack && localUser.audioTrack.close();
   localUser.videoTrack && localUser.videoTrack.close();
 
   // 离开频道
   if (client) {
     await client.leave
上一篇:南京邮电大学数学实验A 作业4 符号计算 答案 | 《MATLAB数学实验》第三版 第七章 课后习题答案-3(课本习题4)


下一篇:NotePad++联动ABAQUS-Abaqus 中脚本运行