Compare commits

..

28 Commits

Author SHA1 Message Date
zhangtao 7874ebd377 change axios 2022-12-08 11:37:03 +08:00
zhangtao 285c149943 change mirror 2022-11-29 09:40:25 +08:00
zhangtao bc2b7dfb1e change mirror 2022-11-28 17:21:59 +08:00
zhangtao d8546abbaf change device 2022-10-28 10:21:55 +08:00
zhangtao ac94990547 change device 2022-10-28 10:16:26 +08:00
zhangtao c3d3e737b7 change device 2022-10-28 10:10:28 +08:00
zhangtao ca616cfb08 change device 2022-10-28 10:04:15 +08:00
zhangtao 69356dd714 change device 2022-10-28 10:00:26 +08:00
zhangtao 95bfae8356 change api 2022-10-26 18:20:52 +08:00
zhangtao 7825e02ef5 change heart 2022-10-26 15:44:38 +08:00
zhangtao f2b4cc7091 taskid 2022-10-26 10:49:41 +08:00
zhangtao c3346a2f1f change domain 2022-10-24 11:09:50 +08:00
zhangtao 8682fa26db add log 2022-10-24 09:56:30 +08:00
zhangtao b18105f02d add log 2022-10-24 09:45:53 +08:00
zhangtao a91424d995 string userid 2022-10-24 09:39:42 +08:00
zhangtao 71cb7da4d4 string userid 2022-10-24 09:37:35 +08:00
zhangtao fd4cc250f9 string userid 2022-10-24 09:14:55 +08:00
zhangtao 26ccf348e5 userSig 2022-10-23 14:21:10 +08:00
zhangtao 51af040686 userSig 2022-10-23 11:57:31 +08:00
zhangtao 10ad7cdeb2 add mini redirect 2022-10-22 14:56:00 +08:00
zhangtao 8bcb39045c add mini redirect 2022-10-22 14:53:07 +08:00
zhangtao 83a9ed380e add mini redirect 2022-10-22 14:49:46 +08:00
zhangtao 29e1ccad73 change camera 2022-10-22 14:17:25 +08:00
zhangtao b696b192ed change camera 2022-10-22 14:13:10 +08:00
zhangtao d911a20419 add log 2022-10-22 11:59:12 +08:00
zhangtao 377c3e7856 view camera 2022-10-22 10:38:28 +08:00
zhangtao 2698ba7007 view camera 2022-10-22 10:22:57 +08:00
zhangtao 54f189b4c4 public 2022-10-21 18:32:18 +08:00
9 changed files with 304 additions and 71 deletions

2
.env
View File

@ -1,5 +1,5 @@
# title
VITE_APP_TITLE = 'h5'
VITE_APP_TITLE = '视频会议'
# 端口号
VITE_PORT = 3000

View File

@ -10,6 +10,8 @@
<link rel="icon" href="/favicon.ico" />
<title><%= title %></title>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
</head>
<body>
<div id="app"></div>

1
public/DYFRqZwcf2.txt Normal file
View File

@ -0,0 +1 @@
db957f82a208d53cdaeff928dd554022

View File

