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

这篇具有很好参考价值的文章主要介绍了【多人会议功能】uniapp - 微信小程序 - 腾讯云。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

源码下载地址:https://download.csdn.net/download/qq_39891453/86790793

效果展示:

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

功能实现:

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

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

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

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

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

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

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

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

  •  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

步骤三:下载多人会议功能源码  源码下载地址:https://download.csdn.net/download/qq_39891453/86790793

 项目结构如图所示:【多人会议功能】uniapp - 微信小程序 - 腾讯云

步骤四: 开通腾讯云服务 

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

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

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

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

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

  • SDKAPPID:默认为0,请设置为实际的 SDKAppID。
  • SECRETKEY:默认为空字符串,请设置为实际的密钥信息。【多人会议功能】uniapp - 微信小程序 - 腾讯云

步骤五: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'; //userID
			    const 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 = nowTime
			    this.checkDeviceAuthorize().then((result) => {
			      console.log('授权成功', result)
			      wx.navigateTo({ url })
			    })
			      .catch((error) => {
			        console.log('没有授权', error)
			      })
			  },
			  checkDeviceAuthorize() {
			    this.hasOpenDeviceAuthorizeModal = false
			    return 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 = true
			            if (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 = true
			            if (this.authorizeMic) {
			              resolve()
			            } else {
			              this.openConfirm()
			              reject(new Error('authorize fail'))
			            }
			          })
			            .catch((error) => {
			              console.log('authorize camera error', error)
			              this.authorizeCamera = false
			              this.openConfirm()
			              reject(new Error('authorize fail'))
			            })
			        }
			      })
			    })
			  },
			  openConfirm() {
			    if (this.hasOpenDeviceAuthorizeModal) {
			      return
			    }
			    this.hasOpenDeviceAuthorizeModal = true
			    return uni.showModal({
			      content: '您没有打开麦克风和摄像头的权限,是否去设置打开?',
			      confirmText: '确认',
			      cancelText: '取消',
			      success: (res) => {
			        this.hasOpenDeviceAuthorizeModal = false
			        console.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)文章来源地址https://www.toymoban.com/news/detail-455479.html

<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: '', // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppID
				userID: '', // 必要参数 用户 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 转换成 boolean
		Object.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.roomID
			const 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.EVENT
			console.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.data
				this.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.data
				console.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.data
				console.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.data
				this.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.data
				this.pusher = pusher;
			})
		},

		// 是否订阅某一个player Audio
		_mutePlayerAudio(player) {
			console.log('22222',player)
			//const player = event.currentTarget.dataset.value
			if (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.value
			if (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 : 0
			this.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 - 微信小程序 - 腾讯云的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • uniapp微信小程序vue企业会议室预约系统python+python+nodejs+php

    该系统游客可以通过注册成为注册员工,之后就能够对会议室、车辆信息浏览与预约。员工登录后可以修改个人密码,这个主要是微信端登录的。服务端登录管理员;管理员在登录前选择自己的角色,然后登录该系统进行相应的操作。主要编辑上传、会议室、会议室预约、车

    2024年04月29日
    浏览(42)
  • uniapp&&微信小程序中打开腾讯地图获取用户位置信息

    个人项目地址: SubTopH前端开发个人站 (自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面) SubTopH前端开发个人站 https://subtop.gitee.io/subtoph.github.io/#/home 实现的效果 第一步:首先登录微信公众平

    2024年02月13日
    浏览(70)
  • 【uniapp】 微信小程序使用腾讯API地图、路线轨迹、marker标记点

    引入js import amap from \\\'@/common/qqmap-wx-jssdk.js\\\'; var qqmapsdk; qqmapsdk = new amap({ key: \\\'腾讯地图API key\\\' // 必填 }); 小程序配置合法域名 :https://apis.map.qq.com 下载地址 :请前往【小程序地图、腾讯API、商业圈、路线轨迹、地图选点】 示例图 请前往小程序查询

    2024年02月16日
    浏览(66)
  • 【微信小程序支付功能】uniapp实现微信小程序支付功能

    场景 :要实现公司微信小程序的电商模块微信支付功能 一.实现步骤和思路 在登录状态,登录的时候获取到code,利用code获取到 openid: https://blog.csdn.net/weixin_45308405/article/details/128868377?spm=1001.2014.3001.5501 在manifest.json文件“App模块配置”项的“Payment(支付)”下,勾选“微信支付

    2024年02月11日
    浏览(56)
  • UNIAPP 微信小程序实现分享功能

    默认情况下点击微信小程序调试器无法实现分享功能,如下图  此时需要设置如下操作,个人默认习惯是在 utils文件下 创建 share.js 文件 并写入代码 内容如下 然后打开main.js 修改如下 设置完成后再点击右上角的分享就打开了 回到组件内 如果需要通过按钮实现分享功能  参考

    2024年02月04日
    浏览(67)
  • uniapp微信小程序使用分享功能

    实现效果为如下所示的小程序分享功能: 本项目是一个使用uniapp搭建的微信小程序,上线后点击右上角的…,发现其中的发送给朋友和分享到朋友圈是如下图所示的灰色不能点击: 那么,如何设置微信小程序的分享功能呢? 第一步:在onLoad方法中写wx.showShareMenu方法,设置

    2024年02月11日
    浏览(46)
  • uniapp微信小程序地图功能实现教程

    本篇文章将介绍如何在uniapp中实现微信小程序的地图功能,包括获取appid和地图授权的key,以及具体的功能实现步骤。

    2024年02月05日
    浏览(119)
  • uniapp 微信小程序导航功能(单个地址)

    获取终点的坐标,根据终点的坐标,终点名称,终点详细地址,调起地图导航到第三方APP 1、针对单个地址导航

    2024年02月12日
    浏览(59)
  • uniapp 微信小程序分享、分享朋友圈功能

    页内自定义分享按钮 当页面js上没有添加事件“onShareAppMessage”,右上角‘…’不会出现“转发”事件。 如果有事件,但是没有定义事件内容的话,转发的卡片则是当前页面的截屏信息。 官方文档:https://uniapp.dcloud.io/api/plugins/share?id=onshareappmessage 方式1:小程序右上角原生菜

    2024年02月16日
    浏览(55)
  • uniapp 微信小程序导出excel功能实现

    需要用到xlsx.core.min.js的js库,以实现导出excel。 下载链接: SheetJS: https://github.com/SheetJS/sheetjs 找到dist目录下,xlsx.core.min.js文件,将它复制到你项目的/common/js/目录下。 1、导入js库; 2、编辑导出数据。  3、利用js库导出excel。 这样就可以了。

    2024年03月21日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包