From bcf3520111684fef71d6644091071630410317a0 Mon Sep 17 00:00:00 2001 From: zhangzheng Date: Fri, 6 Mar 2026 15:15:01 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90m=E3=80=91=E7=A6=81=E7=94=A8=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E5=8A=9F=E8=83=BD=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebApp/client/public/onebyone/renderer.js | 91 ++++++++++++++++------- WebApp/client/public/onebyone/store.js | 71 +++++++++++++++++- 2 files changed, 135 insertions(+), 27 deletions(-) diff --git a/WebApp/client/public/onebyone/renderer.js b/WebApp/client/public/onebyone/renderer.js index 189d52a..f7a5fa1 100644 --- a/WebApp/client/public/onebyone/renderer.js +++ b/WebApp/client/public/onebyone/renderer.js @@ -234,39 +234,80 @@ class UIRenderer { // 渲染远程视频流 renderRemoteStream(stream) { if (this.elements.remoteVideo && stream) { - this.elements.remoteVideo.srcObject = stream; - this.elements.remoteVideo.autoplay = true; + console.log('Rendering remote stream:', stream); - // 关键设置:启用硬件加速和最佳质量渲染 - this.elements.remoteVideo.style.transform = 'translateZ(0)'; // 启用硬件加速 - this.elements.remoteVideo.style.imageRendering = 'pixelated'; // 保持像素清晰 - this.elements.remoteVideo.style.objectFit = 'contain'; // 保持比例 - console.log('Remote stream set successfully:', this.elements.remoteVideo.srcObject); + // 即使流对象相同,也要重新设置,确保视频元素能够识别轨道变化 + this.elements.remoteVideo.srcObject = null; - // 隐藏断开连接覆盖层 - if (this.elements.disconnectedOverlay) { - this.elements.disconnectedOverlay.classList.add('hidden'); - } + // 延迟设置srcObject,确保视频元素能够正确处理 + setTimeout(() => { + this.elements.remoteVideo.srcObject = stream; + console.log('Remote stream reset successfully:', stream); - // 隐藏占位背景 - if (this.elements.remoteVideoPlaceholder) { - this.elements.remoteVideoPlaceholder.classList.add('hidden'); - } - // 获取视频轨道并处理分辨率 - const videoTracks = stream.getVideoTracks(); - if (videoTracks.length > 0) { - const resolution = this.getVideoResolution(videoTracks[0]); - this.adjustVideoSize(this.elements.remoteVideo, resolution); + // 确保视频元素的属性正确设置 + this.elements.remoteVideo.autoplay = true; + this.elements.remoteVideo.playsinline = true; + this.elements.remoteVideo.muted = true; - // 监听轨道变化,处理分辨率调整 - videoTracks[0].addEventListener('resize', () => { - const newResolution = this.getVideoResolution(videoTracks[0]); - this.adjustVideoSize(this.elements.remoteVideo, newResolution); + // 关键设置:启用硬件加速和最佳质量渲染 + this.elements.remoteVideo.style.transform = 'translateZ(0)'; // 启用硬件加速 + this.elements.remoteVideo.style.imageRendering = 'pixelated'; // 保持像素清晰 + this.elements.remoteVideo.style.objectFit = 'contain'; // 保持比例 + + // 隐藏断开连接覆盖层 + if (this.elements.disconnectedOverlay) { + this.elements.disconnectedOverlay.classList.add('hidden'); + } + + // 隐藏占位背景 + if (this.elements.remoteVideoPlaceholder) { + this.elements.remoteVideoPlaceholder.classList.add('hidden'); + } + + // 获取视频轨道并处理分辨率 + const videoTracks = stream.getVideoTracks(); + console.log('Remote video tracks:', videoTracks); + + // 检查是否有有效的视频轨道 + const hasValidVideoTrack = videoTracks.length > 0 && videoTracks.some(track => { + // 检查轨道是否已停止或被禁用 + return track.readyState === 'live'; }); - } + + console.log('Has valid video track:', hasValidVideoTrack); + + if (hasValidVideoTrack) { + console.log('Found valid video tracks, updating resolution'); + const activeVideoTrack = videoTracks.find(track => track.readyState === 'live'); + if (activeVideoTrack) { + const resolution = this.getVideoResolution(activeVideoTrack); + this.adjustVideoSize(this.elements.remoteVideo, resolution); + + // 监听轨道变化,处理分辨率调整 + activeVideoTrack.addEventListener('resize', () => { + const newResolution = this.getVideoResolution(activeVideoTrack); + this.adjustVideoSize(this.elements.remoteVideo, newResolution); + }); + } + } else { + console.log('No valid video tracks in remote stream'); + // 清空视频元素的源 + this.elements.remoteVideo.srcObject = null; + + // 显示占位背景 + if (this.elements.remoteVideoPlaceholder) { + this.elements.remoteVideoPlaceholder.classList.remove('hidden'); + } + } + }, 50); // 增加延迟时间,确保视频元素有足够的时间处理 } else { console.error('Either remoteVideo element or stream is missing'); + // 清空视频元素的源 + if (this.elements.remoteVideo) { + this.elements.remoteVideo.srcObject = null; + } + // 显示占位背景 if (this.elements.remoteVideoPlaceholder) { this.elements.remoteVideoPlaceholder.classList.remove('hidden'); diff --git a/WebApp/client/public/onebyone/store.js b/WebApp/client/public/onebyone/store.js index 131585e..a98b705 100644 --- a/WebApp/client/public/onebyone/store.js +++ b/WebApp/client/public/onebyone/store.js @@ -120,16 +120,69 @@ class CallStateManager { // 如果是开启视频,重新获取摄像头资源 if (mediaType === 'video' && value) { if (this.state.localStream) { + // 停止当前的媒体流 + if (this.state.localStream) { + this.state.localStream.getTracks().forEach(track => track.stop()); + } this.state.localStream = null; } - //if(this.state.localStream.getVideoTracks().length==0){ // 请求摄像头权限并获取媒体流 this.state.localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); - // } await this.getLocalStream(); + + // 更新WebRTC连接中的视频轨道 + if (this.renderstreaming) { + console.log('Updating video track in WebRTC connection'); + + // 获取所有收发器 + const transceivers = this.renderstreaming.getTransceivers(); + console.log('All transceivers:', transceivers); + + // 查找现有的视频收发器 + const videoTransceivers = transceivers.filter(t => { + return t.sender && t.sender.track && t.sender.track.kind === 'video'; + }); + console.log('Found video transceivers:', videoTransceivers); + + // 获取新的视频轨道 + const videoTracks = this.state.localStream.getVideoTracks(); + console.log('New video tracks:', videoTracks); + + if (videoTracks.length > 0) { + const newVideoTrack = videoTracks[0]; + console.log('Using new video track:', newVideoTrack); + + if (videoTransceivers.length > 0) { + // 替换现有的视频轨道 + for (const transceiver of videoTransceivers) { + try { + console.log('Replacing video track in transceiver:', transceiver); + await transceiver.sender.replaceTrack(newVideoTrack); + console.log('Successfully replaced video track'); + } catch (error) { + console.error('Error replacing video track:', error); + } + } + } else { + // 添加新的视频收发器 + try { + console.log('Adding new video transceiver'); + const transceiver = this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }); + console.log('Added new video transceiver:', transceiver); + } catch (error) { + console.error('Error adding new video transceiver:', error); + } + } + + // 延迟设置编解码器偏好,确保收发器已完全创建 + setTimeout(() => { + this.setCodecPreferences(); + }, 100); + } + } } else { // 直接更新媒体状态 this.state.session.localUser.mediaState[mediaType] = value; @@ -231,9 +284,23 @@ class CallStateManager { if (this.state.remoteStream == null) { this.state.remoteStream = new MediaStream(); } + + // 检查是否已经有相同类型的轨道 + const existingTracks = this.state.remoteStream.getTracks().filter(track => track.kind === data.track.kind); + + // 移除旧的轨道 + existingTracks.forEach(track => { + this.state.remoteStream.removeTrack(track); + console.log('Removed old track:', track.kind); + }); + + // 添加新的轨道 this.state.remoteStream.addTrack(data.track); + console.log('Added new track:', data.track.kind); + // 通知UI远程流已更新 this.notify({ type: 'REMOTE_STREAM_OBTAINED', stream: this.state.remoteStream }); + console.log('Notified UI about remote stream update'); // 如果是音频轨道,启动远程音频活动检测 if (data.track.kind === 'audio') {