安装依赖:

npm install aliyun-rtc-wx-sdk crypto-js

uni-app,新建一个页面,粘贴以下代码
在阿里云实时音视频补充appId、appKey即可,

<template><view class="container"><!-- 用户输入区域 --><view class="input-section" v-if="!isJoined"><uni-easyinputv-model="channelId"placeholder="请输入频道ID":clearable="true"/><uni-easyinputv-model="userName"placeholder="请输入用户名":clearable="true"/><uni-easyinputv-model="userId"placeholder="请输入用户ID":clearable="true"/><button @click="joinChannel" type="primary">加入房间</button></view><!-- 直播控制区域 --><view class="control-section" v-if="isJoined"><button @click="leaveChannel" type="warn">离开房间</button><button @click="switchCamera">切换摄像头</button><button @click="toggleMic">{{ pusher.enableMic ? '关闭麦克风' : '开启麦克风' }}</button><button @click="toggleCamera">{{ pusher.enableCamera ? '关闭摄像头' : '开启摄像头' }}</button></view><!-- 推流组件 --><live-pusher ref="livePusher":url="pusher.url" :mode="pusher.mode" :autopush="pusher.autopush" :beauty="pusher.beauty":whiteness="pusher.whiteness" :muted="pusher.muted" :mirror="pusher.mirror" :local-mirror="pusher.localMirror":enable-camera="pusher.enableCamera" :enable-mic="pusher.enableMic" :remote-mirror="pusher.remoteMirror":enable-ans="pusher.enableAns" :device-position="pusher.devicePosition" :enable-agc="pusher.enableAgc"@statechange="onPusherStateChange" @netstatus="onPusherNetStatus" @error="onPusherError"style="width: calc((100vw - 40rpx)); height: calc((100vw - 40rpx)/4*3);" v-if="pusher.url" />拉流组件列表({{ playerList.length }}):<view class="player-list" v-if="playerList.length > 0"><view v-for="(player, index) in playerList" :key="index" class="player-item"><live-player :src="player.src" mode="RTC" autoplay @statechange="onPlayerStateChange" @netstatus="onPlayerNetStatus"style="width: calc((50vw - 25rpx)); height: calc((50vw - 25rpx)/4*3);" /><text>{{ player.userName || player.userId }}</text></view></view><!-- 调试信息 --><view class="debug-info"><text>房间状态: {{ isJoined ? '已加入' : '未加入' }}</text><text>用户数量: {{ playerList.length }}</text></view></view>
</template><script setup lang="ts">
import { ref, onMounted, onUnmounted, getCurrentInstance } from 'vue'
import { queryAndGetUserInfo, UserInfo, getUserInfo } from '@/utils/userInfo'
import * as MainApi from './mainApi'
import baseInfo from '@/utils/base'
import { pagesRecords } from '@/hooks/pageRecordsHooks'// live-pusher  实例,用于切换摄像头
let LivePusher = uni.createLivePusherContext('livePusher')import AliRtcEngine from "aliyun-rtc-wx-sdk";
import CryptoJS from 'crypto-js';pagesRecords()let currentInstance = ref()
const { ctx } = getCurrentInstance() as any// 响应式数据
const pusher = ref({})
const playerList = ref([])
const isJoined = ref(false)
const userName = ref('')
const userId = ref('')
const appId = ref('')
const appKey = ref('')
const channelId = ref('AliRtcDemo')let artc: any = null// 生成Token
const generateToken = (appId: string, appKey: string, channelId: string, userId: string, timestamp: number) => {const data = `${appId}${appKey}${channelId}${userId}${timestamp}`;const hash = CryptoJS.SHA256(data);return hash.toString(CryptoJS.enc.Hex);
}// 初始化ARTC引擎
const initARTC = async () => {try {artc = AliRtcEngine.getInstance()bindEvents()uni.showToast({title: 'ARTC引擎初始化成功',icon: 'success'})} catch (error) {console.error('ARTC引擎初始化失败:', error)uni.showToast({title: 'ARTC引擎初始化失败',icon: 'error'})}
}// 绑定事件监听
const bindEvents = () => {// 远程用户上线通知artc.on("remoteUserOnLineNotify", (user: any, newPlayerList: any[]) => {		uni.showToast({title: `${user.displayName || user.userId} 加入了房间`,icon: "none",})playerList.value = newPlayerList})// 远程用户下线通知artc.on("remoteUserOffLineNotify", (user: any, newPlayerList: any[]) => {uni.showToast({title: `${user.displayName || user.userId} 退出了房间`,icon: "none",})playerList.value = newPlayerList})// 远程轨道可用通知artc.on("remoteTrackAvailableNotify", (user: any, newPlayerList: any[]) => {playerList.value = newPlayerList})// 被踢出房间artc.on("bye", () => {uni.showToast({title: "您已被踢出房间",icon: "none",})pusher.value = {}playerList.value = []isJoined.value = false})
}// 加入频道
const joinChannel = async () => {if (isJoined.value) {uni.showToast({title: '已在房间中',icon: 'none'})return}// 检查用户输入if (!userName.value.trim()) {uni.showToast({title: '请输入用户名',icon: 'none'})return}if (!userId.value.trim()) {uni.showToast({title: '请输入用户ID',icon: 'none'})return}uni.showLoading({title: '加入房间中...'})try {const timestamp = Math.floor(Date.now() / 1000) + 3600const token = generateToken(appId.value, appKey.value, channelId.value, userId.value, timestamp)const { pusherAttributes, playerList: newPlayerList } = await artc.joinChannel({appId: appId.value,appKey: appKey.value,channelId: channelId.value,userId: userId.value,userName: userName.value,token: token,timestamp: timestamp}, userName.value)pusher.value = pusherAttributesplayerList.value = newPlayerListisJoined.value = true// 开始推流artc.getPusherInstance().start()uni.hideLoading()uni.showToast({title: '加入房间成功',icon: 'success'})} catch (error) {uni.hideLoading()console.error('加入房间失败:', error)uni.showToast({title: '加入房间失败',icon: 'error'})}
}// 离开频道
const leaveChannel = async () => {if (!isJoined.value) {return}try {await artc.leaveChannel()pusher.value = {}playerList.value = []isJoined.value = falseuni.showToast({title: '已离开房间',icon: 'success'})} catch (error) {console.error('离开房间失败:', error)}
}// 切换摄像头
const switchCamera = () => {LivePusher.switchCamera()
}// 切换麦克风
const toggleMic = () => {pusher.value.enableMic = !pusher.value.enableMic
}// 切换摄像头
const toggleCamera = () => {pusher.value.enableCamera = !pusher.value.enableCamera
}// live-pusher 状态变化处理
const onPusherStateChange = (e: any) => {console.log("live-pusher code: ", e.detail.code)artc.handlePusherStateChange(e)
}// live-pusher 网络状态处理
const onPusherNetStatus = (e: any) => {console.log("live-pusher netStatus: ", e.detail.info)artc.handlePusherNetStatus(e)
}// live-pusher 错误处理
const onPusherError = (e: any) => {artc.handlePusherError(e)
}// live-player 状态变化处理
const onPlayerStateChange = (e: any) => {console.log("live-player code: ", e.detail.code)artc.handlePlayerStateChange(e)
}// live-player 网络状态处理
const onPlayerNetStatus = (e: any) => {console.log("live-player netStatus: ", e.detail.info)artc.handlePlayerNetStatus(e)
}// 生命周期
onMounted(() => {initARTC()
})onUnmounted(() => {leaveChannel()
})
</script><style scoped lang="scss">
.container {padding: 20rpx;
}.input-section {margin-bottom: 30rpx;.uni-easyinput {margin-bottom: 20rpx;}button {margin-top: 20rpx;}
}.control-section {display: flex;flex-wrap: wrap;gap: 10rpx;margin-bottom: 30rpx;button {font-size: 24rpx;flex: 1;padding: 0;}
}.player-list {display: flex;flex-wrap: wrap;gap: 10rpx;margin-top: 30rpx;.player-item {text-align: center;text {display: block;margin-top: 10rpx;font-size: 24rpx;color: #666;}}
}.debug-info {margin-top: 30rpx;padding: 20rpx;background-color: #f5f5f5;border-radius: 10rpx;text {display: block;margin-bottom: 10rpx;font-size: 24rpx;color: #333;}
}
</style>

userName、userId随便写,不重复即可,想进入同一个频道就让channelId一致,

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

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

相关文章

Java技术栈/面试题合集(3)-Java并发篇

场景 Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享: Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享_java高级进阶-CSDN博客 通过对面试题进行系统的复习可以对Java体系的知识点进行查漏补缺。…

[AI 生成] Spark 面试题

spark 基础问题面试题以下是 Spark 基础面试题的全面梳理&#xff0c;涵盖核心概念、架构原理和编程模型&#xff0c;帮助快速掌握高频考点&#xff1a;一、核心概念1. Spark 核心组件组件作用Driver执行 main() 方法&#xff0c;调度任务&#xff0c;管理集群资源Executor在 W…

MySQL的DML增删改操作:

目录 添加数据&#xff1a; 方式1&#xff1a;一条一条添加数据&#xff1a; 方式2&#xff1a;将查询结果插入到表中&#xff1a; 更新数据&#xff1a; 删除数据&#xff1a; MySQL8的新特性&#xff1a;计算列&#xff1a; 本文介绍了MySQL数据库操作语言(DML)的基本使…

MySQL运维常用语法速查

&#x1f5c3;️ 一、数据库操作 CREATE DATABASE db_name; USE db_name; DROP DATABASE db_name; SHOW DATABASES;&#x1f517; 官方文档 &#x1f4ca; 二、表操作 表创建示例 CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL,email V…

汽车以太网通信协议——SOME/IP

1. 背景 SOME/IP是一种汽车中间件解决方案&#xff0c;其全称是Scalable Service-Oriented Middleware over IP&#xff0c;即位于 IP 协议层以上的一种面向服务的可扩展的中间件。 中间件&#xff1a;该术语起源于复杂的软件系统开发&#xff0c;用以实现软件组件之间的数据交…

什么是负载均衡,有哪些常见算法?

文章目录1.什么是负载均衡2.负载均衡的分类2.1 二层负载均衡2.2 三层负载均衡2.3 四层负载均衡2.4 七层负载均衡3.负载均衡工具3.1 LVS3.2 Nginx3.3 HAProxy4.常见负载均衡算法5.面试回答模板1.什么是负载均衡 为了提升web应用的各方面能力&#xff0c;我们一般会把多台机器组…

PyTorch 核心三件套:Tensor、Module、Autograd

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录引言1 Tensor1.1 &#x1f6e0;️Tensor 的核心用…

python源码是如何运行起来的

为什么要了解底层原理 写出高质量代码 问题定位 满足好奇心 机械通感 开始 当我们编写并运行一行 print(Hello, World!) 时&#xff0c;背后究竟发生了什么&#xff1f;Python 代码是如何从我们可读的文本&#xff0c;变成计算机可以执行的指令的呢&#xff1f; 很多人将…

MacOS Docker 安装指南

MacOS Docker 安装指南 引言 Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。Docker …

Cisco 3750X交换机更新到IOS 15.2后无法启动 提示:Boot process failed...

背景及故障现象 一台新购入的二手Cisco 3750X-48P&#xff0c;原机自带IOS软件版本为12.x&#xff0c;可以正常工作。 但将IOS版本升级到15.2之后&#xff0c;在启动过程中卡住。 第一次加载IOS软件时是正常的&#xff0c;提示&#xff1a; Loading "flash:/c3750e-uni…

Redis Redis 常见数据类型

Redis 提供了 5 种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维非常重要&#xff0c;同时掌握每种数据结构的常见命令&#xff0c;会在使用 Redis 的时候做到游刃有余。 一、预备知识 官方文档&#xff1a;Commands | Docs (redis.io) 1、最核心的两个命令…

金融风控实战:Spring Boot + LightGBM 贷款预测模型服务化(超详细版)

金融风控实战&#xff1a;Spring Boot LightGBM 贷款预测模型服务化&#xff08;超详细版&#xff09;一、整体架构设计二、模型训练与优化1. 特征工程&#xff08;Python&#xff09;2. 模型评估与优化三、Spring Boot 服务实现1. 项目结构2. ONNX 模型服务3. 特征工程服务4.…

前端学习 7:EDA 工具

目录 EDA 工具 Design Ware Synopsys CoreTools 套件 VCS verdi Design Compiler EDA 工具 常用的EDA工具主要来自三家公司&#xff1a;Synopsys、Cadence和Mentor&#xff08;已被Siemens收购&#xff09;。EDA&#xff0c;全称电子设计自动化&#xff08;Electronics …

windows有一个企业微信安装包,脚本执行并安装到d盘。

以下是将本地已有的企业微信安装包安装到D盘的完整PowerShell脚本&#xff0c;包含详细的错误处理和进度反馈&#xff1a; <# .SYNOPSIS使用本地企业微信安装包安装到D盘 .DESCRIPTION自动检测本地安装包&#xff0c;静默安装到指定目录支持.exe和.msi格式安装包 #># 强制…

[LVGL] 布局系统 lv_flex, lv_grid | 输入设备 lv_indev | union

第五章&#xff1a;布局系统&#xff08;lv_flex, lv_grid&#xff09; 欢迎回来&#xff01; 在第四章&#xff1a;样式&#xff08;lv_style&#xff09;中&#xff0c;我们掌握了如何通过色彩、字体和圆角等特性美化部件。当界面元素具备视觉吸引力后&#xff0c;如何优雅…

Linux中的mkdir命令

基本语法mkdir 命令的基本语法如下&#xff1a;mkdir [选项] 目录名创建单个目录要创建一个新目录&#xff0c;只需在 mkdir 后跟上目录名称。例如&#xff1a;mkdir new_folder这会在当前工作目录下创建一个名为 new_folder 的目录。创建多个目录可以一次性创建多个目录&#…

基于大数据的美食视频播放数据可视化系统 Python+Django+Vue.js

本文项目编号 25003 &#xff0c;文末自助获取源码 \color{red}{25003&#xff0c;文末自助获取源码} 25003&#xff0c;文末自助获取源码 目录 一、系统介绍二、系统录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状 六、核心代码6.1 查询数据6.2 新…

微信小程序精品项目-基于springboot+Android的计算机精品课程学习系统(源码+LW+部署文档+全bao+远程调试+代码讲解等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

(五)系统可靠性设计

2024年博主考软考高级系统架构师没通过&#xff0c;于是决定集中精力认真学习系统架构的每一个环节&#xff0c;并在2025年软考中取得了不错的成绩&#xff0c;虽然做信息安全的考架构师很难&#xff0c;但找对方法&#xff0c;问题就不大&#xff01; 本文主要是博主在学习过程…

Shuffle SOAR使用学习经验

Shuffle SOAR 1. 基础操作与配置1.1 环境搭建与系统要求1.1.1 硬件与操作系统要求Shuffle SOAR 平台作为一款开源的安全编排、自动化与响应&#xff08;SOAR&#xff09;工具&#xff0c;其部署方式灵活&#xff0c;支持云端和自托管两种模式。对于自托管部署&#xff0c;官方推…