目的:uniapp微信小程序通過騰訊云實現(xiàn)多人會議功能。
源碼下載地址:https://download.csdn.net/download/qq_39891453/86790793
效果展示:
功能實現(xiàn):
前提條件:?注冊騰訊云 賬號,并完成 實名認證。
推拉流標簽不支持個人小程序,要求申請的企業(yè)類微信小程序。
步驟一:開通微信小程序權(quán)限
推拉流標簽不支持個人小程序,要求申請的企業(yè)類微信小程序,登錄微信公眾平臺 =》開發(fā)?=》開發(fā)管理 =》接口設置,在其他接口中打開實時播放音視頻流和實時播放音視頻流。如圖:
步驟二:在微信小程序控制臺配置域名
在 微信公眾平臺?=》?開發(fā)?=》?開發(fā)管理?=》?開發(fā)設置?=》?服務器域名中設置 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
步驟三:下載多人會議功能源碼??源碼下載地址:https://download.csdn.net/download/qq_39891453/86790793
?項目結(jié)構(gòu)如圖所示:
步驟四:?開通騰訊云服務?
- 登錄到 即時通信 IM 控制臺,單擊創(chuàng)建新應用,在彈出的對話框中輸入您的應用名稱,并單擊確定。
- 單擊剛剛創(chuàng)建出的應用,進入基本配置頁面,并在頁面的右下角找到開通騰訊實時音視頻服務功能區(qū),單擊免費體驗即可開通 TUICallKit 的 7 天免費試用服務。
- 在同一頁面找到 SDKAppID 和密鑰并記錄下來。
步驟四:?配置 meeting =》debug =》GenerateTestUserSig.js 工程文件
設置 GenerateTestUserSig.js
文件中的相關(guān)參數(shù):文章來源:http://www.zghlxwxcb.cn/news/detail-455479.html
- 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: '房間號只能為數(shù)字',
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('授權(quán)成功', result)
wx.navigateTo({ url })
})
.catch((error) => {
console.log('沒有授權(quán)', error)
})
},
checkDeviceAuthorize() {
this.hasOpenDeviceAuthorizeModal = false
return new Promise((resolve, reject) => {
if (!wx.getSetting || !wx.getSetting()) {
// 微信測試版 獲取授權(quán)API異常,目前只能即使沒授權(quán)也可以通過
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']) {
// 授權(quán)成功
resolve()
} else {
// 沒有授權(quán),彈出授權(quán)窗口
// 注意: wx.authorize 只有首次調(diào)用會彈框,之后調(diào)用只返回結(jié)果,如果沒有授權(quán)需要自行彈框提示處理
console.log('getSetting 沒有授權(quán),彈出授權(quán)窗口', 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: '您沒有打開麥克風和攝像頭的權(quán)限,是否去設置打開?',
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 會議頁面(樣式按自己需求調(diào)整):?實時音視頻 API 概覽-含 UI 集成方案-文檔中心-騰訊云 (tencent.com)文章來源地址http://www.zghlxwxcb.cn/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: '', // 必要參數(shù) 開通實時音視頻服務創(chuàng)建應用后分配的 sdkAppID
userID: '', // 必要參數(shù) 用戶 ID 可以由您的帳號系統(tǒng)指定
userSig: '', // 必要參數(shù) 身份簽名,相當于登錄密碼的作用
},
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,
}
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
computed: {
...mapState(['userInfo'])
},
onLoad(options) {
console.log('room onload', options)
wx.setKeepScreenOn({
keepScreenOn: true,
})
this.TRTC = new TRTC(this)
// 將String 類型的 true false 轉(zhuǎn)換成 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 初始化參數(shù)
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)
},
// 事件監(jiān)聽
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)
},
//數(shù)組重構(gòu)
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 是初始值,不支持動態(tài)設置
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 不支持動態(tài)設置 pusher.frontCamera ,只支持調(diào)用 API switchCamer() 設置,這里修改 cameraPosition 是為了記錄狀態(tài)
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>
到了這里,關(guān)于【多人會議功能】uniapp - 微信小程序 - 騰訊云的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!