当前位置:   article > 正文

记一下最近做的腾讯实时视频(TCRC)_腾讯trtc支持录屏吗

腾讯trtc支持录屏吗

记一下最近做的腾讯实时视频
业务需要,在客户端加一下跳转小程序,在小程序里面进行和pc客户的视频/语音通话。于是乎就用到了腾讯的tcrc实时视频。博客也有很多大佬做过了,我只是班门弄斧,记录一下自己弄的,我这里只列出了小程序的实现方式和代码,pc的没有列出。
pc端效果:
在这里插入图片描述
移动端效果
呼叫中:
在这里插入图片描述

接通后语音模式:
在这里插入图片描述

接通后视频模式:
在这里插入图片描述

1,官方demo
下载官方demo,附地址:https://github.com/undefineders/WXMiniByUniapp-TRTC,然后导入本地HbuilderX中,运行到小程序,如果运行成功进行下一步。
填好secret以及sdkid啥的运行到开发者工具,记住这样是不行的,要真机调试才可以看到效果。
2,我做的是uniapp,所以官方的demo对于我来说不能直接用,找了找,果然有大佬,把官方的转成了uniapp版本。
地址:https://ext.dcloud.net.cn/plugin?id=1286。
3,下载下来,删掉不用的(我这里用的是1v1)
这是我的组件目录
在这里插入图片描述
要使用人家这个uniapp里面的两个js文件,人家重写了setData方法
在这里插入图片描述
组件代码:基本未动,你只需要监控里面的一些操作(如挂断,切换摄像头等),还有更改一些字体图标

