【声网】实现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-router,npm 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 Plus ,npm install element-plus --save,并且设置组件自动导入,具体可以看官方文档

    安装Pinia,npm 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 -->远程用户:<divclass="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.queryconst 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><divclass="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>本地用户: <divclass="local-player"ref="localPlayerRef"></div></div><!-- 创建本地视频容器 end --><!-- 使用 v-for 循环遍历所有远程用户并为每个用户创建一个视频容器 --><div>远程用户:<divclass="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();client = null;}// 返回首页localPlayerRef.value = null;remoteUserRef.value = null;router.push({ name: "Home" });};const handleUserPublished = async (user, mediaType) => {await client.subscribe(user, mediaType);if (user.uid !== localUser.uid &&!remoteUsers.value.some((remoteUser) => remoteUser.uid === user.uid)) {remoteUsers.value.push(user);}// 如果是视频轨道,则添加到远程用户列表if (mediaType === "video") {nextTick(() => {const remoteUserRef = remoteUserRefMap.value[`remote_Ref_${user.uid}`];if (remoteUserRef) {user.videoTrack.play(remoteUserRef);}});}// 如果是音频轨道,直接播放if (mediaType === "audio") {user.audioTrack.play();}};const handleUserUnpublished = (user) => {// 移除远程用户remoteUsers.value = remoteUsers.value.filter((remoteUser) => remoteUser.uid !== user.uid);};onMounted(async () => {// 监听远程用户发布事件client.on("user-published", handleUserPublished);client.on("user-unpublished", handleUserUnpublished);await joinChannel();await createTrack();});
 .local-player,.remote-user {width: 640px;height: 480px;}

uniapp小程序端

技术栈:uniapp+vue3+pinia

组件库:uni ui

开发环境准备:

  • 下载并安装最新版的微信开发者工具。
  • 一个经过企业认证的微信小程序账号。在调试小程序 Demo 过程中,需要使用 live-pusher 和 live-player 组件。只有特定行业的认证企业账号才可以使用这两个组件。具体组件见微信官方文档
  • 微信小程序账号需要在微信公众平台进行配置。
  • 参考开通服务在控制台创建项目、获取 App ID 和临时 Token,并开启小程序服务。
  • 一台安装有微信 App 的移动设备。

Console开启小程序服务

第一次使用微信小程序时,需要参考如下步骤开通服务:

  1. 登录声网控制台,点击左侧导航栏的全部产品,选择实时互动 RTC,进入实时互动 RTC 页面。
  2. 在实时互动 RTC 页面,切换到功能配置页签。

在这里插入图片描述

微信小程序配置

  1. 获取小程序组件权限

​ 在微信公众平台的小程序开发选项中,切换到接口设置页签,打开实时播放音视频流实时录制音视频流的开关。

在这里插入图片描述

  1. 配置服务器域名

在小程序的开发设置里,将如下域名配到服务器域名里。

request 合法域名区域填入以 https 开头的域名;

   https://uap-ap-web-1.agora.iohttps://uap-ap-web-2.agoraio.cnhttps://uap-ap-web-3.agora.iohttps://uap-ap-web-4.agoraio.cnhttps://report-ad.agoralab.cohttps://rest-argus-ad.agoralab.cohttps://uni-webcollector.agora.io

socket 合法域名区域点入以 wss 开头的域名。

wss://miniapp.agoraio.cn

在这里插入图片描述

