diff --git a/WebApp/client/public/onebyone/index.html b/WebApp/client/public/onebyone/index.html
index d1f34ef..d63811f 100644
--- a/WebApp/client/public/onebyone/index.html
+++ b/WebApp/client/public/onebyone/index.html
@@ -288,12 +288,16 @@
-
-
diff --git a/WebApp/client/public/onebyone/renderer.js b/WebApp/client/public/onebyone/renderer.js
index 7a8e7c5..9c14a59 100644
--- a/WebApp/client/public/onebyone/renderer.js
+++ b/WebApp/client/public/onebyone/renderer.js
@@ -143,6 +143,9 @@ class UIRenderer {
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;
@@ -374,6 +377,30 @@ class UIRenderer {
if (localName) {
localName.textContent = localUser.name;
}
+ // 渲染本地用户媒体状态
+ const localMediaStatus = localUserElement.querySelector('[data-field="localUser.mediaStatus"]');
+ if (localMediaStatus) {
+ if (!localUser.mediaState.audio) {
+ localMediaStatus.textContent = '静音中';
+ localMediaStatus.className = 'text-xs text-gray-500';
+ } else if (!localUser.mediaState.video) {
+ localMediaStatus.textContent = '视频关闭';
+ localMediaStatus.className = 'text-xs text-gray-500';
+ } else {
+ localMediaStatus.textContent = '在线';
+ localMediaStatus.className = 'text-xs text-green-400';
+ }
+ }
+ // 渲染本地用户静音图标
+ const localMuteIcon = localUserElement.querySelector('[data-field="localUser.muteIcon"]');
+ if (localMuteIcon) {
+ if (!localUser.mediaState.audio) {
+ localMuteIcon.classList.remove('hidden');
+ localMuteIcon.className = 'fas fa-microphone-slash text-gray-500 text-xs';
+ } else {
+ localMuteIcon.classList.add('hidden');
+ }
+ }
}
// 渲染远程用户
@@ -389,6 +416,49 @@ class UIRenderer {
if (remoteName) {
remoteName.textContent = remoteUser.name;
}
+ // 渲染远程用户媒体状态
+ const remoteMediaStatus = remoteUserElement.querySelector('[data-field="remoteUser.mediaStatus"]');
+ if (remoteMediaStatus) {
+ if (!remoteUser.mediaState.audio) {
+ remoteMediaStatus.textContent = '静音中';
+ remoteMediaStatus.className = 'text-xs text-gray-500';
+ } else if (!remoteUser.mediaState.video) {
+ remoteMediaStatus.textContent = '视频关闭';
+ remoteMediaStatus.className = 'text-xs text-gray-500';
+ } else {
+ remoteMediaStatus.textContent = '在线';
+ remoteMediaStatus.className = 'text-xs text-green-400';
+ }
+ }
+ // 渲染远程用户在线状态指示器
+ const remoteStatusIndicator = remoteUserElement.querySelector('.absolute.-bottom-1.-right-1.w-3.h-3');
+ if (remoteStatusIndicator) {
+ if (remoteUser.status === 'online') {
+ remoteStatusIndicator.classList.remove('hidden');
+ remoteStatusIndicator.className = 'absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-slate-900';
+ } else {
+ remoteStatusIndicator.classList.add('hidden');
+ }
+ }
+ // 渲染远程用户静音图标
+ const remoteMuteIcon = remoteUserElement.querySelector('[data-field="remoteUser.muteIcon"]');
+ if (remoteMuteIcon) {
+ if (!remoteUser.mediaState.audio) {
+ remoteMuteIcon.classList.remove('hidden');
+ remoteMuteIcon.className = 'fas fa-microphone-slash text-gray-500 text-xs';
+ } else {
+ remoteMuteIcon.classList.add('hidden');
+ }
+ }
+ // 渲染远程用户说话状态指示器
+ const remoteSpeakingIndicator = remoteUserElement.querySelector('[data-field="remoteUser.speakingIndicator"]');
+ if (remoteSpeakingIndicator) {
+ if (remoteUser.mediaState.isSpeaking && remoteUser.mediaState.audio) {
+ remoteSpeakingIndicator.classList.remove('hidden');
+ } else {
+ remoteSpeakingIndicator.classList.add('hidden');
+ }
+ }
}
}
// 在renderer.js中添加方法
diff --git a/WebApp/client/public/onebyone/store.js b/WebApp/client/public/onebyone/store.js
index d161382..7d4b17f 100644
--- a/WebApp/client/public/onebyone/store.js
+++ b/WebApp/client/public/onebyone/store.js
@@ -233,23 +233,31 @@ class CallStateManager {
// 如果是关闭视频,释放摄像头资源
if (mediaType === 'video' && !value && this.state.localStream) {
+ this.state.session.localUser.mediaState.video = false;
this.state.localStream.getTracks().forEach(track => {
if (track.kind === 'video') {
track.stop();
}
});
+ // 发送媒体状态到服务器
+ this.emitMediaStateChange();
}
// 如果是音频状态变化,控制本地音频轨道
if (mediaType === 'audio' && this.state.localStream) {
+ this.state.session.localUser.mediaState.audio = value;
this.state.localStream.getTracks().forEach(track => {
if (track.kind === 'audio') {
track.enabled = value;
}
});
+ // 发送媒体状态到服务器
+ this.emitMediaStateChange();
}
+ // 通知UI更新用户列表
+ this.notify({ type: 'USER_LIST_UPDATE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser });
}
@@ -362,12 +370,17 @@ class CallStateManager {
};
// 初始化 RenderStreaming 实例后
this.renderstreaming.onMessage = (data) => {
- console.log('收到聊天:', data);
+ console.log('收到消息:', data);
if (data.type === 'chat-message') {
// 处理聊天
// 添加到列表并更新UI
chatMessage.handleChatMessage(data.message);
+ } else if (data.type === 'media-state-changed') {
+ // 处理媒体状态变化
+ console.log('收到媒体状态变化:', data.data);
+ // 更新远程用户的媒体状态
+ this.updateRemoteMedia(data.data);
} else if (data.type === 'on-message') {
}
@@ -450,23 +463,9 @@ class CallStateManager {
...mediaState
};
this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState });
+ // 通知UI更新用户列表
+ this.notify({ type: 'USER_LIST_UPDATE', localUser: this.state.session.localUser, remoteUser: this.state.session.remoteUser });
}
-
- // 添加消息
- addMessage(message) {
- chatMessage.addMessage(message);
- }
-
- // 发送聊天消息
- sendChatMessage(message) {
- chatMessage.sendChatMessage(message, this.renderstreaming);
- }
-
- // 切换侧边栏
- toggleSidebar() {
- chatMessage.toggleSidebar();
- }
-
// 结束通话
endCall() {
clearInterval(this.durationInterval);
@@ -801,7 +800,13 @@ class CallStateManager {
...this.state.session.localUser.mediaState
};
console.log('[WebSocket Emit] media-state-changed:', payload);
- // socket.emit('media-state-changed', payload);
+ // 使用WebRTC发送媒体状态变化
+ if (this.renderstreaming) {
+ this.renderstreaming.sendMessage({
+ type: 'media-state-changed',
+ data: payload
+ });
+ }
}
// 显示统计信息