<template>
|
<view class="content">
|
<!-- 加入频道 -->
|
<view class="index" v-if="!videoShow">
|
<!-- 输入频道 -->
|
<view class="chanel">
|
<input class="uni-input activetext" v-model="channel" focus placeholder="请输入频道号" />
|
</view>
|
|
<view class="setrole">
|
|
<button type="default" :class="role == 1? 'active': 'button'" @click="setClientRole(1)"><text class="text button_text"
|
:class="role == 1? 'activetext': ''">我是主播</text></button>
|
|
<button type="default" :class="role == 2? 'active': 'button'" @click="setClientRole(2)"><text class="text" :class="role == 2? 'activetext': ''">我是游客</text></button>
|
</view>
|
|
<view class="join">
|
<button type="primary" class="button jion_bg" @click="join"><text class="activetext">加入频道</text></button>
|
</view>
|
</view>
|
|
<!-- 视频 -->
|
<view class="vedio vedioWatch" v-else>
|
|
<view class="video_bg">
|
<image class="video_bg_img" src="../../static/BG.png" mode=""></image>
|
<!-- <text class="activetext" v-if="videoShowBg"></text> -->
|
<!-- <view class="video_bg video_bg_text">
|
|
<text class="activetext">{{promptText}}</text>
|
</view> -->
|
</view>
|
|
<view class="video_region" :class="PeerVideoUser.length > 1 ? 'video_region_padding' : ''">
|
<!-- 渲染视频 -->
|
<view v-for="peervideo in PeerVideoUser" :key="peervideo">
|
<view :class="PeerVideoUserStyle" v-if="peervideo == uid && role == 2 ? false : true">
|
<AR-CanvasView :ref="`popup${peervideo}`" style="flex: 1;"></AR-CanvasView>
|
</view>
|
|
</view>
|
</view>
|
|
<!-- 转换摄像头 -->
|
<view class="camera position" @click="cameraSwitchFn" v-if="role == 1">
|
<image class="video_bg_img" src="../../static/camera.png" mode=""></image>
|
|
</view>
|
<!-- 音视频基本开关 -->
|
<view class="videoshow_control position">
|
<!-- 音频开关 -->
|
<view class="open" @click="audioSwitchFn" v-if="role == 1">
|
<image class="video_bg_img" src="../../static/au_in.png" mode="" v-if="audioSwitch == 'open'"></image>
|
<image class="video_bg_img" src="../../static/au_on.png" mode="" v-else></image>
|
<text class="open_text">音频</text>
|
</view>
|
|
<!-- 挂断 -->
|
<view class="open" @click="phoneFn">
|
<image class="video_bg_img" src="../../static/over.png" mode=""></image>
|
<text class="open_text">挂断</text>
|
|
</view>
|
|
<!-- 视频开关 -->
|
<view class="open" @click="vedioSwitchFn" v-if="role == 1">
|
<image class="video_bg_img" src="../../static/vi_on.png" mode="" v-if="vedioSwitch == 'open'"></image>
|
<image class="video_bg_img" src="../../static/vi_in.png" mode="" v-else></image>
|
<text class="open_text">视频</text>
|
</view>
|
|
<!-- <scroll-view scroll-y="true" style="height: 500px;padding: 20px;">
|
<view v-for="(item,value) in closeArray" :key='item+value'>{{item}}</view>
|
</scroll-view> -->
|
</view>
|
<!-- 提示文字 -->
|
<view class="video_bg video_bg_text" v-if="promptText">
|
<!-- <view class="video_bg video_bg_text"> -->
|
<text class="activetext">{{promptText}}</text>
|
<!-- </view> -->
|
</view>
|
</view>
|
<uni-popup ref="popup" type="center">
|
<uni-popup-message :type="popupType" :message="popupMessage" :duration="2000"></uni-popup-message>
|
</uni-popup>
|
</view>
|
|
|
</template>
|
|
<script>
|
const RtcModule = uni.requireNativePlugin('AR-RtcModule');
|
import uniPopup from '@/components/uni-popup/uni-popup.vue'
|
import uniPopupMessage from '@/components/uni-popup-message/uni-popup-message.vue'
|
import uniPopupDialog from '@/components/uni-popup-dialog/uni-popup-dialog.vue'
|
import permision from "@/js_sdk/wa-permission/permission.js"
|
export default {
|
components: {
|
uniPopup,
|
uniPopupMessage,
|
uniPopupDialog
|
},
|
data() {
|
return {
|
//anyRTC 为 App 开发者签发的 App ID。每个项目都应该有一个独一无二的 App ID。如果你的开发包里没有 App ID,请从anyRTC官网(https://www.anyrtc.io)申请一个新的 App ID
|
appid: "d5a164cd8e0a8352ee108c561ba2e44e",
|
channel: "",
|
uid: "",
|
role: 1, //角色 主播-游客
|
|
videoShow: false, //视频展示
|
// videoShowBg: true, //背景展示
|
promptText: "loading...",
|
|
PeerVideoUser: [], //用户视频加入存储
|
PeerVideoUserStyle: "video_local", //用户视频加入样式
|
|
// 本地
|
audioSwitch: "open", //音频开关
|
vedioSwitch: "open", //视频开关
|
|
videoWidth: 0,
|
videoHeight: 0,
|
//提示
|
popupType: "",
|
popupMessage: "",
|
|
// closeArray: []
|
}
|
},
|
// 页面初始加载(仅执行一次)
|
onReady() {
|
// 初始化
|
console.log(RtcModule)
|
this.init();
|
},
|
|
watch: {
|
PeerVideoUser: function(newName) {
|
if (this.role == 2) {
|
newName = newName.filter((x) => x !== this.uid);
|
}
|
// video_local
|
if (newName.length == 1) {
|
this.PeerVideoUserStyle = "video_local"
|
} else if (newName.length > 1 && newName.length < 5) {
|
this.PeerVideoUserStyle = "video_local_1"
|
} else if (newName.length > 4 && newName.length < 10) {
|
this.PeerVideoUserStyle = "video_local_2"
|
} else if (newName.length > 9 && newName.length < 17) {
|
this.PeerVideoUserStyle = "video_local_3"
|
} else if (newName.length == 0) {
|
this.role == 2 ? this.promptText = "暂无主播播放视频" : this.promptText = "loading..."
|
}
|
}
|
},
|
methods: {
|
// 初始化
|
async init() {
|
// 查看权限
|
if (uni.getSystemInfoSync().platform == 'ios') {
|
//查看相机权限
|
await this.requestAndroidPermission("camera", 'ios');
|
//查看录音权限
|
await this.requestAndroidPermission("record", 'ios');
|
|
} else if (uni.getSystemInfoSync().platform === 'android') {
|
//查看相机权限
|
await this.requestAndroidPermission("android.permission.CAMERA", 'android');
|
//查看录音权限
|
await this.requestAndroidPermission("android.permission.RECORD_AUDIO", 'android');
|
}
|
// 初始化 setCallBack
|
await this.callbackFn();
|
// 初始化 create
|
|
await RtcModule.create({
|
"appId": this.appid
|
}, (res) => {
|
|
});
|
this.uid = this.randomFn(6);
|
},
|
//设置角色
|
setClientRole(num) {
|
this.role = num;
|
//设置直播场景下的用户角色
|
RtcModule.setClientRole({
|
"role": num
|
}, (ret) => {});
|
},
|
|
//加入频道 跳转到视频
|
async join() {
|
uni.showLoading({
|
title: '加载中',
|
mask: true
|
});
|
//加入房间
|
await RtcModule.joinChannel({
|
"token": "",
|
"channelId": this.channel,
|
"uid": this.uid
|
}, (res) => {
|
console.log(res,'join break')
|
})
|
},
|
|
// 挂断 离开
|
phoneFn() {
|
//离开频道
|
RtcModule.leaveChannel((res) => {})
|
},
|
|
//添加本地视频到页面
|
setupLocalVideoFn() {
|
//视频
|
RtcModule.enableVideo((res) => {});
|
this.$refs[`popup${this.uid}`][0].setupLocalVideo({
|
"renderMode": 1,
|
"channelId": this.channel,
|
"uid": this.uid,
|
"mirrorMode": 0
|
}, (res) => {});
|
// 本地预览
|
RtcModule.startPreview((res) => {});
|
},
|
|
// 视频
|
vedioSwitchFn() {
|
let open = true;
|
|
if (this.vedioSwitch == "open") {
|
this.vedioSwitch = "colse";
|
open = false;
|
} else {
|
this.vedioSwitch = "open";
|
open = true;
|
}
|
RtcModule.enableLocalVideo({
|
"enabled": open
|
}, (res) => {
|
if (res.code == 0) {
|
open == false ? this.promptFn("warn", "关闭本地视频采集") : this.promptFn("info", "开启本地视频采集");
|
}
|
});
|
},
|
// 音频
|
audioSwitchFn() {
|
let open = true;
|
if (this.audioSwitch == "open") {
|
this.audioSwitch = "colse";
|
open = false;
|
} else {
|
this.audioSwitch = "open";
|
open = true;
|
}
|
|
RtcModule.enableLocalAudio({
|
"enabled": open
|
}, (res) => {
|
if (res.code == 0) {
|
open == false ? this.promptFn("warn", "关闭本地音频采集") : this.promptFn("info", "开启本地音频采集");
|
}
|
});
|
},
|
//转化摄像头
|
cameraSwitchFn() {
|
RtcModule.switchCamera((res) => {
|
res.code == 0 ? this.promptFn("success", "切换摄像头成功") : this.promptFn("error", "切换摄像头失败");
|
})
|
},
|
|
//callback 接收
|
callbackFn() {
|
RtcModule.setCallBack((res) => {
|
switch (res.engineEvent) {
|
case "onWarning":
|
this.promptFn("warn", res.warningCode);
|
break;
|
case "onError":
|
res.errorCode != 18 ? this.promptFn("error", res.errorCode) : '';
|
break;
|
case "onJoinChannelSuccess": //用户加入成功
|
uni.hideLoading();
|
this.role == 1 ? this.PeerVideoUser.push(res.uid) : "";
|
this.videoShow = true;
|
setTimeout(() => {
|
// this.videoShowBg = false;
|
this.promptText = ""
|
//扬声器
|
RtcModule.setEnableSpeakerphone({
|
"enabled": true
|
}, (res) => {})
|
setTimeout(() => {
|
// 启用视频模块。
|
this.role == 1 ? this.setupLocalVideoFn() : RtcModule.enableVideo((res) => {});
|
}, 200)
|
}, 2000)
|
break;
|
case "onLeaveChannel": //离开频道回调
|
setTimeout(() => {
|
this.closeAll()
|
}, 500)
|
break;
|
case "onUserJoined": //远端用户加入当前频道回调。
|
// this.promptFn("info", "远端用户加入当前频道回调");
|
this.PeerVideoUser.push(res.uid);
|
break;
|
case "onUserOffline": //远端用户离开当前频道回调。
|
this.PeerVideoUser = this.PeerVideoUser.filter((x) => x !== res.uid);
|
break;
|
|
case "onFirstLocalAudioFrame": //已发送本地音频首帧的回调。(页面上添加音频)
|
break;
|
case "onFirstLocalVideoFrame": //已显示本地视频首帧的回调。(页面添加本地视频)
|
// this.promptFn("error", "已显示本地视频首帧的回调");
|
break;
|
case "onFirstRemoteVideoDecoded": //已完成远端视频首帧解码回调。(页面添加远端视频)
|
// this.promptFn("info", "已完成远端视频首帧解码回调");
|
this.promptText = "请稍等。。。"
|
let uid = []
|
uid.push(res.uid)
|
setTimeout(() => {
|
this.promptText = "";
|
// this.videoShowBg = false; //设置背景开关
|
setTimeout(() => {
|
uid.map(item => {
|
this.$refs[`popup${item}`][0].setupRemoteVideo({
|
"renderMode": 1,
|
"channelId": this.chanel,
|
"uid": item,
|
"mirrorMode": 0
|
}, (res) => {})
|
//预览
|
RtcModule.startPreview((res) => {});
|
})
|
}, 500)
|
|
}, 2000)
|
break;
|
}
|
|
})
|
},
|
//提示
|
promptFn(type, content) {
|
this.popupType = type;
|
this.popupMessage = content;
|
this.$refs.popup.open()
|
},
|
//支持自定义字符长度和特征字符集合
|
randomFn(len, charSet) {
|
charSet = charSet || 'abcdefghijklmnopqrstuvwxyz0123456789';
|
let randomString = '';
|
for (let i = 0; i < len; i++) {
|
let randomPoz = Math.floor(Math.random() * charSet.length);
|
randomString += charSet.substring(randomPoz, randomPoz + 1);
|
}
|
return randomString;
|
},
|
// 离开清空
|
async closeAll() {
|
// 销毁实例
|
await RtcModule.destroyRtc((res) => {});
|
this.videoShow = false; //视频展示
|
// this.videoShowBg = true; //背景展示
|
this.promptText = "loading...";
|
|
this.PeerVideoUser = []; //远端用户加入存储
|
// 本地
|
this.audioSwitch = "open"; //音频开关
|
this.vedioSwitch = "open"; //视频开关
|
// 重新创建实例
|
await this.init();
|
// 如果需要跳转其它页面请按下边步骤
|
// await uni.redirectTo({
|
// url: '..',
|
// success: () => {
|
// RtcModule.destroyRtc((res) => {
|
// console.log("页面销毁", res.code);
|
// });
|
// }
|
// });
|
|
},
|
//查看授权
|
async requestAndroidPermission(permisionID, type) {
|
let result = 0;
|
let strStatus = "";
|
type == 'ios' ? result = await permision.judgeIosPermission(permisionID) : result = await permision.requestAndroidPermission(
|
permisionID);
|
if (result == 1) {
|
strStatus = "已获得授权"
|
} else if (result == 0) {
|
strStatus = "未获得授权"
|
} else {
|
strStatus = "被永久拒绝权限"
|
}
|
},
|
|
}
|
}
|
</script>
|
|
<style>
|
.content {
|
flex: 1;
|
}
|
|
/* 加入频道 */
|
.index {
|
flex: 1;
|
background-color: #0A1621;
|
}
|
|
.chanel {
|
padding: 120px 20px 20px;
|
}
|
|
.uni-input {
|
height: 120rpx;
|
padding: 0 20px;
|
background-color: #2F3041;
|
border-radius: 6px;
|
}
|
|
.setrole {
|
padding: 60px 20px;
|
flex-direction: row;
|
justify-content: space-between;
|
}
|
|
.button {
|
padding: 10px 70rpx;
|
background-color: #2F3041;
|
border-radius: 6px;
|
border-width: 2px;
|
border-color: #2f3041;
|
}
|
|
.text {
|
color: #B4B5BE;
|
}
|
|
|
|
.activetext {
|
color: #fff;
|
}
|
|
.active {
|
padding: 10px 70rpx;
|
border-radius: 6px;
|
border-width: 2px;
|
border-color: #40a3fb;
|
background-color: #0A1621;
|
}
|
|
.join {
|
padding: 20px;
|
}
|
|
.jion_bg {
|
background-color: #40A3FB;
|
border-width: 0;
|
}
|
|
|
/* 视频 */
|
.vedioWatch {
|
flex: 1;
|
position: relative;
|
}
|
|
/* 初始背景 */
|
.video_bg {
|
flex: 1;
|
position: absolute;
|
top: 0;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background-color: transparent;
|
}
|
|
.video_bg_img {
|
flex: 1;
|
}
|
|
.video_bg_text {
|
justify-content: center;
|
align-items: center;
|
}
|
|
/* 转换摄像头 */
|
.camera {
|
width: 44px;
|
height: 37px;
|
/* position: absolute; */
|
left: 20px;
|
top: 40px;
|
}
|
|
/* 视频区域 */
|
.video_region {
|
flex: 1;
|
/* position: absolute; */
|
flex-wrap: wrap;
|
flex-direction: row;
|
background-color: transparent;
|
}
|
|
/* 1个视频 */
|
.video_local {
|
width: 750rpx;
|
height: 1334rpx;
|
background-color: transparent;
|
}
|
|
.video_region_padding {
|
margin-top: 20px;
|
padding: 200rpx 0 260rpx;
|
width: 750rpx;
|
height: 840rpx;
|
}
|
|
/* 4个视频 */
|
.video_local_1 {
|
width: 375rpx;
|
height: 420rpx;
|
}
|
|
/* 9个视频 */
|
.video_local_2 {
|
width: 250rpx;
|
height: 280rpx;
|
}
|
|
/* 16个视频 */
|
.video_local_3 {
|
width: 187.5rpx;
|
height: 210rpx;
|
}
|
|
/* 音视频基本开关 */
|
.videoshow_control {
|
/* position: absolute; */
|
bottom: 20rpx;
|
left: 0;
|
width: 750rpx;
|
/* background-color: #007AFF; */
|
/* height: 250rpx; */
|
padding: 20px;
|
background-color: transparent;
|
color: #fff;
|
flex-direction: row;
|
justify-content: space-around;
|
}
|
|
.open {
|
height: 205rpx;
|
width: 128rpx;
|
justify-content: center;
|
}
|
|
.open_text {
|
padding: 15px 0 0;
|
text-align: center;
|
color: #fff;
|
}
|
|
.position {
|
position: absolute;
|
}
|
</style>
|