视频会议

This commit is contained in:
duoaohui
2026-05-23 23:49:15 +08:00
parent 7eaf448740
commit 9b85c9c9e5

View File

@@ -91,10 +91,6 @@
</view>
</view>
<!-- 屏幕可见的调试浮层小程序 WebView 看不到 console先用这个排查按钮无反应问题 -->
<view v-if="debugLines.length" class="debug-panel">
<view class="debug-line" v-for="(line, idx) in debugLines" :key="idx">{{ line }}</view>
</view>
</view>
</view>
</template>
@@ -321,15 +317,6 @@ const startTimer = () => {
const localMediaError = ref('')
// 屏幕可见的调试日志(小程序 WebView 没法看 console
const debugLines = ref([])
const pushDebug = (msg) => {
try {
const line = `[${new Date().toLocaleTimeString()}] ${msg}`
debugLines.value = [...debugLines.value.slice(-29), line]
console.log('[CloudLawVideoCall][DEBUG]', line)
} catch (e) { /* ignore */ }
}
const joinMeeting = async () => {
if (joining.value) return
@@ -392,10 +379,9 @@ const prepareLocalMediaTracks = async (startWithVideo) => {
}
// #ifdef H5
if (typeof navigator === 'undefined' || !navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
pushDebug('prepare: navigator.mediaDevices 不可用')
console.warn('[CloudLawVideoCall] navigator.mediaDevices 不可用,跳过预申请')
return prefs
}
pushDebug(`prepare -> getUserMedia(audio:true, video:${startWithVideo})`)
try {
const constraints = {
audio: true,
@@ -406,7 +392,6 @@ const prepareLocalMediaTracks = async (startWithVideo) => {
const stream = await navigator.mediaDevices.getUserMedia(constraints)
prefs.audioTrack = stream.getAudioTracks()[0] || null
prefs.videoTrack = stream.getVideoTracks()[0] || null
pushDebug(`prepare 成功 audio=${!!prefs.audioTrack} video=${!!prefs.videoTrack}`)
// 如果用户拒了视频stream 里不会有 video track自动降级为不开摄像头
if (startWithVideo && !prefs.videoTrack) {
prefs.startVideo = false
@@ -415,7 +400,7 @@ const prepareLocalMediaTracks = async (startWithVideo) => {
prefs.startAudio = false
}
} catch (err) {
pushDebug(`prepare 失败: ${err?.name || ''} ${err?.message || err}`)
console.error('[CloudLawVideoCall] prepare media failed', err)
localMediaError.value = `预申请音视频失败:${err?.name || ''} ${err?.message || err}`
// 拿不到也继续走 joinAndEnter让后端协议建好用户可以在入会后手动点麦/摄像头按钮重试
prefs.startAudio = false
@@ -469,29 +454,20 @@ const acquireVideoTrack = async () => {
}
const onMicToggle = async () => {
pushDebug(`mic点击 loading=${audioLoading.value} on=${audioEnabled.value} producer=${meetingStore.localProducers?.audio || 'null'}`)
if (audioLoading.value || leaving.value) {
pushDebug('mic 被 loading/leaving 拦住')
return
}
if (audioLoading.value || leaving.value) return
audioLoading.value = true
try {
if (meetingStore.localProducers?.audio) {
// 已经有 producer只 mute/unmute不释放硬件关键:WebView 释放后申请会被拒)
pushDebug(`mic -> setLocalAudioMuted(${audioEnabled.value})`)
// 已经有 producer只 mute/unmute不释放硬件WebView 释放后申请会被拒)
await meetingStore.setLocalAudioMuted(audioEnabled.value)
pushDebug(`mic mute 切换完成 enabled=${meetingStore.localAudioEnabled}`)
} else {
// 没 producer兜底走完整流程自己 getUserMedia 拿 track用户手势作用域内
pushDebug('mic -> getUserMedia(audio)')
// 没 producer兜底走完整流程在用户手势作用域内 getUserMedia
const track = await acquireAudioTrack()
pushDebug(`mic 拿到 track id=${track?.id?.slice(0, 8)} label=${track?.label || ''}`)
await meetingStore.startLocalAudio(undefined, track)
pushDebug(`mic start 完成 enabled=${meetingStore.localAudioEnabled}`)
}
localMediaError.value = ''
} catch (err) {
pushDebug(`mic 报错: ${err?.name || ''} ${err?.message || err}`)
console.error('[CloudLawVideoCall] mic toggle failed', err)
localMediaError.value = `麦克风:${err?.message || err}`
} finally {
audioLoading.value = false
@@ -499,27 +475,18 @@ const onMicToggle = async () => {
}
const onCamToggle = async () => {
pushDebug(`cam点击 loading=${videoLoading.value} on=${videoEnabled.value} producer=${meetingStore.localProducers?.video || 'null'}`)
if (videoLoading.value || leaving.value) {
pushDebug('cam 被 loading/leaving 拦住')
return
}
if (videoLoading.value || leaving.value) return
videoLoading.value = true
try {
if (meetingStore.localProducers?.video) {
pushDebug(`cam -> setLocalVideoMuted(${videoEnabled.value})`)
await meetingStore.setLocalVideoMuted(videoEnabled.value)
pushDebug(`cam mute 切换完成 enabled=${meetingStore.localVideoEnabled}`)
} else {
pushDebug('cam -> getUserMedia(video)')
const track = await acquireVideoTrack()
pushDebug(`cam 拿到 track id=${track?.id?.slice(0, 8)} label=${track?.label || ''}`)
await meetingStore.startLocalVideo(undefined, track)
pushDebug(`cam start 完成 enabled=${meetingStore.localVideoEnabled}`)
}
localMediaError.value = ''
} catch (err) {
pushDebug(`cam 报错: ${err?.name || ''} ${err?.message || err}`)
console.error('[CloudLawVideoCall] cam toggle failed', err)
localMediaError.value = `摄像头:${err?.message || err}`
} finally {
videoLoading.value = false
@@ -910,24 +877,4 @@ onUnload(() => {
.clean-video-tile :deep(.tag-host) {
display: none;
}
/* 屏幕调试浮层 */
.debug-panel {
position: absolute;
left: 12rpx;
right: 12rpx;
bottom: calc(560rpx + env(safe-area-inset-bottom));
z-index: 99;
max-height: 360rpx;
overflow: auto;
background: rgba(0, 0, 0, 0.72);
color: #b6f8ff;
font-size: 22rpx;
line-height: 1.45;
padding: 12rpx 16rpx;
border-radius: 12rpx;
pointer-events: none;
}
.debug-line {
word-break: break-all;
}
</style>