实时视频部分内容

This commit is contained in:
tdg930622 2025-01-08 17:06:02 +08:00
parent b092ea2ba0
commit 748ab4c25d
3 changed files with 1327 additions and 2623 deletions

3623
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
"quill-image-resize-module": "^3.0.0",
"sm-crypto": "^0.3.7",
"style-loader": "^2.0.0",
"trtc-sdk-v5": "^5.8.6",
"vue": "^2.6.11",
"vue-meta-info": "^0.1.7",
"vue-quill-editor": "^3.0.6",

View File

@ -1,7 +1,4 @@
<template>
<!-- <div class="video-dialog-wrapper">-->
<!-- </div>-->
<div ref="videoRoom" class="room-content border-radius-8" v-vdrag :class="zoomActive ? `room-content-big` : 'room-content-small'">
<div class="room-top flex-row justify-content-between align-items-center">
<div class="f16 f-weight600">调解视频画面</div>
@ -14,78 +11,20 @@
</div>
</div>
<div class="room-middle">
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<!-- 本地 -->
<div class="video-col position-r" :class="personnelNumber <= 4 ? 'w-50' : 'w-33'" v-show="camStatus">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
<div class="video-col-name text-center color-fff f12">调解人</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<!-- 远端 -->
<div class="video-col position-r" :class="personnelNumber <= 4 ? 'w-50' : 'w-33'"
v-for="(item, index) in remoteUsersViews" :key="index">
<div class="video-col-Graphics border-radius-4" :id="item.id"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
</div>
<div class="video-col position-r" :class="personnelNumber.length <= 4 ? 'w-50' : 'w-33'">
<div class="video-col-Graphics border-radius-4" id="realTimeVideo0"></div>
<div class="video-col-btn" v-if="zoomActive">
<div class="cursor-pointer"><svg-icon class="mb-8" icon-class="sound-off" className="tabs-svg" /></div>
<div class="cursor-pointer"><svg-icon icon-class="remove-room" className="tabs-svg" /></div>
</div>
<div class="video-col-name text-center color-fff f12">申请人 XXX</div>
<div class="video-col-name text-center color-fff f12">{{item.name}}</div>
</div>
</div>
<div v-if="zoomActive" class="room-bottom border-radius-8 background-color-fff flex-row justify-content-between align-items-center">
@ -105,7 +44,7 @@
<svg-icon icon-class="mute-all" className="tabs-svg" />
<div class="pl-4 f14">全部静音</div>
</div>
<div class="room-bottom-btn-finish border-radius-4 f14 color-fff" @click="handleClose">
<div class="room-bottom-btn-finish cursor-pointer border-radius-4 f14 color-fff" @click="handleClose">
结束录制
</div>
</div>
@ -113,6 +52,7 @@
</template>
<script>
import TRTC from 'trtc-sdk-v5';
export default {
props: {
eventDialog: {
@ -125,14 +65,37 @@ export default {
data() {
return {
zoomActive: true,// true false
personnelNumber: [1,2,3,4,5]
roomId: '',
sdkAppId: '',
userId: '',
userSig: '',
cameraId: '',//
microphoneId: '',//
vidStatus: false,//
micStatus: false,//
trtc: null,
personnelNumber: 1,
remoteUsersViews: [],
};
},
computed: {
zoomedStyles() {
return {
left: '269px',
top: '330px'
};
},
defaultTop() {
const itemsPerRow = 4;
const rowHeight = 35.5;
const numberOfRows = Math.ceil(this.personnelNumber / itemsPerRow);
return `${numberOfRows * rowHeight + 35.5}px`;
}
},
mounted() {
this.initMedia()
},
methods: {
handleClose() {
@ -141,39 +104,205 @@ export default {
toggleZoom() {
this.zoomActive = !this.zoomActive;
const zoomedStyles = {
left: '269px',
top: '330px'
};
const defaultStyles = {
left: '157px',
// 71 106.5 141
top: '35.5'
};
this.$nextTick(() => {
if (this.$refs.videoRoom) {
this.$refs.videoRoom.style.left = this.zoomActive ? zoomedStyles.left : defaultStyles.left;
// this.$refs.videoRoom.style.left = '100px';
this.$refs.videoRoom.style.top = this.zoomActive ? zoomedStyles.top : defaultStyles.top;
// this.$refs.videoRoom.style.top = '100px';
console.log(this.defaultTop, '---this.defaultTop')
this.$refs.videoRoom.style.left = this.zoomActive ? this.zoomedStyles.left : '157px';
this.$refs.videoRoom.style.top = this.zoomActive ? this.zoomedStyles.top : this.defaultTop;
}
});
}
},
//
async getDeviceList() {
let camera = await TRTC.getCameraList();
let microphone = await TRTC.getMicrophoneList();
console.log(camera, '---camera')
console.log(microphone, '---microphone')
this.cameraId = camera[0].deviceId;
this.microphoneId = microphone[0].deviceId;
},
async initMedia() {
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((stream) => {
console.log('音视频初始化完毕:', stream)
// stream.getTracks().forEach(track => track.stop());
this.getDeviceList();
}).catch(err =>{
console.log('访问用户媒体设备失败:' , err)
});
} else {
console.log('你的浏览器不支持访问用户媒体设备')
}
},
//
handleEnterRoom() {
let data = {
sdkSecretKey: '',
sdkAppId: '',
userId: '',
roomId: '',
userSig: ''
}
this.enterRoom();
this.handleStartLocalAudio();
this.handleStartLocalVideo();
},
async enterRoom() {
this.trtc = TRTC.create();
try {
await this.trtc.enterRoom({
roomId: this.roomId,
sdkAppId: parseInt(this.sdkAppId, 10),
userId: this.userId,
userSig: this.userSig,
});
this.installEventHandlers();
this.startGetAudioLevel();
}catch (e) {
console.log('视频云初始化报错!', e)
throw e;
}
},
//
async handleStartLocalAudio() {
if (this.micStatus) {
return;
}
try {
await this.trtc.startLocalAudio({
option: {
microphoneId: this.microphoneId,
},
});
this.micStatus = true;
} catch (error) {
throw error;
}
},
async handleStopLocalAudio() {
if (!this.micStatus) {
return;
}
try {
await this.trtc.stopLocalAudio();
this.micStatus = false;
} catch (error) {
throw error;
}
},
//
async handleStartLocalVideo() {
if (this.vidStatus) {
return;
}
try {
await this.trtc.startLocalVideo({
view: 'local',
option: {
cameraId: this.cameraId,
profile: '1080p',
},
});
this.vidStatus = true;
} catch (error) {
throw error;
}
},
async handleStopLocalVideo() {
if (!this.vidStatus) {
return;
}
try {
await this.trtc.stopLocalVideo();
this.vidStatus = false;
} catch (error) {
throw error;
}
},
// 退-
async exitRoom() {
this.stopGetAudioLevel();
try {
await this.trtc.exitRoom();// 退
this.micStatus = false;
this.personnelNumber = 1;
this.remoteUsersViews = [];
this.uninstallEventHandlers();
} catch (error) {
throw error;
}
await this.trtc.stopLocalAudio();//
await this.trtc.stopLocalVideo();//
// await this.trtc.stopScreenShare();//
},
//
startGetAudioLevel() {
this.trtc.on(TRTC.EVENT.AUDIO_VOLUME, (event) => {
event.result.forEach(({ userId, volume }) => {
const isMe = userId === '';
if (isMe) {
console.log(`my volume: ${volume}`);
} else {
console.log(`user: ${userId} volume: ${volume}`);
}
});
});
this.trtc.enableAudioVolumeEvaluation(2000);
},
stopGetAudioLevel() {
this.trtc && this.trtc.enableAudioVolumeEvaluation(-1); //
},
//
installEventHandlers() {
this.trtc.on(TRTC.EVENT.KICKED_OUT, this.handleKickedOut);
this.trtc.on(TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, this.handleRemoteVideoAvailable);
this.trtc.on(TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, this.handleRemoteVideoUnavailable);
},
uninstallEventHandlers() {
this.trtc.off(TRTC.EVENT.KICKED_OUT, this.handleKickedOut);
this.trtc.off(TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, this.handleRemoteVideoAvailable);
this.trtc.off(TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, this.handleRemoteVideoUnavailable);
},
// 退
async handleKickedOut(event) {
this.trtc = null;
await this.exitRoom();
},
//
handleRemoteVideoAvailable(event) {
const { userId, streamType } = event;
try {
let data = {
id: `${userId}_main`,
name: '222',
userId: userId
}
this.personnelNumber++;
this.remoteUsersViews.push(data);
this.$nextTick(async () => {
await this.trtc.startRemoteVideo({ userId, streamType, view: `${userId}_main` });
});
} catch (error) {
console.log(error)
}
},
// 退
handleRemoteVideoUnavailable(event) {
const { streamType } = event;
this.trtc.stopRemoteVideo({ userId: event.userId, streamType });
this.personnelNumber--;
this.remoteUsersViews = this.remoteUsersViews.filter(item => item.userId !== event.userId);
},
}
};
</script>
<style scoped lang="scss">
.video-dialog-wrapper{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
}
.room-content{
background: linear-gradient(180deg, #F8E8FF 0%, #E7EAFE 100%);
border: 2px solid #FFFFFF;
@ -182,6 +311,7 @@ export default {
position: absolute;
margin: 0 !important;
transform: translate(-50%, -50%);
user-select: none;
.room-top{
.room-top-btn{
padding: 6px 10px;
@ -201,7 +331,7 @@ export default {
.video-col-Graphics{
width: 100%;
height: 100%;
background-color: #FFFFFF;
//background-color: #FFFFFF;
}
.video-col-btn{
position: absolute;