项目开发

  1. 初始化项目

    HBuilder X 可视化(推荐)或者cli脚手架创建uniapp项目。 具体创建方式

    创建项目后,需要集成小程序SDK。有两种方式:

    • 第一种:下载小程序SDK 并解压。

      将解压出来的JS文件复制到项目中主目录的static下,在主目录下创建一个utils,创建一个sdk.js,引入并导出该SDK,用于vue文件可以引入并使用。

      const AgoraMiniappSDK = require('../static/Agora_Miniapp_SDK_for_WeChat.js');export default AgoraMiniappSDK
      
    • 第二种方式:npm 安装

      npm install agora-miniapp-sdk
      
    1. 使用pinia存入音视频所需要的APP ID 和临时token

      如果使用的是HBuilder X 可视化创建的项目,可以直接使用pinia,使用cli脚手架创建的需要手动通过npm 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}
        })
        
    2. 引入uni ui组件库

      如果使用HBuilder X ,可以直接通过uni ui组件库导入到项目中

    3. 编写路由文件Pages.json

      暂定只有两个页面,index页面用于输入房间号和用户id,video文件用于视频通话

      {"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "主页"}},{"path": "pages/video/video","style": {"navigationStyle":"custom"}}],"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8"},"uniIdRouter": {}
      }
      
    4. 编写index页面

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

      <template><view class="contain"><uni-forms :modelValue="formData" ref="form" :rules="rules"><uni-forms-item name="channle"><uni-easyinputtype="text"v-model="formData.channle"placeholder="请输入房间号"/></uni-forms-item><uni-forms-item name="uid"><uni-easyinputtype="text"v-model="formData.uid"placeholder="请输入用户uid"/></uni-forms-item><button @click="joinChannle">进入房间</button></uni-forms></view>
      </template><script setup>
      import { ref } from "vue";const formData = ref({channle: "",uid: "",
      });const form = ref(null);const rules = {channle: {rules: [{ required: true, errorMessage: "请输入房间号", trigger: "blur" }],},uid: {rules: [{ required: true, errorMessage: "请输入用户uid", trigger: "blur" }],},
      };const joinChannle = async () => {await form.value.validate();uni.navigateTo({url: `/pages/video/video? channle=${formData.value.channle}&uid=${formData.value.uid}`,});
      };
      </script><style scoped lang="scss">
      ::v-deep(.contain) {display: flex;flex-direction: column;align-items: center;height: 100vh;.uni-forms {width: 80%;margin-top: 40%;.uni-easyinput {.uni-easyinput__content {height: 90rpx;}}button {width: 100%;height: 80rpx;line-height: 80rpx;background-color: #409eff;color: #fff;border: none;border-radius: 10rpx;margin-top: 40rpx;}}
      }
      </style>
      
    5. 编写video.vue

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

      • 可以用以下的图片概括

        在这里插入图片描述

        一、代码实现步骤

        1. 初始化客户端对象

          ​ 引入SDK对象 import AgoraMiniappSDK from "../../utils/sdk"

          ​ 在setup中实例化客户端对象let client = new AgoraMiniappSDK.Client();在setup中创建是因为可以最一开始就创建好对象,并且在全局可以访问到同一个客户端对象。实例化好客户端对象后,需要进行初始化,调用的是client.init(appId)方法,appId通过pinia取出,此方法是一个异步函数,返回一个promise对象,可以使用.then(),也可以使用async、await方法。但在setup语法糖中不能直接使用async修饰,所以需要将方法包裹在函数中。

          ​ 在这里会使用微信小程序的onLoad生命周期函数,正好也可以接收从index页面传过来的路由参数。在vue3中,onLoad函数需要引入。import { onLoad } from "@dcloudio/uni-app";

          ​ 到这里,代码就如同:

          <template>
          </template><script setup>
          import AgoraMiniappSDK from "../../utils/sdk";
          import { useOptionsStore } from "../../store/options";
          import { onLoad } from "@dcloudio/uni-app;const store = useOptionsStore();
          const { appId, token } = store.options;let client = new AgoraMiniappSDK.Client();
          let channel,uid;onLoad(async (options) => {if (options) {channel = options.channle;uid = options.uid;}await client.init(appId);
          });</script>
          
        2. 订阅远端流

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

          onLoad(async (options) => {if (options) {channel = options.channle;uid = options.uid;}client.on("stream-added", handleAdd);client.on("stream-removed", handleRemove);await client.init(appId);
          });
          

          ​ 在handleAdd函数中编写远端用户加入事件,远端用户加入事件中需要做的事情是通过调用client.subscribe(远端加入的用户uid)方法获取到远端用户的远端音视频地址,并将地址绑定在微信的<live-player>的src上,就可以在页面上显示远端用户的视频。所以需要在<template><live-player>组件,也需要定义一个变量livePlayer存入地址。

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

          <template><view><!-- 远端拉流 start --><live-playerclass="live-view"id="player":src="livePlayer"mode="RTC":autoplay="true"/><!-- mode为模式,RTC为实时通话,autoplay一定要设置了true才会自动播放 -->      <!-- 远端拉流 end --></view>
          </template><script setup>
          import {ref} from "vue"
          import AgoraMiniappSDK from "../../utils/sdk";
          import { useOptionsStore } from "../../store/options";
          import { onLoad } from "@dcloudio/uni-app;const store = useOptionsStore();
          const { appId, token } = store.options;let client = new AgoraMiniappSDK.Client();
          let channel,uid;const livePlayer = ref(null);const handleAdd = async (e) => {const { url } = await client.subscribe(e.uid);//远端用户uidlivePlayer.value = url;
          };const handleRemove = async (e) => {livePlayer.value = null;
          };onLoad(async (options) => {if (options) {channel = options.channle;uid = options.uid;}await client.init(appId);
          });
          </script>
          
        3. 加入频道

          ​ 调用 client.join(yourToken, channel, uid) 方法加入频道。此方法是异步函数

          ​ 在 client.join 中你需要将 yourToken 替换成你自己生成的 Token。并填入想要加入的频道名以及用户 uid。为了能够及时加入频道,并且使得整个流程清晰,所以将join方法写在onLoad中。

          <template><view>...</view>
          </template><script setup>
          ...const joinChannle = async () => {await client.join(token, channel, uid);
          };...onLoad(async (options) => {if (options) {channel = options.channle;uid = options.uid;}await client.init(appId);await joinChannle();
          });
          </script>
          
        4. 发布本地流

          ​ 成功加入频道后,就能调用 client.publish 方法将本地音视频流发布到频道中。成功发布后,SDK 会返回该路音视频流的 URL。URL用于微信小程序的组件<live-pusher>。同理,需要设置变量pusherPlayer存入地址。需要调用client.setRole(“broadcaster”)方法先将推流的角色设置为主播(broadcaster),才能推流,并且<live-pusher>的autopush需要设置为true

        const livePlayer = ref(null);
        const joinChannle = async () => {await client.setRole("broadcaster");await client.join(token, channel, uid);pusherPlayer.value = await client.publish();
        };
        
        1. 退出关闭本地流

          调用client.cleave()方法退出频道。

        整体代码

      <template><view><!-- 本地推流 start --><live-pusher:url="pusherPlayer"mode="RTC":autopush="true"class="pusher"/><!-- 本地推流 end --><!-- 远端拉流 start --><live-playerclass="live-view":src="livePlayer"mode="RTC"style="width: 100vw; height: 100vh":autoplay="true"/><!-- 远端拉流 end --><!-- 功能按钮 start --><view> <i class="iconfont hang-up return-icon" @click="goBack"></i></view><!-- 功能按钮 end --></view>
      </template><script setup>
      import { ref,  computed, watch } from "vue";
      import AgoraMiniappSDK from "../../utils/sdk";
      import { useOptionsStore } from "../../store/options";
      import { onLoad } from "@dcloudio/uni-app";const store = useOptionsStore();const { appId, token } = store.options;let channel, uid;let client = new AgoraMiniappSDK.Client();const pusherPlayer = ref(null);
      const livePlayer = ref(null);const joinChannle = async () => {await client.init(appId);await client.setRole("broadcaster");await client.join(token, channel, uid);pusherPlayer.value = await client.publish();
      };const handleAdd = async (e) => {const { url } = await client.subscribe(e.uid);livePlayer.value = url;
      };const handleRemove = async (e) => {livePlayer.value = null;
      };const goBack = () => {uni.showModal({title: "提示",content: "确定要退出直播吗?",success: (res) => {if (res.confirm) {client.leave();uni.navigateBack();}},});
      };onLoad(async (options) => {if (options) {channel = options.channle;uid = options.uid;}client.on("stream-added", handleAdd);client.on("stream-removed", handleRemove);await joinChannle();
      });</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/3865.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python版的openCV使用及下载

一、下载OpenCV模块 截止目前&#xff1a;现在OpenCV使用环境还是python3.8的版本所以咱们下载时记得用3.8版本的 终端下载&#xff1a;pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python 这是国内的镜像下载能快一些&#xff1b; 下载成功的标志&am…

Linux简单命令

目录 显示目录下的内容 ls 切换工作目录 cd 查看-当前工作目录pwd 创建-文件夹 mkdir 创建-文件 touch 查看-文件内容 cat 查看-分屏查看文件内容 more 删除-文件、文件夹 rm 复制-文件、文件夹 cp 移动-文件、文件夹 mv 查找-命令的程序文件存放处 which 查找-按文…

Linux平台Unity下RTMP|RTSP低延迟播放器技术实现

技术背景 国产操作系统对于确保信息安全、促进技术创新、满足特定需求以及推动经济发展等方面都具有重要意义&#xff0c;多以Linux为基础二次开发。2014年4月8日起&#xff0c;美国微软公司停止了对Windows XP SP3操作系统提供支持&#xff0c;这引起了社会和广大用户的广泛关…

SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention多变量时间序列预测

SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention秃鹰算法优化卷积门控循环单元融合多头注意力机制多变量时间序列预测 目录 SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention秃鹰算法优化卷积门控循环单元融合多头注意力机制多变量时间序列预测预测效果基本介绍…

Unreal Engine创建Plugin

打开UE工程&#xff0c;点击编辑&#xff0c;选择插件 点击“新插件”按钮&#xff0c;选择“空白选项”填入插件名字"MultiPlayerPlugin"&#xff0c;填入插件作者、描述&#xff0c;点击“创建插件”按钮打开C工程&#xff0c;即可看到插件目录&#xff0c;编译C工…

Linux网络编程---多进/线程并发服务器

一、多进程并发服务器 实现一个服务器可以连接多个客户端&#xff0c;每当accept函数等待到客户端进行连接时 就创建一个子进程 思路分析&#xff1a; 核心思路&#xff1a;让accept循环阻塞等待客户端&#xff0c;每当有客户端连接时就fork子进程&#xff0c;让子进程去和客户…

2分钟自己写小游戏:使用js和css编写石头剪刀布小游戏、扫雷小游戏、五子棋小游戏。新手老手毕业论文都能用。

系列文章目录 【复制就能用1】2分钟玩转轮播图,unslider的详细用法 【复制就能用2】css实现转动的大风车&#xff0c;效果很不错。 【复制就能用3】2分钟自己写小游戏&#xff1a;剪刀石头布小游戏、扫雷游戏、五子棋小游戏 【复制就能用4】2024最新智慧医疗智慧医院大数据…

MySQL:ACCESS DENIED FOR USER‘ROOT‘@‘IP地址

起因是使用若依的环境连接数据库时报错&#xff1a;远程数据库连接异常&#xff0c;最终原因是密码错误&#xff0c;且看分解 07:12:06.895 [main] INFO c.r.RuoYiApplication - [logStartupProfileInfo,686] - The following 1 profile is active: "druid" 07:12:…

阿里巴巴瓴羊基于 Flink 实时计算的优化和实践

摘要&#xff1a;本⽂整理⾃阿里云智能集团技术专家王柳焮⽼师在 Flink Forward Asia 2023 中平台建设专场的分享。内容主要为以下四部分&#xff1a; 阿里巴巴瓴羊基于 Flink 实时计算的平台演进Flink 能力优化与建设基于 Flink 的最佳实践未来规划 1. 阿里巴巴瓴羊基于 Flink…

等保测评有那些流程?为什么要做等保

根据《网络安全法》规定&#xff0c;网络运营者应当按照国家的网络安全技术标准和要求&#xff0c;采取技术措施保障网络安全&#xff0c;避免网络安全事件的发生。而等保测评是国家对企事业单位进行信息系统安全等级评定的一项重要制度&#xff0c;通过等级测评&#xff0c;可…

macOS 一些系统图标的存放位置 icns

macOS 一些系统图标的存放位置 icns macOS 中有很多好看的图标&#xff0c;有时候就想用一下它&#xff0c;我来告诉你他们的具体位置。 系统图标位置&#xff0c;像各种通用文件类型的图标都在这里面&#xff0c;里面好多高清的系统图标 /System/Library/CoreServices/Core…

Android Studio的button点击事件

xml添加onClick调用方法 public class MainActivity extends AppCompatActivity {// 创建系统时间的文本控件TextView systemTimeTextView;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activit…

精酿啤酒:酿造工艺的自动化与智能化发展

随着科技的不断进步&#xff0c;自动化与智能化已成为啤酒酿造工艺的重要发展方向。Fendi Club啤酒紧跟时代潮流&#xff0c;积极推动酿造工艺的自动化与智能化发展&#xff0c;旨在提高生产效率、确保产品品质和满足市场需求。 Fendi Club啤酒引入自动化生产设备。他们采用自动…

外观模式【结构型模式C++】

1.概述 外观模式是一种结构型设计模式&#xff0c; 能为程序库、 框架或其他复杂类提供一个简单的接口。 2.结构   外观角色&#xff08;Facade&#xff09;&#xff1a;为多个子系统对外提供一个共同的接口&#xff0c;知道哪些子系统负责处理请求&#xff0c;将客户端的请…

Qt下使用OpenCV截取图像并在QtableWidget表格上显示

文章目录 前言一、在QLabel上显示图片并绘制矩形框二、保存矩形框数据为CSV文件三、保存截取图像四、将截取图像填充到表格五、图形视图框架显示图像六、示例完整代码总结 前言 本文主要讲述了在Qt下使用OpenCV截取绘制的矩形框图像&#xff0c;并将矩形框数据保存为CSV文件&a…

235 基于matlab的时频盲源分离(TFBSS)算法

基于matlab的时频盲源分离&#xff08;TFBSS&#xff09;算法&#xff0c;TFBSS用空间频率分布来分离非平稳信号&#xff0c;可以分离具有不同时频分布的源信号&#xff0c;也能够分离具有相同谱密度但时频分布不同的高斯源。同时&#xff0c;该算法在时频域上局域化源信号能量…

vue 3 —— 笔记(模板语法,响应式变量)

模板语法&#xff1a; Vue 使用一种基于 html 的模板语法&#xff0c;使我们能声明式将其组件实例绑定到呈现的 dom 上 文本插值 基础数据绑定形式 双大括号 会替换相应组件实例 msg 属性的值 原始html 双大括号会将数据解释为纯文本 不是html 想插入html 使用 v-html 指令 &…

【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门

【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门 文章目录 【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门1. 概述2. 服务熔断服务降级(CircuitBreaker)2.1 案例说明2.1.1 基于计数的滑动窗口2.1.2 测试2.2.1 基于时间的滑动窗口2.2.2 测试 3. 隔离(B…

前端单元测试的艺术:专业化策略与Vue项目高效实践指南

单元测试是软件开发中的基石&#xff0c;尤其对于前端领域&#xff0c;它为保证代码质量、提升开发效率、强化项目稳定性提供了不可或缺的支持。本文将深入剖析单元测试的核心理念&#xff0c;揭示其在前端开发中的独特价值&#xff0c;并提炼出一套专业且高效的实践策略&#…

git 基础知识(全能版)

文章目录 一 、git 有三个分区二、git 基本操作1、克隆—git clone2、拉取—git fetch / git pull3、查看—git status / git diff3.1 多人开发代码暂存技巧 本地代码4、提交—git add / git commit / git push5、日志—git log / git reflog6、删除—git rm ‘name’7、撤销恢…