<template>
	<view>
		<view class="trtc-room-container">
			<view v-if="template === '1v1'">
				<view data-type="template" data-is="1v1" data-attr="pusher, streamList, debug">
					<view class="template-1v1">
						<view
							v-for="(item, streamID) in streamList"
							:key="streamID"
							v-if="item.src && (item.hasVideo || item.hasAudio)"
							:class="'view-container player-container ' + (item.isVisible ? '' : 'none')"
						>
						<!-- 对方视频 -->
							<!-- <live-player
								class="player"
								: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="playerStateChangeFun"
								@fullscreenchange="playerFullscreenChangeFun"
								@netstatus="playerNetStatusFun"
								@audiovolumenotify="playerAudioVolumeNotifyFun"
								:idAttr="item.streamID"
							></live-player> -->
						</view>
						<!-- 自身画面 -->
						<view v-show="pusher.enableCamera" :class="'view-container pusher-container ' + (pusher.isVisible ? '' : 'none') + ' ' + (JSON.stringify(streamList) == '[]' ? 'fullscreen' : '')">
							<live-pusher
								class="pusher"
								:url="pusher.url"
								:mode="pusher.mode"
								:autopush="pusher.autopush"
								:enable-camera="pusher.enableCamera"
								:enable-mic="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"
								@statechange="pusherStateChangeHandlerFun"
								@netstatus="pusherNetStatusHandlerFun"
								@error="pusherErrorHandlerFun"
								@bgmstart="pusherBGMStartHandlerFun"
								@bgmprogress="pusherBGMProgressHandlerFun"
								@bgmcomplete="pusherBGMCompleteHandlerFun"
							></live-pusher>
							<view class="loading" v-if="streamList.length === 0">
								<view class="loading-text">等待接听中...</view>
							</view>
						</view>
						<cover-view v-if="streamList.length != 0" class="calling-time">通话时间 {{ videoOrVoiceObj.msgIPtime.longTime}}</cover-view>
						<cover-view class="handle-btns" v-if="videoBtnsVisible">
							<!--视频/语音   toggleVideoFun -->
							<cover-view class="box-wrap" v-if="streamList.length != 0">
								<cover-view class="btn-normal" @click="toggleVideoFun">
									<cover-image class="closeVideoImg" v-if="pusher.enableCamera" :src="closeVideoImg"></cover-image>
									<cover-image class="videoImg" v-else :src="videoImg"></cover-image>
								</cover-view>
								<cover-view class="btn-word">{{pusher.enableCamera?'关闭摄像头':'打开摄像头'}}</cover-view>
							</cover-view>
							<!-- 挂断 -->
							<cover-view class="box-wrap">
								<cover-view class="btn-hangup" @click="hangUpFun"><cover-image :src="overImg"></cover-image></cover-view>
								<cover-view class="btn-word">挂断</cover-view>
							</cover-view>
							<!-- 静音 -->
							<!-- <cover-view class="btn-normal" bindtap="toggleSoundModeFun">
									<cover-image
										:src="
											streamList[0].soundMode === 'ear'
												? audioImg
												: videoImg
										"
								></cover-image>
								</view> -->
							<!-- 翻转镜头 -->
							<cover-view class="box-wrap" v-if="streamList.length != 0">
								<cover-view class="btn-normal" @click="switchCamera"><cover-image :src="turnCamera"></cover-image></cover-view>
								<cover-view class="btn-word">翻转镜头</cover-view>
							</cover-view>
						</cover-view>
						<view class="bottom-btns">
							
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
import overImg from '@/static/img/挂断.png'
import turnCamera from '@/static/img/翻转镜头.png'
import audioImg from '@/static/img/电话.png'
import videoImg from '@/static/img/摄像头.png'
import closeVideoImg from '@/static/img/关闭摄像头.png'
import { setData } from './debug/GenerateTestUserSig';
import UserController from './controller/user-controller';
import Pusher from './model/pusher';
import { EVENT } from './common/constants';
import Event from './utils/event';
import * as ENV from './utils/environment';
const TAG_NAME = 'TRTC-ROOM';
export default {
	data() {
		return {
			//几个图片
			overImg,
			turnCamera,
			audioImg,
			videoImg,
			closeVideoImg,
			//控制视频按钮显隐
			videoBtnsVisible:true,
			//自己写一个计时功能
			courentTime:0,
			videoOrVoiceObj:{
			//计时器
				msgIPtime:{
					timer: "",
					content: "",
					hour: 0,
					minutes: 0,
					seconds: 0,
					longTime:'00:00:00'
				}
			},
			pusher: null,
			// debugMode: false, // 是否开启调试模式
			debugPanel: true,
			// 是否打开组件调试面板
			debug: false,
			// 是否打开player pusher 的调试信息
			streamList: [],
			// 用于渲染player列表,存储stram
			userList: [],
			// 扁平化的数据用来返回给用户
			template: '',
			// 不能设置默认值,当默认值和传入组件的值不一致时,iOS渲染失败
			cameraPosition: '',
			panelName: '',
			// 控制面板名称,包括 setting-panel  memberlist-panel
			localVolume: 0,
			remoteVolumeList: [],
			appVersion: ENV.APP_VERSION,
			libVersion: ENV.LIB_VERSION,
			debugMode: ''
		};
	},

	components: {},
	props: {
		// 必要的初始化参数
		config: {
			type: Object,
			default: () => ({
				sdkAppID: '',
				userID: '',
				userSig: '',
				template: '',
				debugMode: ''
			})
		}
	},
	watch: {
		streamList(newVal, oldVal){
			console.log('streamList::::::::',newVal, oldVal)
			this.streamList = newVal
		},
		config: {
			handler: function(newVal, oldVal) {
				console.log('watch config');
				this.propertyObserverFun({
					name: 'config',
					newVal,
					oldVal
				});
			},
			deep: true
		}
	},
	created: function() {
		// 在组件实例刚刚被创建时执行
		console.log(TAG_NAME,'组建内部生命周期created', ENV);
	},
	beforeMount: function() {
		// 在组件实例进入页面节点树时执行
		console.log(TAG_NAME, '组建内部生命周期beforeMount  attached');
		this.initFun();
	},
	mounted: function() {
		// 在组件在视图层布局完成后执行
		console.log(TAG_NAME, '组建内部生命周期Mounted  ready');
	},
	destroyed: function() {
		// 在组件实例被从页面节点树移除时执行
		console.log(TAG_NAME, '组建内部生命周期destroyed  detached'); // 停止所有拉流,并重置数据
		//退房
		this.exitRoom();
	},
	error: function(error) {
		// 每当组件方法抛出错误时执行
		console.log(TAG_NAME, '组建方法报错  error', error);
	},
	onPageShow: function() {
		// 组件所在的页面被展示时执行
		console.log(TAG_NAME, '组建所在页面展示  show status:', this.status);

		if (this.status.isPending) {
			// 经历了 5000 挂起事件
			this.status.isPending = false;
		}

		if (this.status.isPush) {
			// 小程序hide - show 有一定概率本地黑屏或静止,远端正常,或者远端和本地同时黑屏或静止,需要手动启动预览,非必现
			// this.data.pusher.getPusherContext().startPreview()
			// this.data.pusher.getPusherContext().resume()
		}
	},
	onPageHide: function() {
		// 组件所在的页面被隐藏时执行
		console.log(TAG_NAME, 'hide');
	},
	onPageResize: function(size) {
		// 组件所在的页面尺寸变化时执行
		console.log(TAG_NAME, 'resize', size);
	},
	methods: {
		setData,
		//隐藏
		hiddenBtns(){
			console.log('隐藏')
			this.videoBtnsVisible = false
		},
		//显示
		refreshBtns(){
			console.log('显示')
			this.videoBtnsVisible = true
		},
		//我写的计时功能
		initTime() {
			console.log('不执行吗?')
			/*时间处理*/
			this.timer = setInterval(() => {
				this.courentTime = new Date().getTime();
			}, 1000);
		},
		//通话时长
		ipVoiceOrVideoLongTimeClick(){
			this.videoOrVoiceObj.msgIPtime.timer = setInterval(this.startMsgIPtimeTimer, 1000);
		},
		startMsgIPtimeTimer () {
			this.videoOrVoiceObj.msgIPtime.seconds += 1;
			if ( this.videoOrVoiceObj.msgIPtime.seconds >= 60) {
				this.videoOrVoiceObj.msgIPtime.seconds = 0;
				this.videoOrVoiceObj.msgIPtime.minutes += 1;
			}
			if ( this.videoOrVoiceObj.msgIPtime.minutes >= 60) {
				this.videoOrVoiceObj.msgIPtime.minutes = 0;
				this.videoOrVoiceObj.msgIPtime.hour =  this.videoOrVoiceObj.msgIPtime.hour + 1;
			}
		this.videoOrVoiceObj.msgIPtime.longTime =( this.videoOrVoiceObj.msgIPtime.hour < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.hour :  this.videoOrVoiceObj.msgIPtime.hour) + ':'+ ( this.videoOrVoiceObj.msgIPtime.minutes < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.minutes :  this.videoOrVoiceObj.msgIPtime.minutes) + ':' + ( this.videoOrVoiceObj.msgIPtime.seconds < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.seconds :  this.videoOrVoiceObj.msgIPtime.seconds);
		},
		resetMsgIPtime(){  //重置
			clearInterval(this.videoOrVoiceObj.msgIPtime.timer);
			this.videoOrVoiceObj.msgIPtime.hour=0;
			this.videoOrVoiceObj.msgIPtime.minute=0;
			this.videoOrVoiceObj.msgIPtime.ms=0;
			this.videoOrVoiceObj.msgIPtime.seconds=0;
			this.videoOrVoiceObj.msgIPtime.longTime="00:00:00";
		},
		stopMsgIPtime(){  //暂停
			clearInterval(this.videoOrVoiceObj.msgIPtime.timer);
		},
		/**
		 * 初始化各项参数和用户控制模块,在组件实例触发 attached 时调用,此时不建议对View进行变更渲染(调用setData方法)
		 */
		initFun: function() {
			console.log(TAG_NAME, '初始化各参数  _init');
			this.userController = new UserController(this);
			this._emitter = new Event();
			this.EVENT = EVENT;
			//初始化推流拉流状态
			this.initStatusFun();
			//远端用户和音视频状态处理
			this.bindEventFun();
			//grid布局, 绑定事件
			this.bindEventGridFun();
			console.log(TAG_NAME, '初始化参数成功 _init success component:', this);
		},

		/**
		 * 进房
		 * @param {Object} params 必传 roomID 取值范围 1 ~ 4294967295
		 * @returns {Promise}
		 */
		enterRoom: function(params) {
			return new Promise((resolve, reject) => {
				// this.pusher = {}
				console.log(TAG_NAME, 'enterRoom');
				console.log(TAG_NAME, 'params', params);
				console.log(TAG_NAME, 'config', this.config);
				console.log(TAG_NAME, 'pusher', this.pusher); // 1. 补齐进房参数,校验必要参数是否齐全
				console.log('进房......', params, this.config, this.pusher);
				if (params) {
					Object.assign(this.pusher, params);
					Object.assign(this.config, params);
				}
				if (!this.checkParamFun(this.config)) {
					reject(new Error('缺少必要参数'));
					return;
				} // 2. 根据参数拼接 push url,赋值给 live-pusher,
				console.log('解决',this.config)
				this.getPushUrlFun(this.config)
					.then(pushUrl => {
						this.pusher.url = pushUrl;
						this.setData(
							{
								pusher: this.pusher,
							},
							() => {
								console.log(TAG_NAME, '进房成功', this.pusher); // view 渲染成功回调后,开始推流
								this.pusher.getPusherContext().start();
								this.status.isPush = true;
								resolve();
							}
						);
					})
					.catch(res => {
						// 获取 room sig 失败, 进房失败需要通过 pusher state 事件通知
						console.error(TAG_NAME, '进房失败', res);
						reject(res);
					});
			});
		},

		/**
		 * 退房,停止推流和拉流,并重置数据
		 * @returns {Promise}
		 */
		exitRoom: function() {
			return new Promise((resolve, reject) => {
				console.log(TAG_NAME, '退出房间');
				this.pusher.reset();
				this.status.isPush = false;
				const result = this.userController.reset();
				this.setData(
					{
						pusher: this.pusher,
						userList: result.userList,
						streamList: result.streamList
					},
					() => {
						// 在销毁页面时调用,不会走到这里
						resolve({
							userList: this.userList,
							streamList: this.streamList
						});
						console.log(TAG_NAME, '退出房间成功', this.pusher, this.streamList, this.userList);
					}
				);
			});
		},

		/**
		 * 开启摄像头
		 * @returns {Promise}
		 */
		publishLocalVideo: function() {
			// 设置 pusher enableCamera
			console.log(TAG_NAME, '这里这里publishLocalVideo 开启摄像头',this.pusher,this.cameraPosition);
			return this.setPusherConfigFun({
				enableCamera: true,
			});
		},

		/**
		 * 关闭摄像头
		 * @returns {Promise}
		 */
		unpublishLocalVideo: function() {
			// 设置 pusher enableCamera
			console.log(TAG_NAME, 'unpublshLocalVideo 关闭摄像头');
			return this.setPusherConfigFun({
				enableCamera: false
			});
		},

		/**
		 * 开启麦克风
		 * @returns {Promise}
		 */
		publishLocalAudio: function() {
			// 设置 pusher enableCamera
			console.log(TAG_NAME, 'publishLocalAudio 开启麦克风');
			return this.setPusherConfigFun({
				enableMic: true
			});
		},

		/**
		 * 关闭麦克风
		 * @returns {Promise}
		 */
		unpublishLocalAudio: function() {
			// 设置 pusher enableCamera
			console.log(TAG_NAME, 'unpublshLocalAudio 关闭麦克风');
			return this.setPusherConfigFun({
				enableMic: false
			});
		},

		/**
		 * 订阅远端视频 主流 小画面 辅流
		 * @param {Object} params {userID,streamType} streamType 传入 small 时修改对应的主流url的 streamtype 参数为small
		 * @returns {Promise}
		 */
		subscribeRemoteVideo(params) {
			console.log(TAG_NAME, '订阅远端视频', params); // 设置指定 user streamType 的 muteVideo 为 false

			const config = {
				muteVideo: false
			}; // 本地数据结构里的 streamType 只支持 main 和 aux ,订阅small 也是对main进行处理

			const streamType = params.streamType === 'small' ? 'main' : params.streamType;

			if (params.streamType === 'small' || params.streamType === 'main') {
				const stream = this.userController.getStream({
					userID: params.userID,
					streamType: streamType
				});

				if (stream && stream.streamType === 'main') {
					console.log(TAG_NAME, 'subscribeRemoteVideo switch small', stream.src);

					if (params.streamType === 'small') {
						config.src = stream.src.replace('main', 'small');
						config._definitionType = 'small'; // 用于设置面板的渲染
					} else if (params.streamType === 'main') {
						stream.src = stream.src.replace('small', 'main');
						config._definitionType = 'main';
					}

					console.log(TAG_NAME, 'subscribeRemoteVideo', stream.src);
				}
			}

			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: streamType,
				config: config
			});
		},

		/**
		 * 取消订阅远端视频
		 * @param {Object} params {userID,streamType}
		 * @returns {Promise}
		 */
		unsubscribeRemoteVideo(params) {
			console.log(TAG_NAME, '取消订阅远端视频', params); // 设置指定 user streamType 的 muteVideo 为 true

			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					muteVideo: true
				}
			});
		},

		/**
		 * 订阅远端音频
		 * @param {Object} params userID 用户ID
		 * @returns {Promise}
		 */
		subscribeRemoteAudio(params) {
			console.log(TAG_NAME, '订阅远端音频', params);
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: 'main',
				config: {
					muteAudio: false
				}
			});
		},

		/**
		 * 取消订阅远端音频
		 * @param {Object} params userID 用户ID
		 * @returns {Promise}
		 */
		unsubscribeRemoteAudio(params) {
			console.log(TAG_NAME, '取消订阅远端音频', params);
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: 'main',
				config: {
					muteAudio: true
				}
			});
		},

		on: function(eventCode, handler, context) {
			this._emitter.on(eventCode, handler, context);
		},
		off: function(eventCode, handler) {
			this._emitter.off(eventCode, handler);
		},
		getRemoteUserList: function() {
			return this.userList;
		},

		/**
		 * 切换前后摄像头
		 */
		switchCamera: function(val) {
			console.log('点击了翻转镜头',val)
			if (!this.cameraPosition) {
				// this.data.pusher.cameraPosition 是初始值,不支持动态设置
				this.cameraPosition = this.pusher.frontCamera;
			}

			console.log(TAG_NAME, '翻转镜头', this.cameraPosition);
			this.cameraPosition = this.cameraPosition === 'front' ? 'back' : 'front';
			this.setData(
				{
					cameraPosition: this.cameraPosition
				},
				() => {
					console.log(TAG_NAME, '翻转镜头 成功', this.cameraPosition);
				}
			); // wx 7.0.9 不支持动态设置 pusher.devicePosition ,需要调用api设置,这里修改cameraPosition是为了记录状态

			this.pusher.getPusherContext().switchCamera();
		},

		/**
		 * 设置指定player view的渲染坐标和尺寸
		 * @param {object} params
		 * userID: string
		 * streamType: string
		 * xAxis: number
		 * yAxis: number
		 * width: number
		 * height: number
		 * @returns {Promise}
		 */
		setViewRect: function(params) {
			console.log(TAG_NAME, 'setViewRect', params);

			if (this.pusher.template !== 'custom') {
				console.warn(`如需使用setViewRect方法,请设置template:"custom", 当前 template:"${this.pusher.template}"`);
			}

			if (this.pusher.userID === params.userID) {
				return this.setPusherConfigFun({
					xAxis: params.xAxis,
					yAxis: params.yAxis,
					width: params.width,
					height: params.height
				});
			}

			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					xAxis: params.xAxis,
					yAxis: params.yAxis,
					width: params.width,
					height: params.height
				}
			});
		},

		/**
		 * 设置指定 player 或者 pusher view 是否可见
		 * @param {object} params
		 * userID: string
		 * streamType: string
		 * isVisible:boolean
		 * @returns {Promise}
		 */
		setViewVisible: function(params) {
			console.log(TAG_NAME, 'setViewVisible', params); // if (this.data.pusher.template !== 'custom') {
			//   console.warn(`如需使用setViewVisible方法,请设置template:"custom", 当前 template:"${this.data.pusher.template}"`)
			// }

			if (this.pusher.userID === params.userID) {
				return this.setPusherConfigFun({
					isVisible: params.isVisible
				});
			}

			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					isVisible: params.isVisible
				}
			});
		},

		/**
		 * 设置指定player view的层级
		 * @param {Object} params
		 * userID: string
		 * streamType: string
		 * zindex: number
		 * @returns {Promise}
		 */
		setViewZIndex: function(params) {
			console.log(TAG_NAME, 'setViewZIndex', params);

			if (this.pusher.template !== 'custom') {
				console.warn(`如需使用setViewZIndex方法,请设置template:"custom", 当前 template:"${this.pusher.template}"`);
			}

			if (this.pusher.userID === params.userID) {
				return this.setPusherConfigFun({
					zindex: params.zindex
				});
			}

			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					zindex: params.zindex
				}
			});
		},

		/**
		 * 播放背景音
		 * @param {Object} params url
		 * @returns {Promise}
		 */
		playBGM: function(params) {
			return new Promise((resolve, reject) => {
				this.pusher.getPusherContext().playBGM({
					url: params.url,
					// 已经有相关事件不需要在这里监听,目前用于测试
					success: () => {
						console.log(TAG_NAME, '播放背景音成功'); // this._emitter.emit(EVENT.BGM_PLAY_START)

						resolve();
					},
					fail: () => {
						console.log(TAG_NAME, '播放背景音失败');

						this._emitter.emit(EVENT.BGM_PLAY_FAIL);

						reject(new Error('播放背景音失败'));
					} // complete: () => {
					//   console.log(TAG_NAME, '背景完成')
					//   this._emitter.emit(EVENT.BGM_PLAY_COMPLETE)
					// },
				});
			});
		},
		stopBGM: function() {
			this.pusher.getPusherContext().stopBGM();
		},
		pauseBGM: function() {
			this.pusher.getPusherContext().pauseBGM();
		},
		resumeBGM: function() {
			this.pusher.getPusherContext().resumeBGM();
		},

		/**
		 * 设置背景音音量
		 * @param {Object} params volume
		 */
		setBGMVolume: function(params) {
			this.pusher.getPusherContext().setBGMVolume({
				volume: params.volume
			});
		},

		/**
		 * 设置麦克风音量
		 * @param {Object} params volume
		 */
		setMICVolume: function(params) {
			this.pusher.getPusherContext().setMICVolume({
				volume: params.volume
			});
		},

		/**
		 * 发送SEI消息
		 * @param {Object} params message
		 * @returns {Promise}
		 */
		sendSEI: function(params) {
			return new Promise((resolve, reject) => {
				this.pusher.getPusherContext().sendMessage({
					msg: params.message,
					success: function(result) {
						resolve(result);
					}
				});
			});
		},

		/**
		 * pusher 和 player 的截图并保存
		 * @param {Object} params userID streamType
		 * @returns {Promise}
		 */
		snapshot: function(params) {
			console.log(TAG_NAME, 'snapshot', params);
			return new Promise((resolve, reject) => {
				this.captureSnapshot(params)
					.then(result => {
						wx.saveImageToPhotosAlbum({
							filePath: result.tempImagePath,

							success(res) {
								wx.showToast({
									title: '已保存到相册'
								});
								console.log('save photo is success', res);
								resolve(result);
							},

							fail: function(error) {
								wx.showToast({
									icon: 'none',
									title: '保存失败'
								});
								console.log('save photo is fail', error);
								reject(error);
							}
						});
					})
					.catch(error => {
						reject(error);
					});
			});
		},

		/**
		 * 获取pusher 和 player 的截图
		 * @param {Object} params userID streamType
		 * @returns {Promise}
		 */
		captureSnapshot: function(params) {
			return new Promise((resolve, reject) => {
				if (params.userID === this.pusher.userID) {
					// pusher
					this.pusher.getPusherContext().snapshot({
						quality: 'raw',
						complete: result => {
							console.log(TAG_NAME, 'snapshot pusher', result);

							if (result.tempImagePath) {
								resolve(result);
							} else {
								console.log('snapShot 回调失败', result);
								reject(new Error('截图失败'));
							}
						}
					});
				} else {
					// player
					this.userController.getStream(params).playerContext.snapshot({
						quality: 'raw',
						complete: result => {
							console.log(TAG_NAME, 'snapshot player', result);

							if (result.tempImagePath) {
								resolve(result);
							} else {
								console.log('snapShot 回调失败', result);
								reject(new Error('截图失败'));
							}
						}
					});
				}
			});
		},

		/**
		 * 将远端视频全屏
		 * @param {Object} params userID streamType direction
		 * @returns {Promise}
		 */
		enterFullscreen: function(params) {
			console.log(TAG_NAME, 'enterFullscreen', params);
			return new Promise((resolve, reject) => {
				this.userController.getStream(params).playerContext.requestFullScreen({
					direction: params.direction || 0,
					success: event => {
						console.log(TAG_NAME, 'enterFullscreen success', event);
						resolve(event);
					},
					fail: event => {
						console.log(TAG_NAME, 'enterFullscreen fail', event);
						reject(event);
					}
				});
			});
		},

		/**
		 * 将远端视频取消全屏
		 * @param {Object} params userID streamType
		 * @returns {Promise}
		 */
		exitFullscreen: function(params) {
			console.log(TAG_NAME, 'exitFullscreen', params);
			return new Promise((resolve, reject) => {
				this.userController.getStream(params).playerContext.exitFullScreen({
					success: event => {
						console.log(TAG_NAME, 'exitFullScreen success', event);
						resolve(event);
					},
					fail: event => {
						console.log(TAG_NAME, 'exitFullScreen fail', event);
						reject(event);
					}
				});
			});
		},

		/**
		 * 设置 player 视图的横竖屏显示
		 * @param {Object} params userID streamType orientation: vertical, horizontal
		 * @returns {Promise}
		 */
		setRemoteOrientation: function(params) {
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					orientation: params.orientation
				}
			});
		},
		// 改为:
		setViewOrientation: function(params) {
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					orientation: params.orientation
				}
			});
		},

		/**
		 * 设置 player 视图的填充模式
		 * @param {Object} params userID streamType fillMode: contain,fillCrop
		 * @returns {Promise}
		 */
		setRemoteFillMode: function(params) {
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					objectFit: params.fillMode
				}
			});
		},
		// 改为:
		setViewFillMode: function(params) {
			return this.setPlayerConfigFun({
				userID: params.userID,
				streamType: params.streamType,
				config: {
					objectFit: params.fillMode
				}
			});
		},

		/**
		 * 切换 player 大小画面
		 * @param {Object} params userID streamType definition: HD SD
		 * @returns {Promise}
		 */
		setRemoteDefinitionFun: function(params) {
			params.streamType = 'main';
			return new Promise((resolve, reject) => {
				const stream = this.userController.getStream({
					userID: params.userID,
					streamType: params.streamType
				});

				if (stream && stream.streamType === 'main') {
					console.log(TAG_NAME, '_switchStreamType', stream.src); // stream.volume = volume

					if (stream.src.indexOf('main') > -1) {
						stream.src = stream.src.replace('main', 'small');
						stream._streamType = 'small'; // 用于设置面板的渲染
					} else if (stream.src.indexOf('small') > -1) {
						stream.src = stream.src.replace('small', 'main');
						stream._streamType = 'main';
					}

					console.log(TAG_NAME, '_switchStreamType', stream.src);
					this.setData(
						{
							streamList: this.streamList
						},
						() => {}
					);
				}
			});
		},

		initStatusFun() {
			this.status = {
				isPush: false,
				// 推流状态
				isPending: false // 挂起状态,触发5000事件标记为true,onShow后标记为false
			};
			this._lastTapTime = 0;
			this._beforeLastTapTime = 0;
			this._isFullscreen = false;
		},

		/**
		 * 设置推流参数并触发页面渲染更新
		 * @param {Object} config live-pusher 的配置
		 * @returns {Promise}
		 */
		setPusherConfigFun(config) {
			console.log(TAG_NAME, '_setPusherConfig', config, this.pusher);
			return new Promise((resolve, reject) => {
				if (!this.pusher) {
					this.pusher = new Pusher(config);
				} else {
					Object.assign(this.pusher, config);
				}

				this.setData(
					{
						pusher: this.pusher
					},
					() => {
						// console.log(TAG_NAME, '_setPusherConfig setData compelete', 'config:', config, 'pusher:', this.data.pusher)
						resolve(config);
					}
				);
			});
		},

		/**
		 *
		 * @param {Object} params include userID,streamType,config
		 * @returns {Promise}
		 */
		setPlayerConfigFun(params) {
			const userID = params.userID;
			const streamType = params.streamType;
			const config = params.config;
			console.log(TAG_NAME, '_setPlayerConfig', params);
			return new Promise((resolve, reject) => {
				// 获取指定的userID streamType 的 stream
				const user = this.userController.getUser(userID);

				if (user && user.streams[streamType]) {
					user.streams[streamType] = Object.assign(user.streams[streamType], config); // user.streams引用的对象和 streamList 里的是同一个

					this.setData(
						{
							streamList: this.streamList
						},
						() => {
							// console.log(TAG_NAME, '_setPlayerConfig complete', params, 'streamList:', this.data.streamList)
							resolve(params);
						}
					);
				} else {
					// 不需要reject,静默处理
					console.warn(TAG_NAME, '指定 userID 或者 streamType 不存在'); // reject(new Error('指定 userID 或者 streamType 不存在'))
				}
			});
		},

		/**
		 * 必选参数检测
		 * @param {Object} rtcConfig rtc参数
		 * @returns {Boolean}
		 */
		checkParamFun: function(rtcConfig) {
			console.log(TAG_NAME, 'checkParam config:', rtcConfig);

			if (!rtcConfig.sdkAppID) {
				console.error('未设置 sdkAppID');
				return false;
			}

			if (rtcConfig.roomID === undefined) {
				console.error('未设置 roomID');
				return false;
			}

			if (rtcConfig.roomID < 1 || rtcConfig.roomID > 4294967296) {
				console.error('roomID 超出取值范围 1 ~ 4294967295');
				return false;
			}

			if (!rtcConfig.userID) {
				console.error('未设置 userID');
				return false;
			}

			if (!rtcConfig.userSig) {
				console.error('未设置 userSig');
				return false;
			}

			if (!rtcConfig.template) {
				console.error('未设置 template');
				return false;
			}

			return true;
		},
		getPushUrlFun: function(rtcConfig) {
			// 拼接 puhser url rtmp 方案
			console.log(TAG_NAME, 'getPushUrl', rtcConfig);

			if (ENV.IS_TRTC) {
				// 版本高于7.0.8,基础库版本高于2.10.0 使用新的 url
				return new Promise((resolve, reject) => {
					// appscene videocall live
					// cloudenv PRO CCC DEV UAT
					// encsmall 0
					// 对外的默认值是rtc ,对内的默认值是videocall
					rtcConfig.scene = !rtcConfig.scene || rtcConfig.scene === 'rtc' ? 'videocall' : 'live';
					rtcConfig.enableBlackStream = rtcConfig.enableBlackStream || 1;
					rtcConfig.encsmall = rtcConfig.encsmall || 0;
					rtcConfig.cloudenv = rtcConfig.cloudenv || 'PRO';
					setTimeout(() => {
						const pushUrl =
							'room://cloud.tencent.com/rtc?sdkappid=' +
							rtcConfig.sdkAppID +
							'&roomid=' +
							rtcConfig.roomID +
							'&userid=' +
							rtcConfig.userID +
							'&usersig=' +
							rtcConfig.userSig +
							'&appscene=' +
							rtcConfig.scene +
							'&encsmall=' +
							rtcConfig.encsmall +
							'&cloudenv=' +
							rtcConfig.cloudenv;
						console.log(TAG_NAME, 'getPushUrl result:', pushUrl);
						resolve(pushUrl);
					}, 0);
				});
			}

			return this.requestSigServerFun(rtcConfig);
		},

		/**
		 * 获取签名和推流地址
		 * @param {Object} rtcConfig 进房参数配置
		 * @returns {Promise}
		 */
		requestSigServerFun: function(rtcConfig) {
			console.log('requestSigServer:', rtcConfig);
			const sdkAppID = rtcConfig.sdkAppID;
			const userID = rtcConfig.userID;
			const userSig = rtcConfig.userSig;
			const roomID = rtcConfig.roomID;
			const privateMapKey = rtcConfig.privateMapKey;
			rtcConfig.useCloud = rtcConfig.useCloud === undefined ? true : rtcConfig.useCloud;
			let url = rtcConfig.useCloud ? 'https://official.opensso.tencent-cloud.com/v4/openim/jsonvideoapp' : 'https://yun.tim.qq.com/v4/openim/jsonvideoapp';
			url += '?sdkappid=' + sdkAppID + '&identifier=' + userID + '&usersig=' + userSig + '&random=' + Date.now() + '&contenttype=json';
			const reqHead = {
				Cmd: 1,
				SeqNo: 1,
				BusType: 7,
				GroupId: roomID
			};
			const reqBody = {
				PrivMapEncrypt: privateMapKey,
				TerminalType: 1,
				FromType: 3,
				SdkVersion: 26280566
			};
			console.log('requestSigServer:', url, reqHead, reqBody);
			return new Promise((resolve, reject) => {
				wx.request({
					url: url,
					data: {
						ReqHead: reqHead,
						ReqBody: reqBody
					},
					method: 'POST',
					success: res => {
						console.log('requestSigServer success:', res);

						if (res.data['ErrorCode'] || res.data['RspHead']['ErrorCode'] !== 0) {
							// console.error(res.data['ErrorInfo'] || res.data['RspHead']['ErrorInfo'])
							console.error('获取roomsig失败');
							reject(res);
						}

						const roomSig = JSON.stringify(res.data['RspBody']);
						let pushUrl = 'room://cloud.tencent.com?sdkappid=' + sdkAppID + '&roomid=' + roomID + '&userid=' + userID + '&roomsig=' + encodeURIComponent(roomSig); // TODO 需要重新整理的逻辑
						// 如果有配置纯音频推流或者recordId参数

						if (rtcConfig.pureAudioPushMod || rtcConfig.recordId) {
							const bizbuf = {
								Str_uc_params: {
									pure_audio_push_mod: 0,
									record_id: 0
								}
							}; // 纯音频推流

							if (rtcConfig.pureAudioPushMod) {
								bizbuf.Str_uc_params.pure_audio_push_mod = rtcConfig.pureAudioPushMod;
							} else {
								delete bizbuf.Str_uc_params.pure_audio_push_mod;
							} // 自动录制时业务自定义id

							if (rtcConfig.recordId) {
								bizbuf.Str_uc_params.record_id = rtcConfig.recordId;
							} else {
								delete bizbuf.Str_uc_params.record_id;
							}

							pushUrl += '&bizbuf=' + encodeURIComponent(JSON.stringify(bizbuf));
						}

						console.log('roomSigInfo', pushUrl);
						resolve(pushUrl);
					},
					fail: res => {
						console.log('requestSigServer fail:', res);
						reject(res);
					}
				});
			});
		},
		doubleTabToggleFullscreenFun: function(event) {
			const curTime = event.timeStamp;
			const lastTime = this._lastTapTime; // 已知问题:上次全屏操作后,必须等待1.5s后才能再次进行全屏操作,否则引发SDK全屏异常,因此增加节流逻辑

			const beforeLastTime = this._beforeLastTapTime;
			console.log(TAG_NAME, 'doubleTabToggleFullscreenFun', event, lastTime, beforeLastTime);

			if (curTime - lastTime > 0 && curTime - lastTime < 300 && lastTime - beforeLastTime > 1500) {
				const userID = event.currentTarget.dataset.userid;
				const streamType = event.currentTarget.dataset.streamtype;

				if (this._isFullscreen) {
					this.exitFullscreen({
						userID,
						streamType
					})
						.then(() => {
							this._isFullscreen = false;
						})
						.catch(() => {});
				} else {
					// const stream = this.userController.getStream({ userID, streamType })
					let direction; // // 已知问题:视频的尺寸需要等待player触发NetStatus事件才能获取到,如果进房就双击全屏,全屏后的方向有可能不对。
					// if (stream && stream.videoWidth && stream.videoHeight) {
					//   // 如果是横视频,全屏时进行横屏处理。如果是竖视频,则为0
					//   direction = stream.videoWidth > stream.videoHeight ? 90 : 0
					// }

					this.enterFullscreen({
						userID,
						streamType,
						direction
					})
						.then(() => {
							this._isFullscreen = true;
						})
						.catch(() => {});
				}

				this._beforeLastTapTime = lastTime;
			}

			this._lastTapTime = curTime;
		},

		/**
		 * TRTC-room 远端用户和音视频状态处理
		 */
		bindEventFun: function() {
			// 远端用户进房
			this.userController.on(EVENT.REMOTE_USER_JOIN, event => {
				console.log(TAG_NAME, '远端用户进房', event, event.data.userID);
				this.setData(
					{
						userList: event.data.userList
					},
					() => {
						this._emitter.emit(EVENT.REMOTE_USER_JOIN, {
							userID: event.data.userID
						});
					},this
				);
				console.log(TAG_NAME, 'REMOTE_USER_JOIN', 'streamList:', this.streamList, 'userList:', this.userList);
			}); // 远端用户离开

			this.userController.on(EVENT.REMOTE_USER_LEAVE, event => {
				console.log(TAG_NAME, '远端用户离开', event, event.data.userID);

				if (event.data.userID) {
					this.setData(
						{
							userList: event.data.userList,
							streamList: event.data.streamList
						},
						() => {
							this._emitter.emit(EVENT.REMOTE_USER_LEAVE, {
								userID: event.data.userID
							});
						},this
					);
				}

				console.log(TAG_NAME, 'REMOTE_USER_LEAVE', 'streamList:', this.streamList, 'userList:', this.userList);
			}); // 视频状态 true

			this.userController.on(EVENT.REMOTE_VIDEO_ADD, event => {
				console.log(TAG_NAME, '远端视频可用', event, event.data.stream.userID);
				const stream = event.data.stream;
				this.setData(
					{
						userList: event.data.userList,
						streamList: event.data.streamList
					},
					() => {
						// 完善 的stream 的 playerContext
						stream.playerContext = wx.createLivePlayerContext(stream.streamID, this); // 新增的需要触发一次play 默认属性才能生效
						// stream.playerContext.play()
						// console.log(TAG_NAME, 'REMOTE_VIDEO_ADD playerContext.play()', stream)
						// TODO 视频通话模版默认订阅且显示

						this._emitter.emit(EVENT.REMOTE_VIDEO_ADD, {
							userID: stream.userID,
							streamType: stream.streamType
						});
					},this
				);
				console.log(TAG_NAME, 'REMOTE_VIDEO_ADD', 'streamList:', this.streamList, 'userList:', this.userList);
			}); // 视频状态 false

			this.userController.on(EVENT.REMOTE_VIDEO_REMOVE, event => {
				console.log(TAG_NAME, '远端视频移除', event, event.data.stream.userID);
				const stream = event.data.stream;
				this.setData(
					{
						userList: event.data.userList,
						streamList: event.data.streamList
					},
					() => {
						// 有可能先触发了退房事件,用户名下的所有stream都已清除
						if (stream.userID && stream.streamType) {
							this._emitter.emit(EVENT.REMOTE_VIDEO_REMOVE, {
								userID: stream.userID,
								streamType: stream.streamType
							});
						}
					},this
				);
				console.log(TAG_NAME, 'REMOTE_VIDEO_REMOVE', 'streamList:', this.streamList, 'userList:', this.userList);
			}); // 音频可用

			this.userController.on(EVENT.REMOTE_AUDIO_ADD, event => {
				console.log(TAG_NAME, '远端音频可用', event);
				const stream = event.data.stream;
				this.setData(
					{
						userList: event.data.userList,
						streamList: event.data.streamList
					},
					() => {
						stream.playerContext = wx.createLivePlayerContext(stream.streamID, this); // 新增的需要触发一次play 默认属性才能生效
						// stream.playerContext.play()
						// console.log(TAG_NAME, 'REMOTE_AUDIO_ADD playerContext.play()', stream)

						this._emitter.emit(EVENT.REMOTE_AUDIO_ADD, {
							userID: stream.userID,
							streamType: stream.streamType
						});
					},this
				);
				console.log(TAG_NAME, 'REMOTE_AUDIO_ADD', 'streamList:', this.streamList, 'userList:', this.userList);
			}); // 音频不可用

			this.userController.on(EVENT.REMOTE_AUDIO_REMOVE, event => {
				console.log(TAG_NAME, '远端音频移除', event, event.data.stream.userID);
				const stream = event.data.stream;
				this.setData(
					{
						userList: event.data.userList,
						streamList: event.data.streamList
					},
					() => {
						// 有可能先触发了退房事件,用户名下的所有stream都已清除
						if (stream.userID && stream.streamType) {
							this._emitter.emit(EVENT.REMOTE_AUDIO_REMOVE, {
								userID: stream.userID,
								streamType: stream.streamType
							});
						}
					},this
				);
				console.log(TAG_NAME, 'REMOTE_AUDIO_REMOVE', 'streamList:', this.streamList, 'userList:', this.userList);
			});
		},

		/**
		 * pusher event handler
		 * @param {*} event 事件实例
		 */
		pusherStateChangeHandlerFun: function(event) {
			const code = event.detail.code;
			const message = event.detail.message;
			console.log(TAG_NAME, 'pusherStateChange:', code, event);

			switch (code) {
				case 0:
					console.log(message, code);
					break;

				case 1001:
					console.log('已经连接推流服务器', code);
					break;

				case 1002:
					console.log('已经与服务器握手完毕,开始推流', code);
					break;

				case 1003:
					console.log('打开摄像头成功', code);
					break;

				case 1004:
					console.log('录屏启动成功', code);
					break;

				case 1005:
					console.log('推流动态调整分辨率', code);
					break;

				case 1006:
					console.log('推流动态调整码率', code);
					break;

				case 1007:
					console.log('首帧画面采集完成', code);
					break;

				case 1008:
					console.log('编码器启动', code);
					break;

				case 1018:
					console.log('进房成功', code);
					this._emitter.emit(EVENT.LOCAL_JOIN, {
						userID: this.pusher.userID
					});
					//进房成功  手动默认关闭摄像头  转后置
					this.switchCamera()
					this.unpublishLocalVideo()
					// //计时功能
					this.initTime()
					this.ipVoiceOrVideoLongTimeClick()

					break;

				case 1019:
					console.log('退出房间', code);

					this._emitter.emit(EVENT.LOCAL_LEAVE, {
						userID: this.pusher.userID
					});

					break;

				case 2003:
					console.log('渲染首帧视频', code);
					break;

				case 1020:
				case 1031:
				case 1032:
				case 1033:
				case 1034:
					// 通过 userController 处理 1020 1031 1032 1033 1034
					this.userController.userEventHandler(event);
					break;

				case -1301:
					console.error('打开摄像头失败: ', code);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case -1302:
					console.error('打开麦克风失败: ', code);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case -1303:
					console.error('视频编码失败: ', code);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case -1304:
					console.error('音频编码失败: ', code);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case -1307:
					console.error('推流连接断开: ', code);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case -100018:
					console.error('进房失败: ', code, message);

					this._emitter.emit(EVENT.ERROR, {
						code,
						message
					});

					break;

				case 5000:
					console.log('小程序被挂起: ', code); // 终端 sdk 建议执行退房操作,唤起时重新进房,临时解决方案,待小程序SDK完全实现自动重新推流后可以去掉

					this.status.isPending = true;

					if (this.status.isPush) {
						// this.exitRoom()
						const tempUrl = this.pusher.url;
						this.pusher.url = ''; // console.log('5000 小程序被挂起后更换pusher', this.data.pusher.getPusherContext().webviewId)

						this.setData(
							{
								pusher: this.pusher
							},
							() => {
								this.pusher.url = tempUrl;
								this.setData(
									{
										pusher: this.pusher
									},
									() => {
										this.pusher.getPusherContext().start();
										console.log('5000 小程序被挂起后更换pusher', this.pusher);
									}
								);
							}
						);
					}

					break;

				case 1021:
					console.log('网络类型发生变化,需要重新进房', code);
					break;

				case 2007:
					console.log('本地视频播放loading: ', code);
					break;

				case 2004:
					console.log('本地视频播放开始: ', code);
					break;

				default:
					console.log(message, code);
			}

			this._emitter.emit(EVENT.LOCAL_STATE_UPDATE, {
				data: event
			});
		},
		pusherNetStatusHandlerFun: function(event) {
			// 触发 LOCAL_NET_STATE_UPDATE
			this._emitter.emit(EVENT.LOCAL_NET_STATE_UPDATE, event);
		},
		pusherErrorHandlerFun: function(event) {
			// 触发 ERROR
			console.warn(TAG_NAME, 'pusher error', event);

			try {
				const code = event.detail.errCode;
				const message = event.detail.errMsg;

				this._emitter.emit(EVENT.ERROR, {
					code,
					message
				});
			} catch (exception) {
				console.error(TAG_NAME, 'pusher error data parser exception', event, exception);
			}
		},
		pusherBGMStartHandlerFun: function(event) {
			// 触发 BGM_START 已经在playBGM方法中进行处理
			// this._emitter.emit(EVENT.BGM_PLAY_START, { data: event })
		},
		pusherBGMProgressHandlerFun: function(event) {
			// BGM_PROGRESS
			this._emitter.emit(EVENT.BGM_PLAY_PROGRESS, event);
		},
		pusherBGMCompleteHandlerFun: function(event) {
			// BGM_COMPLETE
			this._emitter.emit(EVENT.BGM_PLAY_COMPLETE, event);
		},
		// player event handler
		// 获取 player ID 再进行触发
		playerStateChangeFun: function(event) {
			// console.log(TAG_NAME, 'playerStateChangeFun', event)
			this._emitter.emit(EVENT.REMOTE_STATE_UPDATE, event);
		},
		playerFullscreenChangeFun: function(event) {
			// console.log(TAG_NAME, '_playerFullscreenChange', event)
			this._emitter.emit(EVENT.REMOTE_NET_STATE_UPDATE, event);
		},
		playerNetStatusFun: function(event) {
			// console.log(TAG_NAME, 'playerNetStatusFun', event)
			// 获取player 视频的宽高
			const stream = this.userController.getStream({
				userID: event.currentTarget.dataset.userid,
				streamType: event.currentTarget.dataset.streamtype
			});

			if (stream && (stream.videoWidth !== event.detail.info.videoWidth || stream.videoHeight !== event.detail.info.videoHeight)) {
				console.log(TAG_NAME, 'playerNetStatusFun update video size', event);
				stream.videoWidth = event.detail.info.videoWidth;
				stream.videoHeight = event.detail.info.videoHeight;
			}

			this._emitter.emit(EVENT.REMOTE_FULLSCREEN_UPDATE, event);
		},
		playerAudioVolumeNotifyFun: function(event) {
			// console.log(TAG_NAME, 'playerAudioVolumeNotifyFun', event)
			this._emitter.emit(EVENT.REMOTE_AUDIO_VOLUME_UPDATE, event);
		},

		/**
		 * 监听组件属性变更,外部变更组件属性时触发该监听,用于检查属性设置是否正常
		 * @param {Object} data 变更数据
		 */
		propertyObserverFun: function(data) {
			console.log(TAG_NAME, '_propertyObserver', data, this.config);

			if (data.name === 'config') {
				// const config = Object.assign(DEFAULT_PUSHER_CONFIG, data.newVal)
				const config = data.newVal; // querystring 只支持String类型,做一个类型防御

				if (typeof config.debugMode === 'string') {
					config.debugMode === 'true' ? true : false;
				} // 独立设置与pusher无关的配置

				this.setData({
					template: config.template,
					debugMode: config.debugMode || false,
					debug: config.debugMode || false
				});
				this.setPusherConfigFun(config);
			}
		},

		toggleVideoFun() {
			if (this.pusher.enableCamera) {
				this.unpublishLocalVideo();
			} else {
				this.publishLocalVideo();
			}
		},

		toggleAudioFun() {
			if (this.pusher.enableMic) {
				this.unpublishLocalAudio();
			} else {
				this.publishLocalAudio();
			}
		},

		debugToggleRemoteVideoFun(event) {
			console.log(TAG_NAME, '_debugToggleRemoteVideo', event.currentTarget.dataset);
			const userID = event.currentTarget.dataset.userID;
			const streamType = event.currentTarget.dataset.streamType;
			const stream = this.streamList.find(item => {
				return item.userID === userID && item.streamType === streamType;
			});

			if (stream.muteVideo) {
				this.subscribeRemoteVideo({
					userID,
					streamType
				});
				this.setViewVisible({
					userID,
					streamType,
					isVisible: true
				});
			} else {
				this.unsubscribeRemoteVideo({
					userID,
					streamType
				});
				this.setViewVisible({
					userID,
					streamType,
					isVisible: false
				});
			}
		},

		debugToggleRemoteAudioFun(event) {
			console.log(TAG_NAME, '_debugToggleRemoteAudio', event.currentTarget.dataset);
			const userID = event.currentTarget.dataset.userID;
			const streamType = event.currentTarget.dataset.streamType;
			const stream = this.streamList.find(item => {
				return item.userID === userID && item.streamType === streamType;
			});

			if (stream.muteAudio) {
				this.subscribeRemoteAudio({
					userID
				});
			} else {
				this.unsubscribeRemoteAudio({
					userID
				});
			}
		},

		debugToggleVideoDebugFun() {
			this.setData({
				debug: !this.debug
			});
		},

		debugExitRoomFun() {
			this.exitRoom();
		},

		debugEnterRoomFun() {
			this.publishLocalVideo();
			this.publishLocalAudio();
			this.enterRoom({
				roomID: this.config.roomID
			}).then(() => {
				// 进房后开始推送视频或音频
			});
		},

		debugGoBackFun() {
			wx.navigateBack({
				delta: 1
			});
		},

		debugTogglePanelFun() {
			this.setData({
				debugPanel: !this.debugPanel
			});
		},

		toggleAudioVolumeTypeFun() {
			if (this.pusher.audioVolumeType === 'voicecall') {
				this.setPusherConfigFun({
					audioVolumeType: 'media'
				});
			} else {
				this.setPusherConfigFun({
					audioVolumeType: 'voicecall'
				});
			}
		},

		toggleSoundModeFun(val) {
			console.log('点击了切换语音/视频',val)
			if (this.userList.length === 0) {
				return;
			}

			const stream = this.userController.getStream({
				userID: this.userList[0].userID,
				streamType: 'main'
			});

			if (stream) {
				if (stream.soundMode === 'speaker') {
					stream['soundMode'] = 'ear';
				} else {
					stream['soundMode'] = 'speaker';
				}

				this.setPlayerConfigFun({
					userID: stream.userID,
					streamType: 'main',
					config: {
						soundMode: stream['soundMode']
					}
				});
			}
		},

		/**
		 * 退出通话
		 */
		hangUpFun: function() {
			console.log('点击了挂断')
			// this.exitRoom();
			uni.reLaunch({
				url: '/pages/callOver/index',
				fail: e=>{
					uni.switchTab({
						url:'/pages/callOver/index'
					})
				}
			})
			setTimeout(()=>{
				this.exitRoom();
				//停止定时器,重置计时时间
				this.resetMsgIPtime()
				this.stopMsgIPtime()
			},300)
			// uni.navigateBack({
			// 	delta: 1
			// });
		},

		/**
		 * 切换订阅音频状态
		 */
		handleSubscribeAudio: function() {
			if (this.pusher.enableMic) {
				this.unpublishLocalAudio();
			} else {
				this.publishLocalAudio();
			}
		},

		/**
		 * 切换订阅远端视频状态
		 * @param event
		 */
		handleSubscribeRemoteVideoFun: function(event) {
			const userID = event.currentTarget.dataset.userID;
			const streamType = event.currentTarget.dataset.streamType;
			const stream = this.streamList.find(item => {
				return item.userID === userID && item.streamType === streamType;
			});

			if (stream.muteVideo) {
				this.subscribeRemoteVideo({
					userID,
					streamType
				});
			} else {
				this.unsubscribeRemoteVideo({
					userID,
					streamType
				});
			}
		},

		/**
		 * 将远端视频取消全屏
		 * @param event
		 */
		handleSubscribeRemoteAudioFun: function(event) {
			const userID = event.currentTarget.dataset.userID;
			const streamType = event.currentTarget.dataset.streamType;
			const stream = this.streamList.find(item => {
				return item.userID === userID && item.streamType === streamType;
			});

			if (stream.muteAudio) {
				this.subscribeRemoteAudio({
					userID
				});
			} else {
				this.unsubscribeRemoteAudio({
					userID
				});
			}
		},

		/**
		 * grid布局, 唤起 memberlist-panel
		 */
		switchMemberListPanelFun() {
			this.setData({
				panelName: this.panelName !== 'memberlist-panel' ? 'memberlist-panel' : ''
			});
		},

		/**
		 * grid布局, 唤起setting-panel
		 */
		switchSettingPanelFun() {
			this.setData({
				panelName: this.panelName !== 'setting-panel' ? 'setting-panel' : ''
			});
		},

		handleMaskerClickFun() {
			this.setData({
				panelName: ''
			});
		},

		setPuserPropertyFun(event) {
			// console.log(TAG_NAME, '_setPuserProperty', event)
			const key = event.currentTarget.dataset.key;
			let value = event.currentTarget.dataset.value;
			const config = {};

			if (value === 'true') {
				value = true;
			} else if (value === 'false') {
				value = false;
			}

			if (typeof value === 'boolean') {
				config[key] = !this.pusher[key];
			} else if (typeof value === 'string' && value.indexOf('|') > 0) {
				value = value.split('|');

				if (this.pusher[key] === value[0]) {
					config[key] = value[1];
				} else {
					config[key] = value[0];
				}
			} // console.log(TAG_NAME, '_setPuserProperty', config)

			this.setPusherConfigFun(config);
		},

		setPlayerPropertyFun(event) {
			console.log(TAG_NAME, '_setPlayerProperty', event);
			const userID = event.currentTarget.dataset.userid;
			const streamType = event.currentTarget.dataset.streamtype;
			const key = event.currentTarget.dataset.key;
			let value = event.currentTarget.dataset.value;
			const stream = this.userController.getStream({
				userID: userID,
				streamType: streamType
			});

			if (!stream) {
				return;
			}

			const config = {};

			if (value === 'true') {
				value = true;
			} else if (value === 'false') {
				value = false;
			}

			if (typeof value === 'boolean') {
				config[key] = !stream[key];
			} else if (typeof value === 'string' && value.indexOf('|') > 0) {
				value = value.split('|');

				if (stream[key] === value[0]) {
					config[key] = value[1];
				} else {
					config[key] = value[0];
				}
			}

			console.log(TAG_NAME, '_setPlayerProperty', config);
			this.setPlayerConfigFun({
				userID,
				streamType,
				config
			});
		},

		switchStreamTypeFun(event) {
			const userID = event.currentTarget.dataset.userid;
			const streamType = event.currentTarget.dataset.streamtype;
			const stream = this.userController.getStream({
				userID: userID,
				streamType: streamType
			});

			if (stream && stream.streamType === 'main') {
				if (stream._definitionType === 'small') {
					this.subscribeRemoteVideo({
						userID,
						streamType: 'main'
					});
				} else {
					this.subscribeRemoteVideo({
						userID,
						streamType: 'small'
					});
				}
			}
		},

		handleSnapshotClickFun(event) {
			wx.showToast({
				title: '开始截屏',
				icon: 'none',
				duration: 1000
			});
			const userID = event.currentTarget.dataset.userid;
			const streamType = event.currentTarget.dataset.streamtype;
			this.snapshot({
				userID,
				streamType
			});
		},

		/**
		 * grid布局, 绑定事件
		 */
		bindEventGridFun() {
			// 远端音量变更
			this.on(EVENT.REMOTE_AUDIO_VOLUME_UPDATE, event => {
				const data = event.data;
				const userID = data.currentTarget.dataset.userid;
				const streamType = data.currentTarget.dataset.streamtype;
				const volume = data.detail.volume; // console.log(TAG_NAME, '远端音量变更', userID, streamType, volume)

				const stream = this.userController.getStream({
					userID: userID,
					streamType: streamType
				});

				if (stream) {
					stream.volume = volume;
				}

				this.setData(
					{
						streamList: this.streamList
					},
					() => {}
				);
			});
		},

		toggleFullscreenFun(event) {
			console.log(TAG_NAME, '_toggleFullscreen', event);
			const userID = event.currentTarget.dataset.userID;
			const streamType = event.currentTarget.dataset.streamType;

			if (this._isFullscreen) {
				this.exitFullscreen({
					userID,
					streamType
				})
					.then(() => {
						this._isFullscreen = false;
					})
					.catch(() => {});
			} else {
				// const stream = this.userController.getStream({ userID, streamType })
				const direction = 0; // 已知问题:视频的尺寸需要等待player触发NetStatus事件才能获取到,如果进房就双击全屏,全屏后的方向有可能不对。
				// if (stream && stream.videoWidth && stream.videoHeight) {
				//   // 如果是横视频,全屏时进行横屏处理。如果是竖视频,则为0
				//   direction = stream.videoWidth > stream.videoHeight ? 90 : 0
				// }

				this.enterFullscreen({
					userID,
					streamType,
					direction
				})
					.then(() => {
						this._isFullscreen = true;
					})
					.catch(() => {});
			}
		}
	}
};
</script>
<style>
@import './trtc-room.css';
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797
  • 798
  • 799
  • 800
  • 801
  • 802
  • 803
  • 804
  • 805
  • 806
  • 807
  • 808
  • 809
  • 810
  • 811
  • 812
  • 813
  • 814
  • 815
  • 816
  • 817
  • 818
  • 819
  • 820
  • 821
  • 822
  • 823
  • 824
  • 825
  • 826
  • 827
  • 828
  • 829
  • 830
  • 831
  • 832
  • 833
  • 834
  • 835
  • 836
  • 837
  • 838
  • 839
  • 840
  • 841
  • 842
  • 843
  • 844
  • 845
  • 846
  • 847
  • 848
  • 849
  • 850
  • 851
  • 852
  • 853
  • 854
  • 855
  • 856
  • 857
  • 858
  • 859
  • 860
  • 861
  • 862
  • 863
  • 864
  • 865
  • 866
  • 867
  • 868
  • 869
  • 870
  • 871
  • 872
  • 873
  • 874
  • 875
  • 876
  • 877
  • 878
  • 879
  • 880
  • 881
  • 882
  • 883
  • 884
  • 885
  • 886
  • 887
  • 888
  • 889
  • 890
  • 891
  • 892
  • 893
  • 894
  • 895
  • 896
  • 897
  • 898
  • 899
  • 900
  • 901
  • 902
  • 903
  • 904
  • 905
  • 906
  • 907
  • 908
  • 909
  • 910
  • 911
  • 912
  • 913
  • 914
  • 915
  • 916
  • 917
  • 918
  • 919
  • 920
  • 921
  • 922
  • 923
  • 924
  • 925
  • 926
  • 927
  • 928
  • 929
  • 930
  • 931
  • 932
  • 933
  • 934
  • 935
  • 936
  • 937
  • 938
  • 939
  • 940
  • 941
  • 942
  • 943
  • 944
  • 945
  • 946
  • 947
  • 948
  • 949
  • 950
  • 951
  • 952
  • 953
  • 954
  • 955
  • 956
  • 957
  • 958
  • 959
  • 960
  • 961
  • 962
  • 963
  • 964
  • 965
  • 966
  • 967
  • 968
  • 969
  • 970
  • 971
  • 972
  • 973
  • 974
  • 975
  • 976
  • 977
  • 978
  • 979
  • 980
  • 981
  • 982
  • 983
  • 984
  • 985
  • 986
  • 987
  • 988
  • 989
  • 990
  • 991
  • 992
  • 993
  • 994
  • 995
  • 996
  • 997
  • 998
  • 999
  • 1000
  • 1001
  • 1002
  • 1003
  • 1004
  • 1005
  • 1006
  • 1007
  • 1008
  • 1009
  • 1010
  • 1011
  • 1012
  • 1013
  • 1014
  • 1015
  • 1016
  • 1017
  • 1018
  • 1019
  • 1020
  • 1021
  • 1022
  • 1023
  • 1024
  • 1025
  • 1026
  • 1027
  • 1028
  • 1029
  • 1030
  • 1031
  • 1032
  • 1033
  • 1034
  • 1035
  • 1036
  • 1037
  • 1038
  • 1039
  • 1040
  • 1041
  • 1042
  • 1043
  • 1044
  • 1045
  • 1046
  • 1047
  • 1048
  • 1049
  • 1050
  • 1051
  • 1052
  • 1053
  • 1054
  • 1055
  • 1056
  • 1057
  • 1058
  • 1059
  • 1060
  • 1061
  • 1062
  • 1063
  • 1064
  • 1065
  • 1066
  • 1067
  • 1068
  • 1069
  • 1070
  • 1071
  • 1072
  • 1073
  • 1074
  • 1075
  • 1076
  • 1077
  • 1078
  • 1079
  • 1080
  • 1081
  • 1082
  • 1083
  • 1084
  • 1085
  • 1086
  • 1087
  • 1088
  • 1089
  • 1090
  • 1091
  • 1092
  • 1093
  • 1094
  • 1095
  • 1096
  • 1097
  • 1098
  • 1099
  • 1100
  • 1101
  • 1102
  • 1103
  • 1104
  • 1105
  • 1106
  • 1107
  • 1108
  • 1109
  • 1110
  • 1111
  • 1112
  • 1113
  • 1114
  • 1115
  • 1116
  • 1117
  • 1118
  • 1119
  • 1120
  • 1121
  • 1122
  • 1123
  • 1124
  • 1125
  • 1126
  • 1127
  • 1128
  • 1129
  • 1130
  • 1131
  • 1132
  • 1133
  • 1134
  • 1135
  • 1136
  • 1137
  • 1138
  • 1139
  • 1140
  • 1141
  • 1142
  • 1143
  • 1144
  • 1145
  • 1146
  • 1147
  • 1148
  • 1149
  • 1150
  • 1151
  • 1152
  • 1153
  • 1154
  • 1155
  • 1156
  • 1157
  • 1158
  • 1159
  • 1160
  • 1161
  • 1162
  • 1163
  • 1164
  • 1165
  • 1166
  • 1167
  • 1168
  • 1169
  • 1170
  • 1171
  • 1172
  • 1173
  • 1174
  • 1175
  • 1176
  • 1177
  • 1178
  • 1179
  • 1180
  • 1181
  • 1182
  • 1183
  • 1184
  • 1185
  • 1186
  • 1187
  • 1188
  • 1189
  • 1190
  • 1191
  • 1192
  • 1193
  • 1194
  • 1195
  • 1196
  • 1197
  • 1198
  • 1199
  • 1200
  • 1201
  • 1202
  • 1203
  • 1204
  • 1205
  • 1206
  • 1207
  • 1208
  • 1209
  • 1210
  • 1211
  • 1212
  • 1213
  • 1214
  • 1215
  • 1216
  • 1217
  • 1218
  • 1219
  • 1220
  • 1221
  • 1222
  • 1223
  • 1224
  • 1225
  • 1226
  • 1227
  • 1228
  • 1229
  • 1230
  • 1231
  • 1232
  • 1233
  • 1234
  • 1235
  • 1236
  • 1237
  • 1238
  • 1239
  • 1240
  • 1241
  • 1242
  • 1243
  • 1244
  • 1245
  • 1246
  • 1247
  • 1248
  • 1249
  • 1250
  • 1251
  • 1252
  • 1253
  • 1254
  • 1255
  • 1256
  • 1257
  • 1258
  • 1259
  • 1260
  • 1261
  • 1262
  • 1263
  • 1264
  • 1265
  • 1266
  • 1267
  • 1268
  • 1269
  • 1270
  • 1271
  • 1272
  • 1273
  • 1274
  • 1275
  • 1276
  • 1277
  • 1278
  • 1279
  • 1280
  • 1281
  • 1282
  • 1283
  • 1284
  • 1285
  • 1286
  • 1287
  • 1288
  • 1289
  • 1290
  • 1291
  • 1292
  • 1293
  • 1294
  • 1295
  • 1296
  • 1297
  • 1298
  • 1299
  • 1300
  • 1301
  • 1302
  • 1303
  • 1304
  • 1305
  • 1306
  • 1307
  • 1308
  • 1309
  • 1310
  • 1311
  • 1312
  • 1313
  • 1314
  • 1315
  • 1316
  • 1317
  • 1318
  • 1319
  • 1320
  • 1321
  • 1322
  • 1323
  • 1324
  • 1325
  • 1326
  • 1327
  • 1328
  • 1329
  • 1330
  • 1331
  • 1332
  • 1333
  • 1334
  • 1335
  • 1336
  • 1337
  • 1338
  • 1339
  • 1340
  • 1341
  • 1342
  • 1343
  • 1344
  • 1345
  • 1346
  • 1347
  • 1348
  • 1349
  • 1350
  • 1351
  • 1352
  • 1353
  • 1354
  • 1355
  • 1356
  • 1357
  • 1358
  • 1359
  • 1360
  • 1361
  • 1362
  • 1363
  • 1364
  • 1365
  • 1366
  • 1367
  • 1368
  • 1369
  • 1370
  • 1371
  • 1372
  • 1373
  • 1374
  • 1375
  • 1376
  • 1377
  • 1378
  • 1379
  • 1380
  • 1381
  • 1382
  • 1383
  • 1384
  • 1385
  • 1386
  • 1387
  • 1388
  • 1389
  • 1390
  • 1391
  • 1392
  • 1393
  • 1394
  • 1395
  • 1396
  • 1397
  • 1398
  • 1399
  • 1400
  • 1401
  • 1402
  • 1403
  • 1404
  • 1405
  • 1406
  • 1407
  • 1408
  • 1409
  • 1410
  • 1411
  • 1412
  • 1413
  • 1414
  • 1415
  • 1416
  • 1417
  • 1418
  • 1419
  • 1420
  • 1421
  • 1422
  • 1423
  • 1424
  • 1425
  • 1426
  • 1427
  • 1428
  • 1429
  • 1430
  • 1431
  • 1432
  • 1433
  • 1434
  • 1435
  • 1436
  • 1437
  • 1438
  • 1439
  • 1440
  • 1441
  • 1442
  • 1443
  • 1444
  • 1445
  • 1446
  • 1447
  • 1448
  • 1449
  • 1450
  • 1451
  • 1452
  • 1453
  • 1454
  • 1455
  • 1456
  • 1457
  • 1458
  • 1459
  • 1460
  • 1461
  • 1462
  • 1463
  • 1464
  • 1465
  • 1466
  • 1467
  • 1468
  • 1469
  • 1470
  • 1471
  • 1472
  • 1473
  • 1474
  • 1475
  • 1476
  • 1477
  • 1478
  • 1479
  • 1480
  • 1481
  • 1482
  • 1483
  • 1484
  • 1485
  • 1486
  • 1487
  • 1488
  • 1489
  • 1490
  • 1491
  • 1492
  • 1493
  • 1494
  • 1495
  • 1496
  • 1497
  • 1498
  • 1499
  • 1500
  • 1501
  • 1502
  • 1503
  • 1504
  • 1505
  • 1506
  • 1507
  • 1508
  • 1509
  • 1510
  • 1511
  • 1512
  • 1513
  • 1514
  • 1515
  • 1516
  • 1517
  • 1518
  • 1519
  • 1520
  • 1521
  • 1522
  • 1523
  • 1524
  • 1525
  • 1526
  • 1527
  • 1528
  • 1529
  • 1530
  • 1531
  • 1532
  • 1533
  • 1534
  • 1535
  • 1536
  • 1537
  • 1538
  • 1539
  • 1540
  • 1541
  • 1542
  • 1543
  • 1544
  • 1545
  • 1546
  • 1547
  • 1548
  • 1549
  • 1550
  • 1551
  • 1552
  • 1553
  • 1554
  • 1555
  • 1556
  • 1557
  • 1558
  • 1559
  • 1560
  • 1561
  • 1562
  • 1563
  • 1564
  • 1565
  • 1566
  • 1567
  • 1568
  • 1569
  • 1570
  • 1571
  • 1572
  • 1573
  • 1574
  • 1575
  • 1576
  • 1577
  • 1578
  • 1579
  • 1580
  • 1581
  • 1582
  • 1583
  • 1584
  • 1585
  • 1586
  • 1587
  • 1588
  • 1589
  • 1590
  • 1591
  • 1592
  • 1593
  • 1594
  • 1595
  • 1596
  • 1597
  • 1598
  • 1599
  • 1600
  • 1601
  • 1602
  • 1603
  • 1604
  • 1605
  • 1606
  • 1607
  • 1608
  • 1609
  • 1610
  • 1611
  • 1612
  • 1613
  • 1614
  • 1615
  • 1616
  • 1617
  • 1618
  • 1619
  • 1620
  • 1621
  • 1622
  • 1623
  • 1624
  • 1625
  • 1626
  • 1627
  • 1628
  • 1629
  • 1630
  • 1631
  • 1632
  • 1633
  • 1634
  • 1635
  • 1636
  • 1637
  • 1638
  • 1639
  • 1640
  • 1641
  • 1642
  • 1643
  • 1644
  • 1645
  • 1646
  • 1647
  • 1648
  • 1649
  • 1650
  • 1651
  • 1652
  • 1653
  • 1654
  • 1655
  • 1656
  • 1657
  • 1658
  • 1659
  • 1660
  • 1661
  • 1662
  • 1663
  • 1664
  • 1665
  • 1666
  • 1667
  • 1668
  • 1669
  • 1670
  • 1671
  • 1672
  • 1673
  • 1674
  • 1675
  • 1676
  • 1677
  • 1678
  • 1679
  • 1680
  • 1681
  • 1682
  • 1683
  • 1684
  • 1685
  • 1686
  • 1687
  • 1688
  • 1689
  • 1690
  • 1691
  • 1692
  • 1693
  • 1694
  • 1695
  • 1696
  • 1697
  • 1698
  • 1699
  • 1700
  • 1701
  • 1702
  • 1703
  • 1704
  • 1705
  • 1706
  • 1707
  • 1708
  • 1709
  • 1710
  • 1711
  • 1712
  • 1713
  • 1714
  • 1715
  • 1716
  • 1717
  • 1718
  • 1719
  • 1720
  • 1721
  • 1722
  • 1723
  • 1724
  • 1725
  • 1726
  • 1727
  • 1728
  • 1729
  • 1730
  • 1731
  • 1732
  • 1733
  • 1734
  • 1735
  • 1736
  • 1737
  • 1738
  • 1739
  • 1740
  • 1741
  • 1742
  • 1743
  • 1744
  • 1745
  • 1746
  • 1747
  • 1748
  • 1749
  • 1750
  • 1751
  • 1752
  • 1753
  • 1754
  • 1755
  • 1756
  • 1757
  • 1758
  • 1759
  • 1760
  • 1761
  • 1762
  • 1763
  • 1764
  • 1765
  • 1766
  • 1767
  • 1768
  • 1769
  • 1770
  • 1771
  • 1772
  • 1773
  • 1774
  • 1775
  • 1776
  • 1777
  • 1778
  • 1779
  • 1780
  • 1781
  • 1782
  • 1783
  • 1784
  • 1785
  • 1786
  • 1787
  • 1788
  • 1789
  • 1790
  • 1791
  • 1792
  • 1793
  • 1794
  • 1795
  • 1796
  • 1797
  • 1798
  • 1799
  • 1800
  • 1801
  • 1802
  • 1803
  • 1804
  • 1805
  • 1806
  • 1807
  • 1808
  • 1809
  • 1810
  • 1811
  • 1812
  • 1813
  • 1814
  • 1815
  • 1816
  • 1817
  • 1818
  • 1819
  • 1820
  • 1821
  • 1822
  • 1823
  • 1824
  • 1825
  • 1826
  • 1827
  • 1828
  • 1829
  • 1830
  • 1831
  • 1832
  • 1833
  • 1834
  • 1835
  • 1836
  • 1837
  • 1838
  • 1839
  • 1840
  • 1841
  • 1842
  • 1843
  • 1844
  • 1845
  • 1846
  • 1847
  • 1848
  • 1849
  • 1850
  • 1851
  • 1852
  • 1853
  • 1854
  • 1855
  • 1856
  • 1857
  • 1858
  • 1859
  • 1860
  • 1861
  • 1862
  • 1863
  • 1864
  • 1865
  • 1866
  • 1867
  • 1868
  • 1869
  • 1870
  • 1871
  • 1872
  • 1873
  • 1874
  • 1875
  • 1876
  • 1877
  • 1878
  • 1879
  • 1880
  • 1881
  • 1882
  • 1883
  • 1884
  • 1885
  • 1886
  • 1887
  • 1888
  • 1889
  • 1890
  • 1891
  • 1892
  • 1893
  • 1894
  • 1895
  • 1896
  • 1897
  • 1898
  • 1899
  • 1900
  • 1901
  • 1902
  • 1903
  • 1904
  • 1905
  • 1906
  • 1907
  • 1908
  • 1909
  • 1910
  • 1911
  • 1912
  • 1913
  • 1914
  • 1915
  • 1916
  • 1917
  • 1918
  • 1919
  • 1920
  • 1921
  • 1922
  • 1923
  • 1924
  • 1925
  • 1926
  • 1927
  • 1928
  • 1929
  • 1930
  • 1931
  • 1932
  • 1933
  • 1934
  • 1935
  • 1936
  • 1937
  • 1938
  • 1939
  • 1940
  • 1941
  • 1942
  • 1943
  • 1944
  • 1945
  • 1946
  • 1947
  • 1948
  • 1949
  • 1950
  • 1951
  • 1952
  • 1953
  • 1954
  • 1955
  • 1956
  • 1957
  • 1958
  • 1959
  • 1960
  • 1961
  • 1962
  • 1963
  • 1964
  • 1965
  • 1966
  • 1967
  • 1968
  • 1969
  • 1970
  • 1971
  • 1972
  • 1973
  • 1974
  • 1975
  • 1976
  • 1977
  • 1978
  • 1979
  • 1980
  • 1981
  • 1982
  • 1983
  • 1984
  • 1985
  • 1986
  • 1987
  • 1988
  • 1989
  • 1990
  • 1991
  • 1992
  • 1993
  • 1994
  • 1995
  • 1996
  • 1997
  • 1998
  • 1999
  • 2000
  • 2001
  • 2002
  • 2003
  • 2004
  • 2005
  • 2006
  • 2007
  • 2008
  • 2009
  • 2010
  • 2011
  • 2012
  • 2013
  • 2014
  • 2015
  • 2016
  • 2017
  • 2018
  • 2019
  • 2020
  • 2021
  • 2022
  • 2023
  • 2024
  • 2025
  • 2026
  • 2027
  • 2028
  • 2029
  • 2030
  • 2031
  • 2032
  • 2033
  • 2034
  • 2035
  • 2036
  • 2037
  • 2038
  • 2039
  • 2040
  • 2041
  • 2042
  • 2043
  • 2044
  • 2045
  • 2046
  • 2047
  • 2048
  • 2049
  • 2050
  • 2051
  • 2052
  • 2053

