修改优化按钮等待时机
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3m57s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3m57s
				
			This commit is contained in:
		
							parent
							
								
									3edca0d5a7
								
							
						
					
					
						commit
						15374be668
					
				| @ -451,7 +451,7 @@ | ||||
|                     <div class="avatar-container" id="avatarContainer"> | ||||
|                         <div class="avatar" id="avatar"> | ||||
|                             <!-- 使用相对路径引用图片 --> | ||||
|                             <img src="./tx.png" alt="头像" onerror="this.style.display='none'; this.parentElement.innerHTML='AI';"> | ||||
|                             <img src="./tx.png" alt="头像" onerror="this.style.display='none'; this.parentElement.innerHTML='一和零';"> | ||||
|                         </div> | ||||
|                         <!-- <div class="avatar-name">AI助手</div> --> | ||||
|                     </div> | ||||
|  | ||||
							
								
								
									
										229
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								src/index.js
									
									
									
									
									
								
							| @ -9,8 +9,6 @@ class WebRTCChat { | ||||
|     constructor() { | ||||
|         console.log('WebRTCChat 构造函数开始执行'); | ||||
|          | ||||
| 
 | ||||
|          | ||||
|         // 初始化历史消息(异步)
 | ||||
|         this.initializeHistory(); | ||||
|          | ||||
| @ -30,6 +28,10 @@ class WebRTCChat { | ||||
|         this.precreatedStreams = new Map(); // 预创建的视频流
 | ||||
|         this.importantVideos = ['d-3s.mp4', 's-1.mp4']; // 重要视频列表
 | ||||
|         this.isInitialized = false; | ||||
|         // 添加视频加载状态标志
 | ||||
|         this.isVideoReady = false; | ||||
|         this.isDefaultVideoLoaded = false; | ||||
|         this.retryCount = 0; // 添加重试计数器
 | ||||
| 
 | ||||
|         // 添加视频相关属性
 | ||||
|         this.videoSender = null; // WebRTC视频发送器
 | ||||
| @ -63,20 +65,22 @@ class WebRTCChat { | ||||
| 
 | ||||
|         console.log('WebRTC 聊天应用初始化完成'); | ||||
|          | ||||
|         this.initializeElements(); | ||||
|         this.initializeSocket(); | ||||
|         this.initializeElements(); | ||||
|         this.loadVideoMapping(); | ||||
|         this.loadVideoList(); | ||||
|         this.loadDefaultVideo(); | ||||
|          | ||||
|         // 只预加载视频资源,不显示视频
 | ||||
|         this.preloadVideoResources(); | ||||
|         this.bindEvents(); | ||||
| 
 | ||||
|         // 在初始化完成后预加载常用视频
 | ||||
|         setTimeout(() => { | ||||
|             this.logMessage('开始预加载常用视频...', 'info'); | ||||
|             this.preloadCommonVideos().catch(error => { | ||||
|                 this.logMessage(`预加载过程出错: ${error.message}`, 'error'); | ||||
|             }); | ||||
|         }, 500); // 延迟2秒开始预加载,避免影响
 | ||||
|         // setTimeout(() => {
 | ||||
|         //     this.logMessage('开始预加载常用视频...', 'info');
 | ||||
|         //     this.preloadCommonVideos().catch(error => {
 | ||||
|         //         this.logMessage(`预加载过程出错: ${error.message}`, 'error');
 | ||||
|         //     });
 | ||||
|         // }, 500);
 | ||||
| 
 | ||||
|         // 预创建重要视频流
 | ||||
|         setTimeout(() => { | ||||
| @ -88,6 +92,30 @@ class WebRTCChat { | ||||
|         window.webrtcApp = this; | ||||
|     } | ||||
| 
 | ||||
|     // 新增方法:预加载视频资源
 | ||||
|     async preloadVideoResources() { | ||||
|         try { | ||||
|             await this.loadDefaultVideo(); | ||||
|             // 预创建视频流但不设置到video元素
 | ||||
|             const defaultStream = await this.createVideoStreamOptimized(this.defaultVideo); | ||||
|             this.precreatedStreams.set(this.defaultVideo, defaultStream); | ||||
|              | ||||
|             this.isVideoReady = true; | ||||
|             this.isDefaultVideoLoaded = true; | ||||
|              | ||||
|             // 启用开始通话按钮
 | ||||
|             // if (this.startButton) {
 | ||||
|             //     this.startButton.disabled = false;
 | ||||
|             //     this.startButton.style.opacity = '1';
 | ||||
|             // }
 | ||||
|              | ||||
|             console.log('视频资源预加载完成,可以开始通话', 'success'); | ||||
|         } catch (error) { | ||||
|             this.logMessage(`视频资源预加载失败: ${error.message}`, 'error'); | ||||
|             this.isVideoReady = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     initializeElements() { | ||||
|         // 视频元素
 | ||||
|         this.localVideo = document.getElementById('localVideo'); | ||||
| @ -111,6 +139,14 @@ class WebRTCChat { | ||||
|         this.stopButton = document.getElementById('stopButton'); | ||||
|         this.muteButton = document.getElementById('muteButton'); | ||||
|         this.sendTextButton = document.getElementById('sendTextButton'); | ||||
|          | ||||
|         // 初始状态下禁用开始通话按钮,直到视频加载完成
 | ||||
|         if (this.startButton) { | ||||
|             this.startButton.disabled = true; | ||||
|             this.startButton.style.opacity = '0.5'; | ||||
|             // this.startButton.title = '加载中,请稍候...';
 | ||||
|         } | ||||
|          | ||||
|         // this.startVoiceButton = document.getElementById('startVoiceButton');
 | ||||
|         // this.stopVoiceButton = document.getElementById('stopVoiceButton');
 | ||||
|         // this.defaultVideoButton = document.getElementById('defaultVideoButton');
 | ||||
| @ -165,7 +201,7 @@ class WebRTCChat { | ||||
|         // 通话开始处理
 | ||||
|         this.socket.on('call-started', (data) => { | ||||
|             console.log('通话已开始', 'success'); | ||||
|             this.startDefaultVideoStream(); | ||||
|             // 移除这里的视频流启动,因为现在在startCall中处理
 | ||||
|         }); | ||||
| 
 | ||||
|         // 场景切换处理
 | ||||
| @ -204,7 +240,7 @@ class WebRTCChat { | ||||
|             this.videoMapping = data.mapping; | ||||
|             this.interactionVideo = data.mapping['8-4-sh']; | ||||
|             this.defaultVideo = data.mapping["default"]; | ||||
|             this.logMessage('视频映射加载成功', 'success'); | ||||
|             console.log('映射加载成功', 'success'); | ||||
|         } catch (error) { | ||||
|             this.logMessage('加载视频映射失败: ' + error.message, 'error'); | ||||
|         } | ||||
| @ -264,18 +300,35 @@ class WebRTCChat { | ||||
| 
 | ||||
|     async startDefaultVideoStream() { | ||||
|         try { | ||||
|             this.logMessage('开始创建默认视频流', 'info'); | ||||
|             console.log('开始创建默认视频流', 'info'); | ||||
|              | ||||
|             // 显示视频元素
 | ||||
|             if (this.recordedVideo) { | ||||
|                 this.recordedVideo.style.display = 'block'; | ||||
|             } | ||||
|              | ||||
|             // 添加加载状态
 | ||||
|             this.recordedVideo.classList.add('loading'); | ||||
|              | ||||
|             // 创建默认视频的MediaStream
 | ||||
|             const defaultStream = this.precreatedStreams.get(this.defaultVideo); | ||||
|             let defaultStream = this.precreatedStreams.get(this.defaultVideo); | ||||
|              | ||||
|             // 检查流是否有效,如果无效则重新创建
 | ||||
|             if (!defaultStream || defaultStream.getTracks().length === 0 ||  | ||||
|                 defaultStream.getTracks().some(track => track.readyState === 'ended')) { | ||||
|                 console.log('预创建流无效,重新创建默认视频流'); | ||||
|                 try { | ||||
|                     defaultStream = await this.createVideoStreamOptimized(this.defaultVideo); | ||||
|                     this.precreatedStreams.set(this.defaultVideo, defaultStream); | ||||
|                 } catch (createError) { | ||||
|                     throw new Error(`重新创建默认视频流失败: ${createError.message}`); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             // 等待流稳定
 | ||||
|             await new Promise(resolve => setTimeout(resolve, 1000)); | ||||
|              | ||||
|             // 检查流是否有效
 | ||||
|             // 再次检查流是否有效
 | ||||
|             if (!defaultStream || defaultStream.getTracks().length === 0) { | ||||
|                 throw new Error('默认视频流创建失败'); | ||||
|             } | ||||
| @ -311,20 +364,39 @@ class WebRTCChat { | ||||
|             // 确保视频开始播放
 | ||||
|             try { | ||||
|                 await this.recordedVideo.play(); | ||||
|                 this.logMessage('默认视频开始播放', 'success'); | ||||
|                 // this.logMessage('默认视频开始播放', 'success');
 | ||||
|                  | ||||
|                 // 移除加载状态,添加播放状态
 | ||||
|                 this.recordedVideo.classList.remove('loading'); | ||||
|                 this.recordedVideo.classList.add('playing'); | ||||
|             } catch (playError) { | ||||
|                 this.logMessage(`默认视频播放失败: ${playError.message}`, 'error'); | ||||
|                 // this.logMessage(`默认视频播放失败: ${playError.message}`, 'error');
 | ||||
|                 this.recordedVideo.classList.remove('loading'); | ||||
|             } | ||||
| 
 | ||||
|             this.logMessage('默认视频流创建成功', 'success'); | ||||
|             // 再次检查视频是否准备就绪
 | ||||
|             // this.startButton.disabled = false;
 | ||||
|              | ||||
|             console.log('默认流创建成功', 'success'); | ||||
|         } catch (error) { | ||||
|             this.logMessage('创建默认视频流失败: ' + error.message, 'error'); | ||||
|             console.log('创建默认视频流失败: ' + error.message, 'error'); | ||||
| 
 | ||||
|             // 隐藏视频元素
 | ||||
|             if (this.recordedVideo) { | ||||
|                 this.recordedVideo.style.display = 'none'; | ||||
|             } | ||||
|             this.recordedVideo.classList.remove('loading'); | ||||
|              | ||||
|             // 添加重试机制
 | ||||
|             if (!this.retryCount) this.retryCount = 0; | ||||
|             if (this.retryCount < 2) { | ||||
|                 this.retryCount++; | ||||
|                 console.log(`尝试重新创建默认视频流 (${this.retryCount}/2)`); | ||||
|                 setTimeout(() => this.startDefaultVideoStream(), 1000); | ||||
|             } else { | ||||
|                 this.retryCount = 0; | ||||
|                 console.log('默认视频流创建失败,已达到最大重试次数', 'error'); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -355,7 +427,7 @@ class WebRTCChat { | ||||
|     async precreateImportantVideos() { | ||||
|         if (this.isInitialized) return; | ||||
|          | ||||
|         this.logMessage('开始预创建重要视频流...', 'info'); | ||||
|         console.log('开始预创建重要流...', 'info'); | ||||
|          | ||||
|         for (const videoFile of [this.interactionVideo, this.defaultVideo]) { | ||||
|             try { | ||||
| @ -366,8 +438,14 @@ class WebRTCChat { | ||||
|                 this.logMessage(`预创建视频流失败: ${videoFile} - ${error.message}`, 'error'); | ||||
|             } | ||||
|         } | ||||
|         // 启用开始通话按钮
 | ||||
|             if (this.startButton) { | ||||
|                 this.startButton.disabled = false; | ||||
|                 this.startButton.style.opacity = '1'; | ||||
|             } | ||||
|          | ||||
|         this.isInitialized = true; | ||||
|          | ||||
|         this.logMessage('重要视频流预创建完成', 'success'); | ||||
|     } | ||||
| 
 | ||||
| @ -988,8 +1066,14 @@ class WebRTCChat { | ||||
|     } | ||||
| 
 | ||||
|     bindEvents() { | ||||
|         // 开始通话按钮
 | ||||
|         this.startButton.onclick = () => this.startCall(); | ||||
|         // 开始通话按钮 - 添加视频准备状态检查
 | ||||
|         this.startButton.onclick = () => { | ||||
|             if (!this.isVideoReady) { | ||||
|                 this.logMessage('还在加载中,请稍候...', 'warning'); | ||||
|                 return; | ||||
|             } | ||||
|             this.startCall(); | ||||
|         }; | ||||
|          | ||||
|         // 停止通话按钮 - 改为调用 userDisconnect
 | ||||
|         this.stopButton.onclick = () => this.userDisconnect(); | ||||
| @ -1042,13 +1126,27 @@ class WebRTCChat { | ||||
| 
 | ||||
|     async startCall() { | ||||
|         try { | ||||
|             // 立即隐藏开始通话按钮
 | ||||
|             // 检查所有必要条件
 | ||||
|             if (!this.isVideoReady || !this.isDefaultVideoLoaded) { | ||||
|                 this.logMessage('视频资源尚未准备就绪,请稍候...', 'warning'); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (!this.socket || !this.socket.connected) { | ||||
|                 this.logMessage('网络连接未就绪,请稍候...', 'warning'); | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             // 隐藏开始通话按钮
 | ||||
|             this.startButton.style.display = 'none'; | ||||
|             // 显示等待连接提示
 | ||||
|             this.showConnectionWaiting(); | ||||
|             // 切换到通话中图标
 | ||||
|             this.switchToCallingIcon(); | ||||
|              | ||||
|             // 现在才开始显示视频
 | ||||
|             await this.startDefaultVideoStream(); | ||||
|              | ||||
|             // 添加更详细的错误处理
 | ||||
|             console.log('开始请求麦克风权限...'); | ||||
|             this.localStream = await navigator.mediaDevices.getUserMedia({ | ||||
| @ -1061,6 +1159,7 @@ class WebRTCChat { | ||||
|             await this.startVoiceRecording(); | ||||
|              | ||||
|             this.startButton.disabled = true; | ||||
|             this.startButton.style.opacity = '0.5' | ||||
|             this.stopButton.disabled = false; | ||||
|              | ||||
|             // 显示结束通话按钮
 | ||||
| @ -1085,17 +1184,18 @@ class WebRTCChat { | ||||
|             this.socket.emit('call-started'); | ||||
|              | ||||
|             // 开始播放当前场景的默认视频
 | ||||
|             await this.precreateImportantVideos(); | ||||
|             // await this.precreateImportantVideos();
 | ||||
| 
 | ||||
|             // 隐藏等待连接提示
 | ||||
|             this.hideConnectionWaiting(); | ||||
|              | ||||
|         } catch (error) { | ||||
|             this.logMessage(`开始通话失败: ${error.message}`, 'error'); | ||||
|             // 恢复开始通话按钮
 | ||||
|             this.startButton.style.display = 'block'; | ||||
|             // 如果出错,隐藏等待连接提示并恢复到默认图标
 | ||||
|             this.hideConnectionWaiting(); | ||||
|             this.switchToDefaultIcon(); | ||||
|             this.logMessage('无法访问麦克风: ' + error.message, 'error'); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -1133,21 +1233,41 @@ class WebRTCChat { | ||||
|         this.stopButton.style.display = 'none'; | ||||
|         this.stopButton.disabled = true; | ||||
|          | ||||
|         // 隐藏视频元素
 | ||||
|         if (this.recordedVideo) { | ||||
|             this.recordedVideo.style.display = 'none'; | ||||
|             this.recordedVideo.srcObject = null; | ||||
|         } | ||||
|         if (this.recordedVideoBuffer) { | ||||
|             this.recordedVideoBuffer.style.display = 'none'; | ||||
|             this.recordedVideoBuffer.srcObject = null; | ||||
|         } | ||||
|          | ||||
|         // 显示开始通话按钮
 | ||||
|         this.startButton.disabled = true; | ||||
|         this.startButton.style.display = 'block'; | ||||
|         this.startButton.disabled = false; | ||||
|         this.startButton.style.opacity = '0.5'; | ||||
|          | ||||
|         // 移除页面刷新,保持websocket连接
 | ||||
|         // setTimeout(() => {
 | ||||
|         //     window.location.reload();
 | ||||
|         // }, 300);
 | ||||
|          | ||||
|         setTimeout(() => { | ||||
|             // 显示头像,隐藏视频
 | ||||
|             if (this.videoContainer) { | ||||
|                 this.videoContainer.classList.remove('calling'); | ||||
|             } | ||||
|         }, 300); | ||||
|         // 清理视频缓存和预创建流
 | ||||
|         this.clearVideoCache(); | ||||
|          | ||||
|         // setTimeout(() => {
 | ||||
|         //     // 显示头像,隐藏视频
 | ||||
|         //     if (this.videoContainer) {
 | ||||
|         //         this.videoContainer.classList.remove('calling');
 | ||||
|         //     }
 | ||||
|              | ||||
|         //     // 重新初始化重要视频流
 | ||||
|         //     this.precreateImportantVideos().then(() => {
 | ||||
|         //         // 重新启动默认视频流
 | ||||
|         //         this.startDefaultVideoStream();
 | ||||
|         //     });
 | ||||
|         // }, 300);
 | ||||
|     } | ||||
| 
 | ||||
|     // 新增:用户主动断开连接的方法
 | ||||
| @ -1155,16 +1275,36 @@ class WebRTCChat { | ||||
|         // 发送用户关闭连接事件到后端
 | ||||
|         if (this.socket && this.socket.connected) { | ||||
|             this.socket.emit('user-disconnect'); | ||||
|              | ||||
|             // 等待服务器确认断开后再刷新
 | ||||
|             this.socket.on('disconnect', () => { | ||||
|                 console.log('WebSocket已断开,准备刷新页面...'); | ||||
|                 setTimeout(() => { | ||||
|                     window.location.reload(); | ||||
|                 }, 500); | ||||
|             }); | ||||
|              | ||||
|             // 主动断开连接
 | ||||
|             setTimeout(() => { | ||||
|                 this.socket.disconnect(); | ||||
|             }, 200); | ||||
|              | ||||
|             // 兜底机制:如果2秒内没有正常断开,强制刷新
 | ||||
|             setTimeout(() => { | ||||
|                 if (this.socket && this.socket.connected) { | ||||
|                     console.log('WebSocket断开超时,强制刷新页面'); | ||||
|                     window.location.reload(); | ||||
|                 } | ||||
|             }, 2000); | ||||
|         } else { | ||||
|             // 如果socket已经断开,直接刷新
 | ||||
|             setTimeout(() => { | ||||
|                 window.location.reload(); | ||||
|             }, 100); | ||||
|         } | ||||
|          | ||||
|         // 调用停止通话
 | ||||
|         this.stopCall(); | ||||
|          | ||||
|         // 延迟刷新,确保服务器处理完断开逻辑
 | ||||
|         console.log('用户主动断开,300ms后刷新页面清除缓存...'); | ||||
|         setTimeout(() => { | ||||
|             window.location.reload(); | ||||
|         }, 300); | ||||
|     } | ||||
| 
 | ||||
|     // 清除视频缓存的方法
 | ||||
| @ -1194,6 +1334,19 @@ class WebRTCChat { | ||||
|         // 清除视频流映射缓存
 | ||||
|         this.videoStreams.clear(); | ||||
|          | ||||
|         // 清除预创建的视频流
 | ||||
|         if (this.precreatedStreams) { | ||||
|             this.precreatedStreams.forEach((stream, videoFile) => { | ||||
|                 if (stream) { | ||||
|                     stream.getTracks().forEach(track => track.stop()); | ||||
|                 } | ||||
|             }); | ||||
|             this.precreatedStreams.clear(); | ||||
|         } | ||||
|          | ||||
|         // 重置初始化状态,允许重新预创建
 | ||||
|         this.isInitialized = false; | ||||
|          | ||||
|         // 重置视频相关状态
 | ||||
|         this.currentVideo = null; | ||||
|         this.activeVideoElement = 'main'; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user