目的:uniapp微信小程序通过腾讯云实现多人会议功能。

效果展示:

功能实现:

前提条件: 注册腾讯云 账号,并完成 实名认证。

推拉流标签不支持个人小程序,要求申请的企业类微信小程序。

步骤一:开通微信小程序权限

推拉流标签不支持个人小程序,要求申请的企业类微信小程序登录微信公众平台 =》开发 =》开发管理 =》接口设置,在其他接口中打开实时播放音视频流实时播放音视频流。如图:

步骤二:在微信小程序控制台配置域名

在 微信公众平台 =》 开发 =》 开发管理 =》 开发设置 =》 服务器域名中设置 request合法域名socket合法域名,如下图所示:

  • request 合法域名:

    https://official.opensso.tencent-cloud.com
    https://yun.tim.qq.com
    https://cloud.tencent.com
    https://webim.tim.qq.com
    https://query.tencent-cloud.com
    https://web.sdk.qcloud.com
  • socket 合法域名:

    wss://wss.im.qcloud.com
    wss://wss.tim.qq.com

步骤三:下载多人会议功能源码  源码下载地址

项目结构如图所示:

步骤四: 开通腾讯云服务

  1. 登录到 即时通信 IM 控制台,单击创建新应用,在弹出的对话框中输入您的应用名称,并单击确定

  2. 单击刚刚创建出的应用,进入基本配置页面,并在页面的右下角找到开通腾讯实时音视频服务功能区,单击免费体验即可开通 TUICallKit 的 7 天免费试用服务。
  3. 在同一页面找到 SDKAppID密钥并记录下来。

步骤四: 配置 meeting =》debug =》GenerateTestUserSig.js 工程文件

设置 GenerateTestUserSig.js 文件中的相关参数:

  • SDKAPPID:默认为0,请设置为实际的 SDKAppID。
  • SECRETKEY:默认为空字符串,请设置为实际的密钥信息。

步骤五:calling.vue为入口页。