4,这是使用的页面使用的方式(原生组件,所以有个元素层级默认最高,覆盖所有,得使用cover-view才能盖在上面)。一定要有ref,否则不能初始化方法,不能创建实例,还得有config相关配置

<trtc-room id="trtcComponent" :config.sync="playVidoe.input.rtcConfig" ref="trtcComponent"> </trtc-room>
  • 1

4.1别忘了下载两个js到本地
用于测试研签,如果你有后端,签名和用户id就是后端提供给你。但你仍需要历练的setData方法
在这里插入图片描述

5,生命周期函数里面(等页面元素有了之后)
初始化

data(){
	return{
	callVideo:{
	    input:{
	      template: '1v1',
	      debugMode: false,
	      cloudenv: 'PRO',
	      callingMode:'video',  //通话模式  语音/视频  audio/video
	      cameraMode:'back',  //通话模式  前/后  front、after
	    }
	  },
	  playVidoe:{
	    input:{
	      rtcConfig: {
	        sdkAppID: xxxxxx, // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppID
	        userID: 'test001', // 必要参数 用户 ID 可以由您的帐号系统指定
	        userSig: '"xxxxxx"', // 必要参数 身份签名,相当于登录密码的作用
	        template: '1v1', // 必要参数 组件模版,支持的值 1v1 grid custom ,注意:不支持动态修改, iOS 不支持 pusher 动态渲染
	      },
	    }
	  },
	}
}
async mounted() {
      // 获取 rtcroom 实例
      this.trtcComponent = this.$refs['trtcComponent']
      console.log('this.trtcComponent',this.trtcComponent)
      // 监听TRTC Room 关键事件
      this.methods('bindTRTCRoomEvent')
      //基本数据 this.callVideo.input  通话模式等
      Object.getOwnPropertyNames(this.callVideo.input).forEach(key => {

        if (this.callVideo.input[key] === 'true') {
          this.callVideo.input[key] = true;
        }
  
        if (this.callVideo.input[key] === 'false') {
          this.callVideo.input[key] = false;
        }
      });
      this.options = this.callVideo.input;
  },
