diff --git a/WebApp/client/public/onebyone/main.js b/WebApp/client/public/onebyone/main.js index 8638119..04ff676 100644 --- a/WebApp/client/public/onebyone/main.js +++ b/WebApp/client/public/onebyone/main.js @@ -157,7 +157,7 @@ window.addEventListener('DOMContentLoaded', async () => { //await store.init(); // 初始化渲染器 - new UIRenderer(store); + const renderer = new UIRenderer(store); // 加入通话 await store.joinCall(connectionId); @@ -165,6 +165,8 @@ window.addEventListener('DOMContentLoaded', async () => { // 设置WebRTC连接 await store.setUp(connectionId); + renderer.renderHeaderTitle(); + // 绑定DOM事件 bindDomEvents(); diff --git a/WebApp/client/public/onebyone/renderer.js b/WebApp/client/public/onebyone/renderer.js index 701e1b0..5fc8f49 100644 --- a/WebApp/client/public/onebyone/renderer.js +++ b/WebApp/client/public/onebyone/renderer.js @@ -5,6 +5,7 @@ import { formatTime, formatTimestamp, toggleElement, toggleButtonState } from './utils.js'; import { mockCallSession } from './models.js'; import chatMessage from './chatmessage.js'; +import store from './store.js'; class UIRenderer { constructor(stateManager) { this.stateManager = stateManager; @@ -103,60 +104,74 @@ class UIRenderer { } - // 渲染状态变化 + /** + * 渲染方法 - 根据状态变化更新UI + * @param {Object} state - 当前应用状态 + * @param {Object} changes - 状态变化对象 + */ render(state, changes) { + // 根据变化类型执行不同的渲染操作 switch (changes.type) { case 'INIT': - this.renderHeader(state.session); - this.renderRemoteVideo(state.session.remoteUser); - this.renderLocalVideo(state.session.localUser, state.localStream); - this.renderControlButtons(state.session.localUser.mediaState); - this.renderChatMessages(chatMessage.getMessageState().messages); - this.renderUserList(state.session.localUser, state.session.remoteUser); - + // 初始化渲染 - 渲染所有UI元素 + this.renderRemoteVideo(state.session.remoteUser); // 渲染远程视频 + this.renderLocalVideo(state.session.localUser, state.localStream); // 渲染本地视频 + this.renderControlButtons(state.session.localUser.mediaState); // 渲染控制按钮 + this.renderChatMessages(chatMessage.getMessageState().messages); // 渲染聊天消息 + this.renderUserList(state.session.localUser, state.session.remoteUser); // 渲染用户列表 + this.renderHeader(state.session); // 渲染头部信息 // 初始化时检查远程流状态,显示或隐藏占位背景 if (this.elements.remoteVideoPlaceholder) { if (state.remoteStream) { - this.elements.remoteVideoPlaceholder.classList.add('hidden'); + this.elements.remoteVideoPlaceholder.classList.add('hidden'); // 有远程流时隐藏占位背景 } else { - this.elements.remoteVideoPlaceholder.classList.remove('hidden'); + this.elements.remoteVideoPlaceholder.classList.remove('hidden'); // 无远程流时显示占位背景 } } break; case 'DURATION_UPDATE': + // 通话时长更新 - 渲染通话时长 this.renderCallDuration(changes.duration); break; case 'LOCAL_MEDIA_CHANGE': - this.renderControlButtons(state.session.localUser.mediaState); - this.renderLocalVideo(state.session.localUser, state.localStream); - this.renderLocalUserStatus(state.session.localUser); - this.renderUserList(state.session.localUser, state.session.remoteUser); + // 本地媒体状态变化 - 更新相关UI + this.renderControlButtons(state.session.localUser.mediaState); // 渲染控制按钮 + this.renderLocalVideo(state.session.localUser, state.localStream); // 渲染本地视频 + this.renderLocalUserStatus(state.session.localUser); // 渲染本地用户状态 + this.renderUserList(state.session.localUser, state.session.remoteUser); // 渲染用户列表 break; case 'LOCAL_STREAM_OBTAINED': - this.renderLocalStream(state.localStream); - this.renderLocalVideo(state.session.localUser, state.localStream); + // 本地流获取成功 - 更新本地视频显示 + this.renderLocalStream(state.localStream); // 渲染本地流 + this.renderLocalVideo(state.session.localUser, state.localStream); // 渲染本地视频 break; case 'REMOTE_STREAM_OBTAINED': - this.renderRemoteStream(state.remoteStream); + // 远程流获取成功 - 更新远程视频显示 + this.renderRemoteStream(state.remoteStream); // 渲染远程流 // 当获取到远程流时,隐藏连接中提示 if (this.elements.connectingOverlay) { this.elements.connectingOverlay.classList.add('hidden'); } break; case 'REMOTE_MEDIA_CHANGE': - this.renderRemoteVideo(state.session.remoteUser); - this.renderUserList(state.session.localUser, state.session.remoteUser); + // 远程媒体状态变化 - 更新远程视频和用户列表 + this.renderRemoteVideo(state.session.remoteUser); // 渲染远程视频 + this.renderUserList(state.session.localUser, state.session.remoteUser); // 渲染用户列表 break; case 'USER_LIST_UPDATE': + // 用户列表更新 - 重新渲染用户列表 this.renderUserList(changes.localUser, changes.remoteUser); break; case 'NETWORK_CHANGE': + // 网络状态变化 - 渲染网络状态 this.renderNetworkStatus(changes.quality); break; case 'CALL_STATUS_CHANGE': + // 通话状态变化 - 渲染通话状态 this.renderCallStatus(changes.status); break; case 'CALL_ENDED': + // 通话结束 - 渲染通话结束界面 this.renderCallEnded(); break; } @@ -175,15 +190,8 @@ class UIRenderer { // 渲染头部 renderHeader(session) { - if (this.elements.headerTitle) { - // 未连接时不显示红框部分 - if (session.status === 'idle' || session.status === 'connecting') { - this.elements.headerTitle.textContent = '通话'; - } else { - this.elements.headerTitle.textContent = `与 ${session.remoteUser.name} 的通话`; - } - } + this.renderHeaderTitle(); if (this.elements.encryptionBadge) { toggleElement(this.elements.encryptionBadge, session.isEncrypted); } @@ -198,6 +206,14 @@ class UIRenderer { this.renderCallDuration(session.duration); } + renderHeaderTitle() { + if (this.elements.headerTitle) { + const connectionId = store.getConnectionId() || ''; + // 未连接时不显示红框部分 + this.elements.headerTitle.textContent = `通话 (${connectionId})`; + + } + } // 渲染通话时长 renderCallDuration(duration) { diff --git a/WebApp/client/public/onebyone/store.js b/WebApp/client/public/onebyone/store.js index e32b856..c7f469b 100644 --- a/WebApp/client/public/onebyone/store.js +++ b/WebApp/client/public/onebyone/store.js @@ -182,6 +182,34 @@ class CallStateManager { const audioTracks = this.state.localStream.getAudioTracks(); console.log('New audio tracks:', audioTracks); + + // 更新音频轨道 + if (audioTracks.length > 0) { + const newAudioTrack = audioTracks[0]; + console.log('Using new audio track:', newAudioTrack); + + if (audioTransceivers.length > 0) { + // 替换现有的音频轨道 + for (const transceiver of audioTransceivers) { + try { + console.log('Replacing audio track in transceiver:', transceiver); + await transceiver.sender.replaceTrack(newAudioTrack); + console.log('Successfully replaced audio track'); + } catch (error) { + console.error('Error replacing audio track:', error); + } + } + } else { + // 添加新的音频收发器 + try { + console.log('Adding new audio transceiver'); + const transceiver = this.renderstreaming.addTransceiver(newAudioTrack, { direction: 'sendonly' }); + console.log('Added new audio transceiver:', transceiver); + } catch (error) { + console.error('Error adding new audio transceiver:', error); + } + } + } // 更新视频轨道 if (videoTracks.length > 0) { const newVideoTrack = videoTracks[0]; @@ -210,33 +238,7 @@ class CallStateManager { } } - // 更新音频轨道 - if (audioTracks.length > 0) { - const newAudioTrack = audioTracks[0]; - console.log('Using new audio track:', newAudioTrack); - if (audioTransceivers.length > 0) { - // 替换现有的音频轨道 - for (const transceiver of audioTransceivers) { - try { - console.log('Replacing audio track in transceiver:', transceiver); - await transceiver.sender.replaceTrack(newAudioTrack); - console.log('Successfully replaced audio track'); - } catch (error) { - console.error('Error replacing audio track:', error); - } - } - } else { - // 添加新的音频收发器 - try { - console.log('Adding new audio transceiver'); - const transceiver = this.renderstreaming.addTransceiver(newAudioTrack, { direction: 'sendonly' }); - console.log('Added new audio transceiver:', transceiver); - } catch (error) { - console.error('Error adding new audio transceiver:', error); - } - } - } // 延迟设置编解码器偏好,确保收发器已完全创建 setTimeout(() => { @@ -294,6 +296,7 @@ class CallStateManager { // 设置状态为连接中 this.state.session.status = 'connecting'; this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' }); + // 确保本地流已经初始化 if (!this.state.localStream) { console.log('Local stream not available, waiting for initialization...');