<template><view class="container"><view class="trtc-demo-container"><!-- <view class='title'  ><view>多人会议</view></view> --><view class="input-box"><input type="number" v-model="roomID" maxlength="10"  placeholder="请输入房间号" placeholder-style="opacity: 0.55;"/></view><view class="choice-content"><view class="label" ><text>开启摄像头</text><u-switch inactiveColor="#999999" activeColor="#00B38A" v-model="localVideo"  @change="switchHandler"/></view><view class="label"><text>开启麦克风</text><u-switch  inactiveColor="#999999" activeColor="#00B38A" v-model="localAudio"  @change="switchHandler2"/></view></view></view><view class='bottom-btn'><button class="btn" @click="enterRoom" hover-class="none">进入房间</button></view></view>
</template>
<script>import { genTestUserSig } from './debug/GenerateTestUserSig'
import { mapState } from 'vuex';export default {data() {return {roomID: '',localVideo: true,localAudio: false,}},computed: {...mapState(['userInfo'])},onLaunch(){},onLoad() {},methods: {enterRoom() {const nowTime = new Date()if (nowTime - this.tapTime < 1000) {return}if (!this.roomID) {uni.showToast({title: '请输入房间号',icon: 'none',duration: 2000,})return}if (/^\d*$/.test(this.roomID) === false) {uni.showToast({title: '房间号只能为数字',icon: 'none',duration: 2000,})return}if (this.roomID > 4294967295 || this.roomID < 1) {uni.showToast({title: '房间号取值范围为 1~4294967295',icon: 'none',duration: 2000,})return}const userID = this.userInfo.userId || '123'; //userIDconst Signature = genTestUserSig(userID)const url = `./room/room?roomID=${this.roomID}&localVideo=${this.localVideo}&localAudio=${this.localAudio}&userID=${userID}&sdkAppID=${Signature.sdkAppID}&userSig=${Signature.userSig}`this.tapTime = nowTimethis.checkDeviceAuthorize().then((result) => {console.log('授权成功', result)wx.navigateTo({ url })}).catch((error) => {console.log('没有授权', error)})},checkDeviceAuthorize() {this.hasOpenDeviceAuthorizeModal = falsereturn new Promise((resolve, reject) => {if (!wx.getSetting || !wx.getSetting()) {// 微信测试版 获取授权API异常,目前只能即使没授权也可以通过resolve()}wx.getSetting().then((result) => {console.log('getSetting', result)this.authorizeMic = result.authSetting['scope.record']this.authorizeCamera = result.authSetting['scope.camera']if (result.authSetting['scope.camera'] && result.authSetting['scope.record']) {// 授权成功resolve()} else {// 没有授权,弹出授权窗口// 注意: wx.authorize 只有首次调用会弹框,之后调用只返回结果,如果没有授权需要自行弹框提示处理console.log('getSetting 没有授权,弹出授权窗口', result)wx.authorize({scope: 'scope.record',}).then((res) => {console.log('authorize mic', res)this.authorizeMic = trueif (this.authorizeCamera) {resolve()}}).catch((error) => {console.log('authorize mic error', error)this.authorizeMic = false})wx.authorize({scope: 'scope.camera',}).then((res) => {console.log('authorize camera', res)this.authorizeCamera = trueif (this.authorizeMic) {resolve()} else {this.openConfirm()reject(new Error('authorize fail'))}}).catch((error) => {console.log('authorize camera error', error)this.authorizeCamera = falsethis.openConfirm()reject(new Error('authorize fail'))})}})})},openConfirm() {if (this.hasOpenDeviceAuthorizeModal) {return}this.hasOpenDeviceAuthorizeModal = truereturn uni.showModal({content: '您没有打开麦克风和摄像头的权限,是否去设置打开?',confirmText: '确认',cancelText: '取消',success: (res) => {this.hasOpenDeviceAuthorizeModal = falseconsole.log(res)// 点击“确认”时打开设置页面if (res.confirm) {console.log('用户点击确认')wx.openSetting({success: (res) => { },})} else {console.log('用户点击取消')}},})},switchHandler(e) {this.localVideo = e;},switchHandler2(e) {this.localAudio = e;},onBack() {wx.navigateBack({delta: 1,})},}}
</script>
<style scoped>.container {width: 100vw;height: 100vh;background-color: #F5F5F5;position: fixed;top: 0;right: 0;left: 0;bottom: 0;}.trtc-demo-container {/* background-image: url(https://mc.qcloudimg.com/static/img/7da57e0050d308e2e1b1e31afbc42929/bg.png); *//* background-color: #333; *//* background-repeat:no-repeat;background-size: cover; */width: 100vw;height: 100vh;display: flex;flex-direction: column;align-items: center;box-sizing: border-box;}.trtc-demo-container .title{color: #FFFFFF;padding-top: 65rpx;line-height: 60rpx;}.trtc-demo-container .input-box {background-color: transparent;color: #333;padding: 2vw 5vw 1vw;border-bottom: 1px solid #577785;margin: 100rpx 0 40rpx 0;text-align: center;box-sizing: border-box;width: 80vw;}.trtc-demo-container .input-box input{font-size: 20px;}.choice-content {margin-top: 20rpx;width: 80vw;display: flex;flex-direction: column;/* justify-content: space-between;flex-wrap: wrap; */font-size: 14px;color: #333;}.label{display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 24rpx 0;}.choice-content switch {color: #00B38A;transform:scale(0.8);}.bottom-btn {position: fixed;width: 100vw;text-align: center;bottom: 5vh;}.bottom-btn .btn{width: 80%;background-color: #00B38A;border-radius: 50px;color: #ffffff;}.close {position:absolute;padding-left:5vw;padding-right:5vw;width:50rpx;height:60rpx;}
</style>

room.vue 会议页面(样式按自己需求调整): 实时音视频 API 概览-含 UI 集成方案-文档中心-腾讯云 (tencent.com)

<template><view class="template-grid"><view class="column-1"><!-- :class="playerList.length !=0? 'fullscreen':'fullscreen2'" --><view class="view-container fullscreen"><live-pusher class="pusher":data-userid="pusher.userID":data-streamid="pusher.streamID":data-streamtype="pusher.streamType":url="pusher.url" :mode="pusher.mode" :autopush="pusher.autopush":enable-camera="pusher.enableCamera" :enable-mic="pusher.enableMic":muted="!pusher.enableMic" :enable-agc="pusher.enableAgc" :enable-ans="pusher.enableAns":enable-ear-monitor="pusher.enableEarMonitor" :auto-focus="pusher.enableAutoFocus":zoom="pusher.enableZoom" :min-bitrate="pusher.minBitrate" :max-bitrate="pusher.maxBitrate":video-width="pusher.videoWidth" :video-height="pusher.videoHeight":beauty="pusher.beautyLevel" :whiteness="pusher.whitenessLevel":orientation="pusher.videoOrientation" :aspect="pusher.videoAspect":device-position="pusher.frontCamera" :remote-mirror="pusher.enableRemoteMirror":local-mirror="pusher.localMirror" :background-mute="pusher.enableBackgroundMute":audio-quality="pusher.audioQuality" :audio-volume-type="pusher.audioVolumeType":audio-reverb-type="pusher.audioReverbType" :waiting-image="pusher.waitingImage":debug="debug" :beauty-style="pusher.beautyStyle" :filter="pusher.filter"@statechange="_pusherStateChangeHandler" @netstatus="_pusherNetStatusHandler"@error="_pusherErrorHandler" @bgmstart="_pusherBGMStartHandler"@bgmprogress="_pusherBGMProgressHandler" @bgmcomplete="_pusherBGMCompleteHandler"@audiovolumenotify="_pusherAudioVolumeNotify" /><view class="no-video" v-if="!pusher.enableCamera"><image class="image" :src="require('../static/images/mute-camera-white.png')"></image></view><view class="no-audio" v-if="!pusher.enableMic"><image class="image" :src="require('../static/images/mute-mic-white.png')"></image></view><view class="audio-volume" v-if="pusher.enableMic"><image class="image" :src="require('../static/images/micro-open.png')"></image><view class="audio-active" :style="'height:' + pusher.volume + '%'"><image class="image" :src="require('../static/images/audio-active.png')"></image></view></view></view></view><swiper v-show="show_memberList" class="swiper" :indicator-dots="true" indicatorActiveColor="#00B38A"><swiper-item class="swiper-item" v-for="(items, index) in playerList" :key="index"><view v-for="(item, streamID) in items" :key="streamID" class="player-container":id="'player-' + item.streamID"><live-player class="player" :id="item.id":data-userid="item.userID":data-streamid="item.streamID":data-streamtype="item.streamType":src="item.src" mode="RTC":autoplay="item.autoplay" :mute-audio="item.muteAudio" :mute-video="item.muteVideo":orientation="item.orientation" :object-fit="item.objectFit":background-mute="item.enableBackgroundMute" :min-cache="item.minCache":max-cache="item.maxCache" :sound-mode="item.soundMode":enable-recv-message="item.enableRecvMessage":auto-pause-if-navigate="item.autoPauseIfNavigate":auto-pause-if-open-native="item.autoPauseIfOpenNative" :debug="debug"@statechange="_playerStateChange" @fullscreenchange="_playerFullscreenChange"@netstatus="_playerNetStatus" @audiovolumenotify="_playerAudioVolumeNotify" /><view class="no-video" v-if="item.muteVideo"><image class="image" :src="require('../static/images/display-pause-white.png')"></image><view class="text"><p>{{ item.userID }}</p></view></view><view class="no-video" v-if="!item.hasVideo && !item.muteVideo"><image class="image" :src="require('../static/images/mute-camera-white.png')"></image><view class="text"><p>{{ item.userID }}</p></view><view class="text"><p>对方摄像头未打开</p></view></view><view class="no-audio" v-if="!item.hasAudio"><image class="image" :src="require('../static/images/mute-mic-white.png')"></image></view><view class="audio-volume" v-if="item.hasAudio"><image class="image" :src="require('../static/images/micro-open.png')"></image><view class="audio-active" :style="'height:' + item.volume + '%'"><image class="image" :src="require('../static/images/audio-active.png')"></image></view></view><view class="sub-box"><image class="audio-image" @click="_mutePlayerAudio(item)" :src="item.muteAudio? require('../static/images/mute-mic-white.png') : require('../static/images/micro-open.png')"></image><image class="audio-image" @click="_mutePlayerVideo(item)" :src="item.muteVideo? require('../static/images/mute-camera-white.png') : require('../static/images/camera.png')"></image></view></view></swiper-item></swiper><view class="bottom-box"><view class="bottom-btns"><view class="btn-normal" @click="_pusherAudioHandler"><image class="btn-image":src="pusher.enableMic? require('../static/images/audio-true.png') : require('../static/images/audio-false.png')"></image></view><view class="btn-normal" @click="_pusherVideoHandler"><image class="btn-image":src="pusher.enableCamera? require('../static/images/camera-true.png') : require('../static/images/camera-false.png')"></image></view><view class="btn-hangup" @click="_hangUp"><image class="btn-image" :src="require('../static/images/hangup.png')"></image></view><view class="btn-normal"@click="_setPusherBeautyHandle"><image class="btn-image":src="pusher.beautyLevel == 9? require('../static/images/beauty-true.png') : require('../static/images/beauty-false.png')"></image></view><view class="btn-normal" @click="_switchMemberListPanel"><image class="btn-image" :src="require('../static/images/list.png')"></image></view></view></view><!-- <view class="panel memberlist-panel" v-if="show_memberList"><view @click="_handleClose" class='close-btn'>X</view><view class="panel-header">成员列表</view><view class="panel-body"><view class="panel-tips" v-if="playerList.length == 0">暂无成员</view><scroll-view class="scroll-container" scroll-y="true"><view v-for="(items, index) in playerList" :key="index"><view class="member-item" v-for="(item, streamID) in items" :key="streamID"><view class="member-id">{{ item.userID }}</view><view class="member-btns"><view class="btn"><image class="audio-image" @click="_mutePlayerAudio(item)":src="item.muteAudio? require('../static/images/mute-mic-white.png') : require('../static/images/micro-open.png')"></image></view><view class="btn"><image class="audio-image" @click="_mutePlayerVideo(item)":src="item.muteVideo? require('../static/images/mute-camera-white.png') : require('../static/images/camera.png')"></image></view></view></view></view></scroll-view></view></view> --></view>
</template>
<script>
import TRTC from '../static/trtc-wx';
import { mapState } from 'vuex';export default {data() {return {RtcConfig: {sdkAppID: '', // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppIDuserID: '', // 必要参数 用户 ID 可以由您的帐号系统指定userSig: '', // 必要参数 身份签名,相当于登录密码的作用},pusher: {enableCamera: false,},//切换后的主频pushed: {enableCamera: false,},playerList: [// {"sre":"room://cloud.tencent.com/rtc?userid=654&streamtype=main",//  "mode":"RTC", //  "autoplay":true, //  "muteAudio" :false, //  "mute Video" :true, //  " orientation": "vertical",// "objectFit":"fillCrop",// "enableBackgroundMute":false,// "minCache":1," maxCache":2, "soundMode":"speaker", // "enableRecMessage":false, "autoPauselfNavigate":true,// "autoPauselfOpenNative":true,"isVisible":true,// "_definitionType": "main", "netStatus":// {"videoBitrate":0, " audioBitrate":42, "videoFPS":0, "netSpeed"// :42, "netQualityLevel":1, " videoWidth":640, " videoHeight":480// }, "userID": "654","streamType": "main","streamID": "654_main", id: "654_main","hasVideo" :false, "hasAudio" :false, "volume":54},// {"sre":"room://cloud.tencent.com/rtc?userid=654&streamtype=main",//  "mode":"RTC", //  "autoplay":true, //  "muteAudio" :false, //  "mute Video" :true, //  " orientation": "vertical",// "objectFit":"fillCrop",// "enableBackgroundMute":false,// "minCache":1," maxCache":2, "soundMode":"speaker", // "enableRecMessage":false, "autoPauselfNavigate":true,// "autoPauselfOpenNative":true,"isVisible":true,// "_definitionType": "main", "netStatus":// {"videoBitrate":0, " audioBitrate":42, "videoFPS":0, "netSpeed"// :42, "netQualityLevel":1, " videoWidth":640, " videoHeight":480// }, "userID": "654","streamType": "main","streamID": "654_main", id: "654_main","hasVideo" :false, "hasAudio" :false, "volume":54},// {"sre":"room://cloud.tencent.com/rtc?userid=654&streamtype=main",//  "mode":"RTC", //  "autoplay":true, //  "muteAudio" :false, //  "mute Video" :true, //  " orientation": "vertical",// "objectFit":"fillCrop",// "enableBackgroundMute":false,// "minCache":1," maxCache":2, "soundMode":"speaker", // "enableRecMessage":false, "autoPauselfNavigate":true,// "autoPauselfOpenNative":true,"isVisible":true,// "_definitionType": "main", "netStatus":// {"videoBitrate":0, " audioBitrate":42, "videoFPS":0, "netSpeed"// :42, "netQualityLevel":1, " videoWidth":640, " videoHeight":480// }, "userID": "654","streamType": "main","streamID": "654_main", id: "654_main","hasVideo" :true, "hasAudio" :true, "volume":54},// {"sre":"room://cloud.tencent.com/rtc?userid=654&streamtype=main",//  "mode":"RTC", //  "autoplay":true, //  "muteAudio" :false, //  "mute Video" :true, //  " orientation": "vertical",// "objectFit":"fillCrop",// "enableBackgroundMute":false,// "minCache":1," maxCache":2, "soundMode":"speaker", // "enableRecMessage":false, "autoPauselfNavigate":true,// "autoPauselfOpenNative":true,"isVisible":true,// "_definitionType": "main", "netStatus":// {"videoBitrate":0, " audioBitrate":42, "videoFPS":0, "netSpeed"// :42, "netQualityLevel":1, " videoWidth":640, " videoHeight":480// }, "userID": "654","streamType": "main","streamID": "654_main", id: "654_main","hasVideo" :true, "hasAudio" :true, "volume":54},// {"sre":"room://cloud.tencent.com/rtc?userid=654&streamtype=main",//  "mode":"RTC", //  "autoplay":true, //  "muteAudio" :false, //  "mute Video" :true, //  " orientation": "vertical",// "objectFit":"fillCrop",// "enableBackgroundMute":false,// "minCache":1," maxCache":2, "soundMode":"speaker", // "enableRecMessage":false, "autoPauselfNavigate":true,// "autoPauselfOpenNative":true,"isVisible":true,// "_definitionType": "main", "netStatus":// {"videoBitrate":0, " audioBitrate":42, "videoFPS":0, "netSpeed"// :42, "netQualityLevel":1, " videoWidth":640, " videoHeight":480// }, "userID": "654","streamType": "main","streamID": "654_main", id: "654_main","hasVideo" :true, "hasAudio" :true, "volume":54}],show_memberList: false,localAudio: false,localVideo: false,myshow:true,shownum:true,}},/*** 生命周期函数--监听页面加载*/computed: {...mapState(['userInfo'])},onLoad(options) {console.log('room onload', options)wx.setKeepScreenOn({keepScreenOn: true,})this.TRTC = new TRTC(this)// 将String 类型的 true false 转换成 booleanObject.getOwnPropertyNames(options).forEach((key) => {if (options[key] === 'true') {options[key] = true}if (options[key] === 'false') {options[key] = false}})// this.playerList = this.sliceIntoChunks(this.playerList,2)//测试this.init(options)this.bindTRTCRoomEvent()this.enterRoom({ roomID: options.roomID })},onReady() {console.log('room ready')},onUnload() {console.log('room unload')},methods: {init(options) {console.log("options", options)// pusher 初始化参数const pusherConfig = {beautyLevel: 9,}const pusher = this.TRTC.createPusher(pusherConfig)console.log("pusher", pusher)console.log('userID', this.RtcConfig)this.RtcConfig.userID = options.userID;this.RtcConfig.sdkAppID = options.sdkAppID;this.RtcConfig.userSig = options.userSig;this.pusher = pusher.pusherAttributes;this.localAudio = options.localAudio;this.localVideo = options.localVideo;console.log(this.localAudio, this.localVideo)console.log("000000000000000")},enterRoom(options) {const roomID = options.roomIDconst config = Object.assign(this.RtcConfig, { roomID })this.pusher = this.TRTC.enterRoom(config);console.log("this.pusher", this.pusher)if (this.pusher) {this.TRTC.getPusherInstance().start() // 开始推流}},exitRoom() {const result = this.TRTC.exitRoom();this.pusher = result.pusher;this.playerList = this.sliceIntoChunks(result.playerList,2);},// 设置 pusher 属性setPusherAttributesHandler(options) {this.pusher = this.TRTC.setPusherAttributes(options);},// 设置某个 player 属性setPlayerAttributesHandler(player, options) {console.log("123",player, options,)//this.playerList = this.TRTC.setPlayerAttributes(player.streamID, options);let playerList = this.TRTC.setPlayerAttributes(player.streamID, options)this.playerList = this.sliceIntoChunks(playerList,2);console.log("12345678:",this.playerList)},// 事件监听bindTRTCRoomEvent() {const TRTC_EVENT = this.TRTC.EVENTconsole.log("xxxxxxxxxxxx", TRTC_EVENT)// 初始化事件订阅this.TRTC.on(TRTC_EVENT.LOCAL_JOIN, (event) => {console.log('* room LOCAL_JOIN', event)if (this.localVideo) {this.setPusherAttributesHandler({ enableCamera: true })}if (this.localAudio) {this.setPusherAttributesHandler({ enableMic: true })}})this.TRTC.on(TRTC_EVENT.LOCAL_LEAVE, (event) => {console.log('* room LOCAL_LEAVE', event)})this.TRTC.on(TRTC_EVENT.ERROR, (event) => {console.log('* room ERROR', event)})this.TRTC.on(TRTC_EVENT.REMOTE_USER_JOIN, (event) => {console.log('* room REMOTE_USER_JOIN', event)const { userID } = event.data;uni.showToast({title: `${userID} 进入了房间`,icon: 'none',duration: 2000,})})// 远端用户退出this.TRTC.on(TRTC_EVENT.REMOTE_USER_LEAVE, (event) => {console.log('* room REMOTE_USER_LEAVE', event)const { userID, playerList } = event.datathis.playerList = this.sliceIntoChunks(playerList,2);uni.showToast({title: `${userID} 离开了房间`,icon: 'none',duration: 2000,})})// 远端用户推送视频this.TRTC.on(TRTC_EVENT.REMOTE_VIDEO_ADD, (event) => {console.log('* room REMOTE_VIDEO_ADD', event)const { player } = event.data// 开始播放远端的视频流,默认是不播放的this.setPlayerAttributesHandler(player, { muteVideo: false })})// 远端用户取消推送视频this.TRTC.on(TRTC_EVENT.REMOTE_VIDEO_REMOVE, (event) => {console.log('* room REMOTE_VIDEO_REMOVE', event)const { player } = event.dataconsole.log("234",player)this.setPlayerAttributesHandler(player, { muteVideo: true })})// 远端用户推送音频this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_ADD, (event) => {console.log('* room REMOTE_AUDIO_ADD', event)const { player } = event.dataconsole.log("345",player)this.setPlayerAttributesHandler(player, { muteAudio: false })})// 远端用户取消推送音频this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_REMOVE, (event) => {console.log('* room REMOTE_AUDIO_REMOVE', event)const { player } = event.datathis.setPlayerAttributesHandler(player, { muteAudio: true })})this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_VOLUME_UPDATE, (event) => {console.log('* room REMOTE_AUDIO_VOLUME_UPDATE', event)const { playerList } = event.data;this.playerList = this.sliceIntoChunks(playerList,2);console.log("@@@@", this.playerList)})this.TRTC.on(TRTC_EVENT.LOCAL_AUDIO_VOLUME_UPDATE, (event) => {// console.log('* room LOCAL_AUDIO_VOLUME_UPDATE', event)const { pusher } = event.datathis.pusher = pusher;})},// 是否订阅某一个player Audio_mutePlayerAudio(player) {console.log('22222',player)//const player = event.currentTarget.dataset.valueif (player.hasAudio && player.muteAudio) {this.setPlayerAttributesHandler(player, { muteAudio: false })return}if (player.hasAudio && !player.muteAudio) {this.setPlayerAttributesHandler(player, { muteAudio: true })return}},// 订阅 / 取消订阅某一个player Audio_mutePlayerVideo(player) {console.log("1111")console.log(player)//const player = event.currentTarget.dataset.valueif (player.hasVideo && player.muteVideo) {this.setPlayerAttributesHandler(player, { muteVideo: false })return}if (player.hasVideo && !player.muteVideo) {this.setPlayerAttributesHandler(player, { muteVideo: true })return}},// 挂断退出房间_hangUp() {this.exitRoom()wx.navigateBack({delta: 1,})},// 设置美颜_setPusherBeautyHandle() {const beautyLevel = this.pusher.beautyLevel === 0 ? 9 : 0this.setPusherAttributesHandler({ beautyLevel })},// 订阅 / 取消订阅 Audio_pusherAudioHandler() {if (this.pusher.enableMic) {this.setPusherAttributesHandler({ enableMic: false })} else {this.setPusherAttributesHandler({ enableMic: true })}},// 订阅 / 取消订阅 Video_pusherVideoHandler() {if (this.pusher.enableCamera) {this.setPusherAttributesHandler({ enableCamera: false })} else {this.setPusherAttributesHandler({ enableCamera: true })}},_switchMemberListPanel() {if(this.playerList.length == 0){uni.showToast({title: "暂无成员",icon: 'none',duration: 2000,})}else{this.show_memberList = !this.show_memberList;}// this.setData({//   show_memberList: true// })},_handleClose() {this.show_memberList = false;// this.setData({//   show_memberList: false// })},// 请保持跟 wxml 中绑定的事件名称一致_pusherStateChangeHandler(event) {this.TRTC.pusherEventHandler(event)},_pusherNetStatusHandler(event) {this.TRTC.pusherNetStatusHandler(event)},_pusherErrorHandler(event) {this.TRTC.pusherErrorHandler(event)},_pusherBGMStartHandler(event) {this.TRTC.pusherBGMStartHandler(event)},_pusherBGMProgressHandler(event) {this.TRTC.pusherBGMProgressHandler(event)},_pusherBGMCompleteHandler(event) {this.TRTC.pusherBGMCompleteHandler(event)},_pusherAudioVolumeNotify(event) {this.TRTC.pusherAudioVolumeNotify(event)},_playerStateChange(event) {this.TRTC.playerEventHandler(event)},_playerFullscreenChange(event) {this.TRTC.playerFullscreenChange(event)},_playerNetStatus(event) {this.TRTC.playerNetStatus(event)},_playerAudioVolumeNotify(event) {this.TRTC.playerAudioVolumeNotify(event)},//数组重构sliceIntoChunks(arr, chunkSize) {const res = [];console.log(arr.length)for (let i = 0; i < arr.length; i += chunkSize) {const chunk = arr.slice(i, i + chunkSize);console.log(chunk)res.push(chunk);}return res;},//切换为主频toggle(e,i,j){// this.setPlayerAttributesHandler(e, { muteVideo: false })// console.log(this.shownum)// console.log('######',e,i,j)// console.log('zhu:',this.pusher,this.pusher.muteVideo,e.muteVideo)// if(e.userID == this.userInfo.userId){//   this.setPlayerAttributesHandler(this.pushed, { muteVideo: false })//    this.playerList[i].splice(j,1,this.pushed);//   this.myshow = true;//  this.shownum = true// }else{//     this.myshow = false;//     if(this.shownum){//         this.playerList[i].splice(j,1,this.pusher);//       this.pushed = e;//         this.shownum = false//     }else{//        this.shownum = false//          //this.setPlayerAttributesHandler(this.pushed, { muteVideo: false })//         this.playerList[i].splice(j,1,this.pushed);//       this.pushed = e;//     }// }// this.setPlayerAttributesHandler(e, { muteVideo: false })// console.log('######',e,i,j)// console.log('zhu:',this.pusher,this.pusher.muteVideo,e.muteVideo)if(e.userID == this.userInfo.userId){this.playerList[i].splice(j,1,this.pushed);this.myshow = true;}else{this.playerList[i].splice(j,1,this.pusher);this.pushed = e;this.myshow = false;}// this.setPlayerAttributesHandler(this.playerList, { muteVideo: false })console.log('$$$$$$$$$$$',this.playerList)},/*** 切换前后摄像头*/switchCamera() {if (!this.cameraPosition) {// this.data.pusher.cameraPosition 是初始值,不支持动态设置this.cameraPosition = this.pusher.frontCamera;}console.log(TAG_NAME, 'switchCamera', this.cameraPosition);this.cameraPosition = this.cameraPosition === 'front' ? 'back' : 'front';this.setData({cameraPosition: this.cameraPosition}, () => {console.log(TAG_NAME, 'switchCamera success', this.cameraPosition);}); // wx 7.0.9 不支持动态设置 pusher.frontCamera ,只支持调用 API switchCamer() 设置,这里修改 cameraPosition 是为了记录状态this.pusher.getPusherContext().switchCamera();},}
}
</script>
<style lang="less" scoped>
/* 9人 会议模版 */
.template-grid{width: 100vw;height: 100vh;overflow: hidden;background-color: #F5F5F5;/* background-image: url(https://mc.qcloudimg.com/static/img/7da57e0050d308e2e1b1e31afbc42929/bg.png); *//* display: flex;flex-direction: row;flex-wrap: wrap; */
}
.pusher {height: 100%;
}
.player{height: 100%;
}.column-1{// max-height: calc(100vh - 170rpx);// min-height: calc(100vh - 170rpx);display: flex;flex-direction: column;/*flex: 1;*/
}.view-container {position: relative;width: 100vh;
}
.no-video{position: absolute;top: 0;left: 0;width: 100%;height: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;box-sizing: border-box;color:#fff;background-color: rgba(0, 0, 0, 0.4);font-size: 24rpx;border-radius: 16rpx;.image{width: 60rpx;height: 60rpx;}
}.fullscreen{width: 100vw;height: calc(100vh - 196rpx);
}live-player {width: 100%;height: 100%;margin: 0;padding: 0;border-radius: 16rpx;
}.template-grid .btn-normal {width: 64rpx;height: 64rpx;margin: 0 6rpx;box-sizing: border-box;display: flex;background: rgba(255, 255, 255, 1);justify-content: center;align-items: center;border-radius: 50%;
}.template-grid .btn-normal .btn-image{width: 36rpx;height: 36rpx;
}.template-grid .btn-hangup {background: #f75c45;
}.template-grid .panel{position: absolute;background: rgba(0, 0, 0, 0.8);width: 90vw;height: auto;z-index: 999;top: 50vh;left: 50vw;transform: translate(-50%, -50%);color: white;display: flex;flex-direction: column;padding: 20rpx 0;border-radius: 10rpx;box-sizing: border-box;font-size: 24rpx;
}
.panel .close-btn {position: absolute;top: 0;right: 0;padding: 10rpx 20rpx;
}
.panel .panel-header{text-align: center;padding-bottom: 20rpx;
}
.panel .panel-tips {color: #999;text-align: center;
}
.panel .panel-body{flex: 1;max-height: 50vh;
}
.panel .panel-body .scroll-container{width: 100%;height: 100%;box-sizing: border-box;
}.memberlist-panel .panel-body{height: 30vh;.audio-image {padding: 0 12rpx;width: 40rpx;height: 40rpx;}
}
.memberlist-panel .member-item {display: flex;/* border-bottom: 1px solid #999; */margin: 16rpx 16rpx 16rpx 32rpx;
}
.memberlist-panel .member-id {width: 60%;font-size: 24rpx;line-height: 64rpx;
}
.memberlist-panel .member-btns{width: 70%;display: flex;justify-content: flex-end;
}
.memberlist-panel .member-btns .btn-normal{margin-left: 0;
}
.memberlist-panel .member-btns .btn{margin-right: 0;
}.sub-box{position: absolute;right: 10rpx;bottom: 24rpx;width: 80rpx;height: 172rpx;background-color: rgba(0,0,0,0.7);border-radius: 8rpx;display: flex;flex-direction: column;justify-content: space-around;.audio-image {padding: 0 14rpx;width: 48rpx;height: 48rpx;}
}.no-audio , .audio-volume{position: absolute;bottom: 20rpx;left: 20rpx;width: 36rpx;height: 36rpx;.image{width: 36rpx;height: 36rpx;position: absolute; /*android 的bug ,image absolute后会向上漂移几个像素,如果要对其必须都设置absolute*/}
}.audio-active {position: absolute;left: 0;bottom: 0;width: 100%;height: 0;overflow: hidden;
}
.audio-active .image{bottom: 0;
}.slide-up-tips {position: absolute;bottom: -100rpx;left: 50%;transform: translate(-50%, 0);width: 200rpx;height: auto;display: flex;flex-direction: column;align-items: center;justify-content: center;box-sizing: border-box;font-size: 24rpx;color: #fff;background-color: rgba(0, 0, 0, 0.4);box-sizing: border-box;padding: 20rpx;border-radius: 10rpx;opacity: 0;
}
.slide-up-tips .image {width: 100rpx;height: 100rpx;
}
.player-placeholder {display: flex;flex-direction: column;align-items: center;justify-content: center;
}
.player-placeholder .image {width: 100rpx;height: 100rpx;
}.bottom-box {width: 100vw;height: 196rpx;background-color: rgba(0,0,0,0.7);.bottom-btns {z-index: 3;width: 100vw;height: 100%;display: flex;flex-direction: row;align-items: center;justify-content: space-around;.btn-hangup  {width: 100rpx;height: 100rpx;background: #f75c45;box-sizing: border-box;display: flex;justify-content: center;align-items: center;border-radius: 50%;}}
}
.btn-normal {width: 72rpx;height: 72rpx;box-sizing: border-box;display: flex;background: white;justify-content: center;align-items: center;border-radius: 50%;
}
.btn-hangup .btn-image,
.btn-normal .btn-image{width: 48rpx;height: 48rpx;
}
.swiper{position: absolute;top: 40%;width: 100vw;height: 48vh;padding: 0 12rpx;background-color: #F5F5F5;.swiper-item{position: relative;background-color: #F5F5F5;display: flex;flex-direction: row;// flex-wrap: wrap;height: 95% !important;.player-container {border-radius: 16rpx;position: relative;margin: 24rpx 12rpx 12rpx 12rpx;width: 45%;height: 93%;}}
}
</style>

【多人会议功能】uniapp - 微信小程序 - 腾讯云相关推荐

  1. 【中级】 微信小程序 - 腾讯云 - wafer2 - PHP - DEMO - 003 - 源码分析 - 01 - 文件组成详细分析

    1 前言: 本文原创,欢迎转载,但是,务必保持原文并且给出原文链接. 微信小程序 - 腾讯云 - PHP - DEMO 是微信提供的一个微信小程序和腾讯云小程序云服务wafer 进行接口的例子. 本仓 ...

  2. php qcloud sdk weapp_微信小程序腾讯云php后台解决方案

    微信小程序腾讯云php后台解决方案 微信小程序前段需要添加必要的文件以配合后端 (1)wafer2-client-sdk sdk提供了几种接口包括登陆,获取用户openid,图片上传等 (2)conf ...

  3. uni-app 微信小程序 腾讯地图选点插件

    微信小程序插件 | 腾讯位置服务https://lbs.qq.com/miniProgram/plugin/pluginGuide/locationPicker 引入插件包和定位授权: "p ...

  4. 【中级】【后台】 微信小程序 - 腾讯云 - wafer2 - PHP - DEMO - 003 - 源码分析 - 03 - 腾讯后台初始化 和 CodeIgniter

    本文原创,欢迎转载,但是,务必保持原文并且给出原文链接. 前言: 本节对Wafer 服务端 SDK 是腾讯云为微信小程序开发者提供的快速开发库,SDK 封装了以下功能供小程序开发者快速调用的源码的初始 ...

  5. 【基础问题】微信小程序 - 腾讯云 - 一站式方案 - PHP - wafer 和 wafer2的区别和wafer2的实践

    前言: 项目目前选择了腾讯小程序一站式部署,反而有点懵了,服务器怎么配置呢?好像接口没有,查询后,发现有的Demo有服务器配置有的没有,折腾观察了一会,原来有两个版本wafer.我把关键的地方高亮了, ...

  6. Mpvue+koa开发微信小程序——腾讯云开发环境的搭建及部署实现真机测试

    为什么写这篇文章? 之前写过一篇文章:微信小程序开发错误:LoginError {type: "ERR_WX_GET_USER_INFO"}解决方法 有的伙伴在这篇文章中评论为什么 ...

  7. 【非常基础实践】 微信小程序 - 腾讯云 - PHP - DEMO - 002 - 云环境搭建和开通指引- 实践

    前言: 微信小程序最快捷的方式应该还是利用腾讯云做后台,本文对开启微信小程序和腾讯云的绑定实践了一下. 包括安装,开通,开发环境配置,生产环境配置.很大一部分内容来自官网 1 注册微信小程序(官网贴图 ...

  8. 微信小程序---腾讯云cos的使用---前端上传图片+后端生成临时密钥

    0. 腾讯云cos介绍: - 第一阶段:文件服务器,将文件存储在某个服务器(目录结构的划分). - 第二阶段:- 文件存储,将文件存储在某个服务器(目录结构的划分).- 对象存储,优化存储和操作优化( ...

  9. 微信小程序 腾讯云 mysql 初始_微信小程序初始化怎么处理?小程序服务器域名配置...

    小程序初始化配置指引 假如您已成功创建了小程序资源,需要对现有的资源进行一些简单配置后,才能让小程序跑起来 未创建过资源的用户可以先在小程序控制台进行创建 1.配置微信小程序通信域名 首先我们在小程序 ...

最新文章

  1. wp8.1 Study7: ListView 和GridView应用
  2. GetCurrentDirectory()函数误区
  3. MR8M CANCEL INVOICE后为什么要手工去FI清帐
  4. robcad和catia是什么关系_proe/CATIA/UG/SolidWorks软件区别与联系
  5. 华为手机怎么强制关机_华为忘记锁屏密码怎么办?多品牌手机通用解锁密码
  6. java se和ocjp_OCJP 考试题之七 - osc_sejhgcp0的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. ios支付 选择货币_iOS In-App Purchase中涉及到的货币单位
  8. 从why到how,双态IT的落地联想为何能走在最前列
  9. Json Schema 是什么?
  10. 哥德巴赫猜想 php,哥德巴赫猜想的程序验证
  11. 【资源帖】漏洞平台(国内外)+企业SRC整理-持续更新
  12. 写给四十岁男人的忠告
  13. word加上尾注之后参考文献下面的横线去除
  14. react使用二级(多级)路由(rout)实现局部跳转
  15. hibernate的Query和Criteria
  16. python软件可以申请著作权吗_什么样的软件可以申请软件著作权?
  17. FBX 解析 材质与贴图
  18. 让人无语的交通拥挤费
  19. 元宇宙开发者指南【Metaverse】
  20. windows找不到文件 pythonw

热门文章

  1. html在线商城购物网站制作——基于HTML+CSS+JavaScript(oppo手机商城 6页)
  2. 两个L组成的括号?(取整符号)
  3. 帆船运行员训练方法研究
  4. java不能安装_java环境安装之不能安装exe文件
  5. 愤怒大叔-喝酒聚会游戏
  6. spinal HDL - 01 - 环境搭建与Scala编程指南
  7. JS实现:哔哩哔哩2020校园招聘技术类笔试卷(二)
  8. 作为一本书,“卷”赢竞争对手的最佳姿势是?
  9. 【Security】操作系统安全
  10. html图片的边框属性,css3图片边框border-image的用法