然后我这里用了websocket,在create里面建立连接,等待推房间号给我,我进房
this.methods('initRtcConfig',{userID :'test001',roomID:this.curRoomId,template:'1v1'})
this.methods('enterRoomBefore')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

6,事件
初始化并监控组件事件(如远端退房等)

//引入js
import { genTestUserSig } from '../../libs/debug/GenerateTestUserSig.js'
//初始化config
initRtcConfig(data){
    data.template = data.template
    data.roomID = data.roomID
    data.userID = data.userID
    console.log('* room enterRoom','走进来99999999', data)

    const Signature = genTestUserSig(data.userID)
    data.sdkAppID = Signature.sdkAppID
    data.userSig = Signature.userSig
    this.template = data.template


    this.playVidoe.input.rtcConfig = {
      sdkAppID: data.sdkAppID, // 您的实时音视频服务创建应用后分配的 sdkAppID
      userID: data.userID,
      roomID : data.roomID,
      userSig: data.userSig,
      template: data.template, // 1v1 grid custom
      debugMode: data.debugMode, // 非必要参数,打开组件的调试模式,开发调试时建议设置为 true
      beautyLevel: 9, // 默认开启美颜
      enableIM: false, // 可选,仅支持初始化设置(进房前设置),不支持动态修改
      audioVolumeType: data.audioVolumeType,
    }
  }
  async enterRoomBefore(){
    let isOk = await this.methods('checkDeviceAuthorize')
    if(isOk){
      //近房间
      let data = {
        roomID:this.playVidoe.input.rtcConfig.roomID,
        userID:this.playVidoe.input.rtcConfig.userID,
        template:this.callVideo.input.template,
        debugMode:this.callVideo.input.debugMode,
        cloudenv:this.callVideo.input.cloudenv,
      }
      this.methods('enterRoom',data)
    }else{
      console.log('出错')
    }
  }
  async checkDeviceAuthorize(){
    let isOk = false
    this.hasOpenDeviceAuthorizeModal = false
    await new Promise((resolve, reject) => {
      if (!uni.getSetting || !uni.getSetting()) {
        // 微信测试版 获取授权API异常,目前只能即使没授权也可以通过
        resolve()
      }
      uni.getSetting().then((result)=> {
        // console.log('getSetting', result[1])
        this.authorizeMic = result[1].authSetting['scope.record']
        this.authorizeCamera = result[1].authSetting['scope.camera']
        if (result[1].authSetting['scope.camera'] && result[1].authSetting['scope.record']) {
          // 授权成功
          isOk = true
          resolve()
        } else {
          // 没有授权,弹出授权窗口
          // 注意: uni.authorize 只有首次调用会弹框,之后调用只返回结果,如果没有授权需要自行弹框提示处理
          console.log('getSetting 没有授权,弹出授权窗口', result)
          uni.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
          })
          uni.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'))
          })
        }
      })
    })
    return isOk
  }
  enterRoom(data) {
    this.trtcComponent.enterRoom({ roomID: data.roomID }).then(()=>{
      console.log('HDFH11111111111111111111111111111',data)
      if (this.template === '1v1') {
        // 设置推流端视窗的坐标和尺寸
        console.log('HDFH',data)
        this.trtcComponent.setViewRect({
          userID: data.userID,
          xAxis: '480rpx',
          yAxis: '160rpx',
          width: '240rpx',
          height: '320rpx',
        })
      }
    }).catch((res)=>{
    	//这里出现了一下奇怪的报错  连续拨通挂断,不懂是腾讯对签名有限制还是怎样,连续操作20几次会出错,进不去房间。。。。
    	这里需要加个检测失败的事件,失败跳出
      console.error('组建所在页面 进房失败:', res)
    })
  }

  bindTRTCRoomEvent() {
    const TRTC_EVENT = this.trtcComponent.EVENT
    this.timestamp = []
    // 初始化事件订阅
    this.trtcComponent.on(TRTC_EVENT.LOCAL_JOIN, (event)=>{
      // console.log('* room LOCAL_JOIN', event)
      // 进房成功,触发该事件后可以对本地视频和音频进行设置
      if (this.options.localVideo === true || this.options.template === '1v1') {
        this.trtcComponent.publishLocalVideo()
      }
      if (this.options.localAudio === true || this.options.template === '1v1') {
        this.trtcComponent.publishLocalAudio()
      }
      if (this.callVideo.input.template === 'custom') {
        this.trtcComponent.setViewRect({
          userID: event.userID,
          xAxis: '0rpx',
          yAxis: '0rpx',
          width: '240rpx',
          height: '320rpx',
        })
      }
    })
    this.trtcComponent.on(TRTC_EVENT.LOCAL_LEAVE, (event)=>{
      console.log('* room LOCAL_LEAVE', event)
    })
    this.trtcComponent.on(TRTC_EVENT.ERROR, (event)=>{
      console.log('* room ERROR', event)
    })
    // 远端用户进房
    this.trtcComponent.on(TRTC_EVENT.REMOTE_USER_JOIN, (event)=>{
      console.log('组件所在页面  远端用户进房', event, this.trtcComponent.getRemoteUserList())
      this.timestamp.push(new Date())
      // 1v1视频通话时限制人数为两人的简易逻辑,建议通过后端实现房间人数管理
      // 2人以上同时进行通话请选择网格布局
      if (this.template === '1v1' && this.timestamp.length > 1) {
        const interval = this.timestamp[1] - this.timestamp[0]
        if (interval < 1000) {
          // 房间里已经有两个人
          // this.setData({
          //   showTipToast: true,
          // }, () => {
          //   setTimeout(()=>{
          //     this.setData({
          //       showTipToast: false,
          //     })
              uni.navigateBack({
                delta: 1,
              })
          //   }, 4000)
          // })
        }
      }
    })
    // 远端用户退出
    this.trtcComponent.on(TRTC_EVENT.REMOTE_USER_LEAVE, (event)=>{
      console.log('组件所在页面  远端用户退出', event, this.trtcComponent.getRemoteUserList())
      //跳转到感谢致电页面
      this.methods('toPage','/pages/callOver/index')
      if (this.template === '1v1') {
        this.timestamp = []
      }
      if (this.template === '1v1' && this.remoteUser === event.data.userID) {
        this.remoteUser = null
      }
    })
    // 远端用户推送视频
    this.trtcComponent.on(TRTC_EVENT.REMOTE_VIDEO_ADD, (event)=>{
      console.log('组件所在页面  远端用户推送视频', event, this.template,this.remoteUser)
      // 订阅视频
      const userList = this.trtcComponent.getRemoteUserList()
      const data = event.data
      if (this.template === '1v1' && (!this.remoteUser || this.remoteUser === data.userID)) {
        // 1v1 只订阅第一个远端流
        this.remoteUser = data.userID;
        this.trtcComponent.subscribeRemoteVideo({
          userID: data.userID,
          streamType: data.streamType
        });
      } else if (this.template === 'grid') {
        this.trtcComponent.subscribeRemoteVideo({
          userID: data.userID,
          streamType: data.streamType
        });
      }
      if (this.template === 'custom' && data.userID && data.streamType) {
        let index = userList.findIndex((item)=>{
          return item.userID === data.userID
        })
        index++
        const y = 320 * index + 160
        // 设置远端视图坐标和尺寸
        this.trtcComponent.setViewRect({
          userID: data.userID,
          streamType: data.streamType,
          xAxis: '480rpx',
          yAxis: y + 'rpx',
          width: '240rpx',
          height: '320rpx',
        })
      }
    })
    // 远端用户取消推送视频
    this.trtcComponent.on(TRTC_EVENT.REMOTE_VIDEO_REMOVE, (event)=>{
      console.log('组件所在页面  远端用户取消推送视频', event, this.trtcComponent.getRemoteUserList())
    })
    // 远端用户推送音频
    this.trtcComponent.on(TRTC_EVENT.REMOTE_AUDIO_ADD, (event)=>{
      console.log('组件所在页面  远端用户推送音频', event, this.template,this.remoteUser )
      // 订阅音频
      const data = event.data
      if (this.template === '1v1' && (!this.remoteUser || this.remoteUser === data.userID)) {
        this.remoteUser = data.userID;
        this.trtcComponent.subscribeRemoteAudio({
          userID: data.userID
        });
      } else if (this.template === 'grid' || this.template === 'custom') {
        this.trtcComponent.subscribeRemoteAudio({
          userID: data.userID
        });
      } 
    })
    // 远端用户取消推送音频
    this.trtcComponent.on(TRTC_EVENT.REMOTE_AUDIO_REMOVE, (event)=>{
      console.log('组件所在页面  远端用户取消推送音频', event, this.trtcComponent.getRemoteUserList())
    })
    // this.trtcComponent.on(TRTC_EVENT.LOCAL_NET_STATE_UPDATE, (event)=>{
    //   console.log('* room LOCAL_NET_STATE_UPDATE', event)
    // })
    // this.trtcComponent.on(TRTC_EVENT.REMOTE_NET_STATE_UPDATE, (event)=>{
    //   console.log('* room REMOTE_NET_STATE_UPDATE', event)
    // })
    this.trtcComponent.on(TRTC_EVENT.IM_READY, (event)=>{
      console.log('* room IM_READY', event)
    })
    this.trtcComponent.on(TRTC_EVENT.IM_MESSAGE_RECEIVED, (event)=>{
      console.log('* room IM_MESSAGE_RECEIVED', event)
    })
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258

记得在微信公众平台打开视频推流拉流权限
在这里插入图片描述
无意间在博客看到一个广告,也不知道怎么样,有没有人用过声网的这个实时视频sdk
在这里插入图片描述

https://www.agora.io/cn/usecase,看起来和腾讯的很相似

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/538976
推荐阅读
相关标签
  

闽ICP备14008679号