等待视频加载完成
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 2m53s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 2m53s
				
			This commit is contained in:
		
							parent
							
								
									a73165a6a1
								
							
						
					
					
						commit
						0478bb4cdd
					
				| @ -451,7 +451,7 @@ | |||||||
|                     <div class="avatar-container" id="avatarContainer"> |                     <div class="avatar-container" id="avatarContainer"> | ||||||
|                         <div class="avatar" id="avatar"> |                         <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> | ||||||
|                         <!-- <div class="avatar-name">AI助手</div> --> |                         <!-- <div class="avatar-name">AI助手</div> --> | ||||||
|                     </div> |                     </div> | ||||||
|  | |||||||
							
								
								
									
										169
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								src/index.js
									
									
									
									
									
								
							| @ -9,8 +9,6 @@ class WebRTCChat { | |||||||
|     constructor() { |     constructor() { | ||||||
|         console.log('WebRTCChat 构造函数开始执行'); |         console.log('WebRTCChat 构造函数开始执行'); | ||||||
|          |          | ||||||
| 
 |  | ||||||
|          |  | ||||||
|         // 初始化历史消息(异步)
 |         // 初始化历史消息(异步)
 | ||||||
|         this.initializeHistory(); |         this.initializeHistory(); | ||||||
|          |          | ||||||
| @ -30,6 +28,10 @@ class WebRTCChat { | |||||||
|         this.precreatedStreams = new Map(); // 预创建的视频流
 |         this.precreatedStreams = new Map(); // 预创建的视频流
 | ||||||
|         this.importantVideos = ['d-3s.mp4', 's-1.mp4']; // 重要视频列表
 |         this.importantVideos = ['d-3s.mp4', 's-1.mp4']; // 重要视频列表
 | ||||||
|         this.isInitialized = false; |         this.isInitialized = false; | ||||||
|  |         // 添加视频加载状态标志
 | ||||||
|  |         this.isVideoReady = false; | ||||||
|  |         this.isDefaultVideoLoaded = false; | ||||||
|  |         this.retryCount = 0; // 添加重试计数器
 | ||||||
| 
 | 
 | ||||||
|         // 添加视频相关属性
 |         // 添加视频相关属性
 | ||||||
|         this.videoSender = null; // WebRTC视频发送器
 |         this.videoSender = null; // WebRTC视频发送器
 | ||||||
| @ -67,7 +69,9 @@ class WebRTCChat { | |||||||
|         this.initializeSocket(); |         this.initializeSocket(); | ||||||
|         this.loadVideoMapping(); |         this.loadVideoMapping(); | ||||||
|         this.loadVideoList(); |         this.loadVideoList(); | ||||||
|         this.loadDefaultVideo(); |          | ||||||
|  |         // 只预加载视频资源,不显示视频
 | ||||||
|  |         this.preloadVideoResources(); | ||||||
|         this.bindEvents(); |         this.bindEvents(); | ||||||
| 
 | 
 | ||||||
|         // 在初始化完成后预加载常用视频
 |         // 在初始化完成后预加载常用视频
 | ||||||
| @ -76,7 +80,7 @@ class WebRTCChat { | |||||||
|             this.preloadCommonVideos().catch(error => { |             this.preloadCommonVideos().catch(error => { | ||||||
|                 this.logMessage(`预加载过程出错: ${error.message}`, 'error'); |                 this.logMessage(`预加载过程出错: ${error.message}`, 'error'); | ||||||
|             }); |             }); | ||||||
|         }, 500); // 延迟2秒开始预加载,避免影响
 |         }, 500); | ||||||
| 
 | 
 | ||||||
|         // 预创建重要视频流
 |         // 预创建重要视频流
 | ||||||
|         setTimeout(() => { |         setTimeout(() => { | ||||||
| @ -88,6 +92,30 @@ class WebRTCChat { | |||||||
|         window.webrtcApp = this; |         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() { |     initializeElements() { | ||||||
|         // 视频元素
 |         // 视频元素
 | ||||||
|         this.localVideo = document.getElementById('localVideo'); |         this.localVideo = document.getElementById('localVideo'); | ||||||
| @ -111,6 +139,14 @@ class WebRTCChat { | |||||||
|         this.stopButton = document.getElementById('stopButton'); |         this.stopButton = document.getElementById('stopButton'); | ||||||
|         this.muteButton = document.getElementById('muteButton'); |         this.muteButton = document.getElementById('muteButton'); | ||||||
|         this.sendTextButton = document.getElementById('sendTextButton'); |         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.startVoiceButton = document.getElementById('startVoiceButton');
 | ||||||
|         // this.stopVoiceButton = document.getElementById('stopVoiceButton');
 |         // this.stopVoiceButton = document.getElementById('stopVoiceButton');
 | ||||||
|         // this.defaultVideoButton = document.getElementById('defaultVideoButton');
 |         // this.defaultVideoButton = document.getElementById('defaultVideoButton');
 | ||||||
| @ -165,7 +201,7 @@ class WebRTCChat { | |||||||
|         // 通话开始处理
 |         // 通话开始处理
 | ||||||
|         this.socket.on('call-started', (data) => { |         this.socket.on('call-started', (data) => { | ||||||
|             console.log('通话已开始', 'success'); |             console.log('通话已开始', 'success'); | ||||||
|             this.startDefaultVideoStream(); |             // 移除这里的视频流启动,因为现在在startCall中处理
 | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         // 场景切换处理
 |         // 场景切换处理
 | ||||||
| @ -204,7 +240,7 @@ class WebRTCChat { | |||||||
|             this.videoMapping = data.mapping; |             this.videoMapping = data.mapping; | ||||||
|             this.interactionVideo = data.mapping['8-4-sh']; |             this.interactionVideo = data.mapping['8-4-sh']; | ||||||
|             this.defaultVideo = data.mapping["default"]; |             this.defaultVideo = data.mapping["default"]; | ||||||
|             this.logMessage('视频映射加载成功', 'success'); |             console.log('映射加载成功', 'success'); | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             this.logMessage('加载视频映射失败: ' + error.message, 'error'); |             this.logMessage('加载视频映射失败: ' + error.message, 'error'); | ||||||
|         } |         } | ||||||
| @ -264,18 +300,35 @@ class WebRTCChat { | |||||||
| 
 | 
 | ||||||
|     async startDefaultVideoStream() { |     async startDefaultVideoStream() { | ||||||
|         try { |         try { | ||||||
|             this.logMessage('开始创建默认视频流', 'info'); |             console.log('开始创建默认视频流', 'info'); | ||||||
|  |              | ||||||
|  |             // 显示视频元素
 | ||||||
|  |             if (this.recordedVideo) { | ||||||
|  |                 this.recordedVideo.style.display = 'block'; | ||||||
|  |             } | ||||||
|              |              | ||||||
|             // 添加加载状态
 |             // 添加加载状态
 | ||||||
|             this.recordedVideo.classList.add('loading'); |             this.recordedVideo.classList.add('loading'); | ||||||
|              |              | ||||||
|             // 创建默认视频的MediaStream
 |             // 创建默认视频的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)); |             await new Promise(resolve => setTimeout(resolve, 1000)); | ||||||
|              |              | ||||||
|             // 检查流是否有效
 |             // 再次检查流是否有效
 | ||||||
|             if (!defaultStream || defaultStream.getTracks().length === 0) { |             if (!defaultStream || defaultStream.getTracks().length === 0) { | ||||||
|                 throw new Error('默认视频流创建失败'); |                 throw new Error('默认视频流创建失败'); | ||||||
|             } |             } | ||||||
| @ -311,20 +364,39 @@ class WebRTCChat { | |||||||
|             // 确保视频开始播放
 |             // 确保视频开始播放
 | ||||||
|             try { |             try { | ||||||
|                 await this.recordedVideo.play(); |                 await this.recordedVideo.play(); | ||||||
|                 this.logMessage('默认视频开始播放', 'success'); |                 // this.logMessage('默认视频开始播放', 'success');
 | ||||||
|                  |                  | ||||||
|                 // 移除加载状态,添加播放状态
 |                 // 移除加载状态,添加播放状态
 | ||||||
|                 this.recordedVideo.classList.remove('loading'); |                 this.recordedVideo.classList.remove('loading'); | ||||||
|                 this.recordedVideo.classList.add('playing'); |                 this.recordedVideo.classList.add('playing'); | ||||||
|             } catch (playError) { |             } catch (playError) { | ||||||
|                 this.logMessage(`默认视频播放失败: ${playError.message}`, 'error'); |                 // this.logMessage(`默认视频播放失败: ${playError.message}`, 'error');
 | ||||||
|                 this.recordedVideo.classList.remove('loading'); |                 this.recordedVideo.classList.remove('loading'); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             // 再次检查视频是否准备就绪
 | ||||||
|  |             // this.startButton.disabled = false;
 | ||||||
|              |              | ||||||
|             this.logMessage('默认视频流创建成功', 'success'); |             console.log('默认流创建成功', 'success'); | ||||||
|         } catch (error) { |         } 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'); |             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'); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -368,6 +440,11 @@ class WebRTCChat { | |||||||
|         } |         } | ||||||
|          |          | ||||||
|         this.isInitialized = true; |         this.isInitialized = true; | ||||||
|  |         // 启用开始通话按钮
 | ||||||
|  |             if (this.startButton) { | ||||||
|  |                 this.startButton.disabled = false; | ||||||
|  |                 this.startButton.style.opacity = '1'; | ||||||
|  |             } | ||||||
|         this.logMessage('重要视频流预创建完成', 'success'); |         this.logMessage('重要视频流预创建完成', 'success'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -988,8 +1065,14 @@ class WebRTCChat { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bindEvents() { |     bindEvents() { | ||||||
|         // 开始通话按钮
 |         // 开始通话按钮 - 添加视频准备状态检查
 | ||||||
|         this.startButton.onclick = () => this.startCall(); |         this.startButton.onclick = () => { | ||||||
|  |             if (!this.isVideoReady) { | ||||||
|  |                 this.logMessage('还在加载中,请稍候...', 'warning'); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             this.startCall(); | ||||||
|  |         }; | ||||||
|          |          | ||||||
|         // 停止通话按钮 - 改为调用 userDisconnect
 |         // 停止通话按钮 - 改为调用 userDisconnect
 | ||||||
|         this.stopButton.onclick = () => this.userDisconnect(); |         this.stopButton.onclick = () => this.userDisconnect(); | ||||||
| @ -1042,13 +1125,27 @@ class WebRTCChat { | |||||||
| 
 | 
 | ||||||
|     async startCall() { |     async startCall() { | ||||||
|         try { |         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.startButton.style.display = 'none'; | ||||||
|             // 显示等待连接提示
 |             // 显示等待连接提示
 | ||||||
|             this.showConnectionWaiting(); |             this.showConnectionWaiting(); | ||||||
|             // 切换到通话中图标
 |             // 切换到通话中图标
 | ||||||
|             this.switchToCallingIcon(); |             this.switchToCallingIcon(); | ||||||
|              |              | ||||||
|  |             // 现在才开始显示视频
 | ||||||
|  |             await this.startDefaultVideoStream(); | ||||||
|  |              | ||||||
|             // 添加更详细的错误处理
 |             // 添加更详细的错误处理
 | ||||||
|             console.log('开始请求麦克风权限...'); |             console.log('开始请求麦克风权限...'); | ||||||
|             this.localStream = await navigator.mediaDevices.getUserMedia({ |             this.localStream = await navigator.mediaDevices.getUserMedia({ | ||||||
| @ -1091,11 +1188,12 @@ class WebRTCChat { | |||||||
|             this.hideConnectionWaiting(); |             this.hideConnectionWaiting(); | ||||||
|              |              | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|  |             this.logMessage(`开始通话失败: ${error.message}`, 'error'); | ||||||
|  |             // 恢复开始通话按钮
 | ||||||
|             this.startButton.style.display = 'block'; |             this.startButton.style.display = 'block'; | ||||||
|             // 如果出错,隐藏等待连接提示并恢复到默认图标
 |             // 如果出错,隐藏等待连接提示并恢复到默认图标
 | ||||||
|             this.hideConnectionWaiting(); |             this.hideConnectionWaiting(); | ||||||
|             this.switchToDefaultIcon(); |             this.switchToDefaultIcon(); | ||||||
|             this.logMessage('无法访问麦克风: ' + error.message, 'error'); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1133,20 +1231,40 @@ class WebRTCChat { | |||||||
|         this.stopButton.style.display = 'none'; |         this.stopButton.style.display = 'none'; | ||||||
|         this.stopButton.disabled = true; |         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.style.display = 'block'; |  | ||||||
|         this.startButton.disabled = false; |         this.startButton.disabled = false; | ||||||
|  |         this.startButton.style.display = 'block'; | ||||||
|  |         this.startButton.style.opacity = '1'; | ||||||
|          |          | ||||||
|         // 移除页面刷新,保持websocket连接
 |         // 移除页面刷新,保持websocket连接
 | ||||||
|         // setTimeout(() => {
 |         // setTimeout(() => {
 | ||||||
|         //     window.location.reload();
 |         //     window.location.reload();
 | ||||||
|         // }, 300);
 |         // }, 300);
 | ||||||
|          |          | ||||||
|  |         // 清理视频缓存和预创建流
 | ||||||
|  |         this.clearVideoCache(); | ||||||
|  |          | ||||||
|         setTimeout(() => { |         setTimeout(() => { | ||||||
|             // 显示头像,隐藏视频
 |             // 显示头像,隐藏视频
 | ||||||
|             if (this.videoContainer) { |             if (this.videoContainer) { | ||||||
|                 this.videoContainer.classList.remove('calling'); |                 this.videoContainer.classList.remove('calling'); | ||||||
|             } |             } | ||||||
|  |              | ||||||
|  |             // 重新初始化重要视频流
 | ||||||
|  |             this.precreateImportantVideos().then(() => { | ||||||
|  |                 // 重新启动默认视频流
 | ||||||
|  |                 this.startDefaultVideoStream(); | ||||||
|  |             }); | ||||||
|         }, 300); |         }, 300); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1164,7 +1282,7 @@ class WebRTCChat { | |||||||
|         console.log('用户主动断开,300ms后刷新页面清除缓存...'); |         console.log('用户主动断开,300ms后刷新页面清除缓存...'); | ||||||
|         setTimeout(() => { |         setTimeout(() => { | ||||||
|             window.location.reload(); |             window.location.reload(); | ||||||
|         }, 300); |         }, 100); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // 清除视频缓存的方法
 |     // 清除视频缓存的方法
 | ||||||
| @ -1194,6 +1312,19 @@ class WebRTCChat { | |||||||
|         // 清除视频流映射缓存
 |         // 清除视频流映射缓存
 | ||||||
|         this.videoStreams.clear(); |         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.currentVideo = null; | ||||||
|         this.activeVideoElement = 'main'; |         this.activeVideoElement = 'main'; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Song367
						Song367