diff --git a/WebApp/client/public/onebyone/index.html b/WebApp/client/public/onebyone/index.html
index 1d7007a..8e1549e 100644
--- a/WebApp/client/public/onebyone/index.html
+++ b/WebApp/client/public/onebyone/index.html
@@ -201,11 +201,14 @@
-

+
diff --git a/WebApp/client/public/onebyone/renderer.js b/WebApp/client/public/onebyone/renderer.js
index d9fd47c..2b3820d 100644
--- a/WebApp/client/public/onebyone/renderer.js
+++ b/WebApp/client/public/onebyone/renderer.js
@@ -70,6 +70,9 @@ class UIRenderer {
this.renderLocalVideo(state.session.localUser);
this.renderLocalUserStatus(state.session.localUser);
break;
+ case 'LOCAL_STREAM_OBTAINED':
+ this.renderLocalStream(state.localStream);
+ break;
case 'REMOTE_MEDIA_CHANGE':
this.renderRemoteVideo(state.session.remoteUser);
break;
@@ -150,6 +153,18 @@ class UIRenderer {
this.renderLocalUserStatus(localUser);
}
+ // 渲染本地视频流
+ renderLocalStream(stream) {
+ if (this.elements.localVideo && stream) {
+ this.elements.localVideo.srcObject = stream;
+ this.elements.localVideo.autoplay = true;
+ this.elements.localVideo.muted = true; // 本地视频静音,避免回声
+ console.log('srcObject set successfully:', this.elements.localVideo.srcObject);
+ } else {
+ console.error('Either localVideo element or stream is missing');
+ }
+ }
+
// 渲染本地用户状态
renderLocalUserStatus(localUser) {
// 更新本地媒体状态文本
diff --git a/WebApp/client/public/onebyone/store.js b/WebApp/client/public/onebyone/store.js
index 6203827..8f71c18 100644
--- a/WebApp/client/public/onebyone/store.js
+++ b/WebApp/client/public/onebyone/store.js
@@ -44,6 +44,9 @@ class CallStateManager {
this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration });
}, 1000);
+ // 获取本地摄像头视频流
+ this.getLocalStream();
+
// 模拟远端音频活动 (实际应由 WebRTC VAD 检测触发)
this.simulateRemoteActivity();
@@ -51,13 +54,95 @@ class CallStateManager {
this.simulateNetworkChange();
}
- // 更新本地媒体状态
- updateLocalMedia(mediaType, value) {
- this.state.session.localUser.mediaState[mediaType] = value;
- this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType, value });
+ // 获取本地摄像头视频流
+ async getLocalStream() {
+ try {
+ console.log('Requesting camera permission...');
- // 发送媒体状态到服务器
- this.emitMediaStateChange();
+ // 检查浏览器是否支持getUserMedia
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
+ console.error('getUserMedia is not supported');
+ throw new Error('getUserMedia is not supported');
+ }
+
+ // 请求摄像头权限并获取媒体流
+ const stream = await navigator.mediaDevices.getUserMedia({
+ video: true,
+ audio: true
+ });
+
+ console.log('Stream obtained successfully:', stream);
+ console.log('Video tracks:', stream.getVideoTracks());
+ console.log('Audio tracks:', stream.getAudioTracks());
+
+ this.state.localStream = stream;
+ this.state.session.localUser.mediaState.video = true;
+ this.state.session.localUser.mediaState.audio = true;
+
+ console.log('Local stream stored, notifying UI...');
+
+ // 先通知视频流已获取
+ this.notify({ type: 'LOCAL_STREAM_OBTAINED', stream });
+ // 再通知媒体状态变化
+ this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: true });
+ this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: true });
+
+ // 发送媒体状态到服务器
+ this.emitMediaStateChange();
+ } catch (error) {
+ console.error('Error getting local stream:', error);
+ // 如果获取视频失败,保持视频关闭状态
+ this.state.session.localUser.mediaState.video = false;
+ this.state.session.localUser.mediaState.audio = false;
+
+ // 通知媒体状态变化
+ this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: false });
+ this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: false });
+ }
+ }
+
+ // 更新本地媒体状态
+ async updateLocalMedia(mediaType, value) {
+ // 如果是关闭视频,释放摄像头资源
+ if (mediaType === 'video' && !value && this.state.localStream) {
+ this.state.localStream.getTracks().forEach(track => {
+ if (track.kind === 'video') {
+ track.stop();
+ }
+ });
+
+ }
+
+ // 如果是音频状态变化,控制本地音频轨道
+ if (mediaType === 'audio' && this.state.localStream) {
+ this.state.localStream.getTracks().forEach(track => {
+ if (track.kind === 'audio') {
+ track.enabled = value;
+ }
+ });
+ }
+
+ // 如果是开启视频,重新获取摄像头资源
+ if (mediaType === 'video' && value ) {
+ if(this.state.localStream){
+ 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();
+ } else {
+ // 直接更新媒体状态
+ this.state.session.localUser.mediaState[mediaType] = value;
+ this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType, value });
+
+ // 发送媒体状态到服务器
+ this.emitMediaStateChange();
+ }
}
// 更新远端媒体状态 (由 WebSocket 消息触发)