@ -37,8 +37,6 @@ body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {

View File

@ -3,10 +3,11 @@ html {
}
html,
body {
body,#app{
width: 100%;
min-width: 1440px;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f2f2f2;
font-family: 'Encode Sans Condensed', sans-serif;

View File

@ -1,75 +1,71 @@
<template>
<div class="select-container">
<n-select
v-model:value="activeDeviceId"
class="select"
:placeholder="deviceType"
:options="deviceList"
value-field="deviceId"
@update:value="handleChange"
/>
</div>
<div class="select-container" />
</template>
<script>
import TRTC from 'trtc-js-sdk'
import { reactive, toRefs, onMounted, defineComponent } from 'vue'
import { defineComponent, reactive, toRefs, onMounted, onBeforeUnmount } from 'vue'
export default defineComponent({
name: 'DeviceSelect',
props: {
deviceType: {
type: String,
default: () => {}
},
value: {
type: String,
default: () => {}
}
},
emits: ['update:value'],
emits: ['init', 'switch'],
setup(props, { emit }) {
const data = reactive({
deviceList: [],
activeDeviceId: ''
videoList: [],
audioList: [],
videoDeviceId: '',
audioDeviceId: ''
})
const getDeviceList = async() => {
switch (props.deviceType) {
case 'camera':
data.deviceList = await TRTC.getCameras()
break
case 'microphone':
data.deviceList = await TRTC.getMicrophones()
break
case 'speaker':
data.deviceList = await TRTC.getSpeakers()
break
default:
break
}
data.activeDeviceId = data.deviceList[0].deviceId
emit('update:value', data.activeDeviceId)
data.videoList = await TRTC.getCameras()
data.audioList = await TRTC.getMicrophones()
data.videoDeviceId = data.videoList[0]?.deviceId || ''
data.audioDeviceId = data.audioList[0]?.deviceId || ''
emit('init', {
cameraId: data.videoDeviceId,
microphoneId: data.audioDeviceId
})
}
const handleChange = (value) => {
data.activeDeviceId = value
emit('update:value', data.activeDeviceId)
const handleCameraReverse = () => {
const index = data.videoList.findIndex((item) => item.deviceId === data.videoDeviceId)
const len = data.videoList.length
if (len <= 1) {
return
} else if (index === 0) {
data.videoDeviceId = data.videoList[len - 1].deviceId
emit('init', {
cameraId: data.videoDeviceId,
microphoneId: data.audioDeviceId
})
emit('switch', { type: 'video', cameraId: data.videoDeviceId, isMirror: false })
} else {
data.videoDeviceId = data.videoList[0].deviceId
emit('init', {
cameraId: data.videoDeviceId,
microphoneId: data.audioDeviceId
})
emit('switch', { type: 'video', cameraId: data.videoDeviceId, isMirror: true })
}
}
onMounted(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(() => {
.then((res) => {
getDeviceList()
})
// navigator.mediaDevices.addEventListener('devicechange', this.getDeviceList)
navigator.mediaDevices.addEventListener('devicechange', getDeviceList)
})
onBeforeUnmount(() => {
navigator.mediaDevices.removeEventListener('devicechange', getDeviceList)
})
// beforeUnmount() {
// navigator.mediaDevices.removeEventListener('devicechange', this.getDeviceList)
// }
return {
...toRefs(data),
handleChange
handleCameraReverse
}
}

View File

@ -0,0 +1,127 @@
<template>
<div class="select-container">
<n-select
v-model:value="activeDeviceId"
class="select"
:placeholder="deviceType"
:options="deviceList"
value-field="deviceId"
@update:value="handleChange"
/>
</div>
</template>
<script>
import TRTC from 'trtc-js-sdk'
import { defineComponent, reactive, toRefs, onMounted, onBeforeUnmount } from 'vue'
export default defineComponent({
name: 'DeviceSelect',
props: {
deviceType: {
type: String,
default: () => {}
},
value: {
type: String,
default: () => {}
}
},
emits: ['update:value', 'switch'],
setup(props, { emit }) {
const data = reactive({
deviceList: [],
activeDeviceId: ''
})
const getDeviceList = async() => {
switch (props.deviceType) {
case 'video':
data.deviceList = await TRTC.getCameras()
break
case 'audio':
data.deviceList = await TRTC.getMicrophones()
break
case 'speaker':
data.deviceList = await TRTC.getSpeakers()
break
default:
break
}
data.activeDeviceId = data.deviceList[0].deviceId
emit('update:value', data.activeDeviceId)
}
const handleChange = (value) => {
data.activeDeviceId = value
emit('update:value', data.activeDeviceId)
emit('switch', { type: props.deviceType, deviceId: data.activeDeviceId })
}
const handleReverse = () => {
const index = data.deviceList.findIndex((item) => item.deviceId === data.activeDeviceId)
if (data.deviceList.length === 1) {
return
} else if (index === 0) {
data.activeDeviceId = data.deviceList[1].deviceId
emit('update:value', data.activeDeviceId)
emit('switch', { type: props.deviceType, deviceId: data.activeDeviceId })
} else {
data.activeDeviceId = data.deviceList[0].deviceId
emit('update:value', data.activeDeviceId)
emit('switch', { type: props.deviceType, deviceId: data.activeDeviceId })
}
}
onMounted(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then((res) => {
console.log(res)
getDeviceList()
})
navigator.mediaDevices.addEventListener('devicechange', getDeviceList)
})
onBeforeUnmount(() => {
navigator.mediaDevices.removeEventListener('devicechange', getDeviceList)
})
return {
...toRefs(data),
handleChange,
handleReverse
}
}
})
</script>
<style lang="scss" scoped>
.select-container {
display: flex;
.label {
display: inline-block;
padding: 0 20px;
width: 120px;
height: 40px;
text-align: left;
line-height: 40px;
border-top: 1px solid #DCDFE6;
border-left: 1px solid #DCDFE6;
border-bottom: 1px solid #DCDFE6;
border-radius: 4px 0 0 4px;
color: #909399;
background-color: #F5F7FA;
font-weight: bold;
}
.select {
flex-grow: 1;
}
}
</style>
<style lang="scss">
.select {
input {
border-radius: 0 4px 4px 0 !important;
}
}
</style>

View File

@ -1,7 +1,8 @@
<template>
<div class="room">
<DeviceSelect v-show="false" v-model:value="cameraId" device-type="camera" />
<DeviceSelect v-show="false" v-model:value="microphoneId" device-type="microphone" />
<!-- <DeviceSelect v-show="false" ref="cameraRef" v-model:value="cameraId" device-type="video" @switch="handleCamareSwitch" /> -->
<!-- <DeviceSelect v-show="false" v-model:value="microphoneId" device-type="audio" /> -->
<Device ref="cameraRef" @init="deviceInit" @switch="handleCamareSwitch" />
<!-- 远端 -->
<div class="remote-container">
@ -19,6 +20,11 @@
<div id="localStream" class="local-stream-content" />
<!-- 本地流操作栏 -->
<div v-if="isPlayingLocalStream" class="local-stream-control">
<div class="video-control control">
<n-icon size="40" @click="handelCameraReverse">
<CameraReverseOutline />
</n-icon>
</div>
<div class="video-control control">
<n-icon v-if="!isMutedVideo" size="40" @click="handleVideoMute">
<VideocamOutline />
@ -46,16 +52,21 @@
<script>
import TRTC from 'trtc-js-sdk'
import { useRoute } from 'vue-router'
import DeviceSelect from './components/Device.vue'
import { reactive, toRefs, onMounted, watch, nextTick } from 'vue'
import { VideocamOutline, VideocamOffOutline } from '@vicons/ionicons5'
import Device from './components/Device.vue'
// import DeviceSelect from './components/DeviceSelect.vue'
import { ref, reactive, toRefs, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { CameraReverseOutline, VideocamOutline, VideocamOffOutline } from '@vicons/ionicons5'
import { AudioOutlined, AudioMutedOutlined } from '@vicons/antd'
import { isUndef } from '@/utils/is.js'
import { formatDateTime } from '@/utils/index.js'
import axios from 'axios'
// import { Screen, ScreenOff } from '@vicons/carbon'
export default {
name: 'HomePage',
components: {
DeviceSelect,
Device,
// DeviceSelect,
CameraReverseOutline,
VideocamOutline,
VideocamOffOutline,
AudioOutlined,
@ -63,17 +74,19 @@ export default {
},
setup() {
const route = useRoute()
const cameraRef = ref()
const data = reactive({
hasInit: false,
client: null,
timer: null,
sdkAppId: 1400752641,
sdkSecret: '9b5fc557f286d7e4d6eafd8023026da59f0674000f319754aa1ec4beefddcdd6',
userId: '',
userId: null,
userSig: null,
roomId: null,
secret: {
'haoran': 'eJwtzEELgjAYxvHvsqsh29ymCB28hIIElZR1G2y1ty2VJSVE3z1Tj8-vgf8HVeUhfGmPUkRDjFbTBqWbHq4wsZGtl83yPJWVXQcKpYRhHHMqGJkfPXTg9eicc4oxnrWHx9*EEFHECGVLBW5jWMn6HCRBW7njJd*WNgNrNrnbFXcZG356V94Vg7W12ydr9P0BbGAyOQ__',
'wanghaoran': 'eJwtzEELgjAcBfDvsnO4ubnFhA6ihwIhUqEOXhZO*6dNUalF9N0z9fh*7-E*KItT56l75CPqELSZMxTajFDCzC9lqptqe2XWdihq1XVQIN-1CNlyKjx3abTtoNeTc84pIWTRER5-E0IwVwq5bgeopnPPRDluaVPGTb1P3nd7CcPMHgJ2zbFJ5HCKrDkHxzLHMmX1Dn1-G3A0Zg__'
},
remoteStreamList: []
taskId: null,
remoteStreamList: [],
isMirror: true
})
const settings = reactive({
@ -98,7 +111,7 @@ export default {
data.client = TRTC.createClient({
sdkAppId: data.sdkAppId, // sdkAppId
userId: data.userId, // userId
userSig: data.secret[data.userId], // userSig
userSig: data.userSig, // userSig
mode: 'rtc'
})
handleClientEvents()
@ -115,6 +128,10 @@ export default {
status.isJoining = false
status.isJoined = true
startGetAudioLevel()
updateUsers(2)
data.timer = setInterval(async() => {
await heartbeat()
}, 5000)
} catch (error) {
status.isJoining = false
console.error('join room failed', error)
@ -293,7 +310,10 @@ export default {
* @return {*}
*/
const playLocalStream = async() => {
settings.localStream.play('localStream')
if (settings.localStream && settings.isPlayingLocalStream) {
settings.isPlayingLocalStream = false
}
settings.localStream.play('localStream', { mirror: data.isMirror })
.then(() => {
settings.isPlayingLocalStream = true
})
@ -405,6 +425,24 @@ export default {
data.client && data.client.enableAudioVolumeEvaluation(-1)
}
/**
* @description: 切换音频
* @param {*} type
* @param {*} cameraId
* @return {*}
*/
const handleCamareSwitch = ({ type, cameraId, isMirror = true }) => {
try {
if (settings.localStream) {
data.isMirror = isMirror
settings.localStream.switchDevice(type, cameraId)
playLocalStream()
}
} catch (error) {
console.error('switchDevice failed', error)
}
}
/**
* @description: 退出直播间
* @return {*}
@ -422,6 +460,7 @@ export default {
await data.client.leave()
status.isLeaving = false
status.isJoined = false
wx.miniProgram.switchTab({ url: '/pages/tool/tool' })
} catch (error) {
status.isLeaving = false
console.error('leave room error', error)
@ -429,13 +468,78 @@ export default {
}
}
onMounted(() => {
const { userId, roomId } = route.query
data.userId = userId
/**
* @description: 用户签名
* @return {*}
*/
const handleSig = async() => {
const res = await axios.get(`/hhz/api/tencentCloudRtc/genUserSig/${data.userId}`)
if (res.data.code === 0) {
data.userSig = res.data.data.userSig
}
}
const updateUsers = async(status) => {
const params = {
roomUserId: data.taskId,
status
}
await axios.put(`/hhz/api/meeting/updatePeopleStatus`, params)
}
/**
* @description: 心跳定时调用
* @param {*} status
* @return {*}
*/
const heartbeat = async() => {
const time = new Date().getTime()
const params = {
roomUserId: data.taskId,
heartbeatTime: formatDateTime(time)
}
await axios.put(`/hhz/api/meeting/heartbeatTime`, params)
}
/**
* @description: 翻转摄像头
* @return {*}
*/
const handelCameraReverse = () => {
if (!status.isMutedVideo) {
cameraRef.value.handleCameraReverse()
}
}
onMounted(async() => {
const { userId, roomId, taskId } = route.query
data.userId = String(userId)
data.roomId = Number(roomId)
data.taskId = Number(taskId)
await handleSig()
})
watch(() => [settings.cameraId, settings.microphoneId], async([cameraId, microphoneId]) => {
if (cameraId && microphoneId) {
onBeforeUnmount(() => {
updateUsers(3)
clearInterval(data.timer)
data.timer = null
})
// watch(() => [settings.cameraId, settings.microphoneId], async([cameraId, microphoneId]) => {
// console.log('cameraId:' + cameraId, 'microphoneId:' + microphoneId)
// if (cameraId && microphoneId) {
// data.hasInit = true
// }
// })
const deviceInit = (device) => {
const { cameraId, microphoneId } = device
settings.cameraId = cameraId
settings.microphoneId = microphoneId
data.hasInit = true
}
watch(() => [data.hasInit, data.userSig], async([init, sig]) => {
if (init && sig) {
await createMeetingRoom()
await joinMeetingRoom()
await initLocalStream()
@ -448,10 +552,14 @@ export default {
...toRefs(data),
...toRefs(settings),
...toRefs(status),
cameraRef,
deviceInit,
handleVideoMute,
handleVideoUnMute,
handleAudioMute,
handleAudioUnMute,
handelCameraReverse,
handleCamareSwitch,
leaveMeetingRoom
}
}

View File

@ -23,7 +23,7 @@ export default {
const data = reactive({
form: {
userId: 'wanghaoran',
roomId: 111
roomId: '111'
}
})