log优化

This commit is contained in:
2026-05-24 14:16:28 +08:00
parent e48a6eae3c
commit 518f8a94b3
12 changed files with 213 additions and 1112 deletions

View File

@@ -1,3 +1,6 @@
import { createLogger } from './logger.js';
const logger = createLogger('chat');
/** /**
* 消息模块 * 消息模块
* 处理聊天消息的发送、接收和显示 * 处理聊天消息的发送、接收和显示
@@ -72,7 +75,7 @@ function sendChatMessage(message) {
* @param {Object} data - 消息数据 * @param {Object} data - 消息数据
*/ */
function handleChatMessage(data) { function handleChatMessage(data) {
console.log('处理聊天:', data); logger.debug('处理聊天:', data);
addMessage(data); addMessage(data);
const isImage = data.content && data.content.startsWith('data:image/'); const isImage = data.content && data.content.startsWith('data:image/');

View File

@@ -1,3 +1,6 @@
import { createLogger } from '../logger.js';
const logger = createLogger('legacy-connect');
/** /**
* 连接界面逻辑 * 连接界面逻辑
* 处理初始连接、创建通话和加入通话的功能 * 处理初始连接、创建通话和加入通话的功能
@@ -51,7 +54,7 @@ async function getAllConnectionIds() {
const data = await response.json(); const data = await response.json();
displayConnectionIds(data.connectionIds); displayConnectionIds(data.connectionIds);
} catch (error) { } catch (error) {
console.error('Error fetching connection IDs:', error); logger.error('Error fetching connection IDs:', error);
showNotification('获取连接ID失败', 'error'); showNotification('获取连接ID失败', 'error');
} }
} }
@@ -164,7 +167,7 @@ function loadUserSettings() {
document.getElementById('userAvatar').src = avatar; document.getElementById('userAvatar').src = avatar;
document.getElementById('avatarPreview').src = avatar; document.getElementById('avatarPreview').src = avatar;
} catch (error) { } catch (error) {
console.error('Error loading user settings:', error); logger.error('Error loading user settings:', error);
// 加载失败时使用默认头像 // 加载失败时使用默认头像
const defaultAvatar = '/images/p1.png'; const defaultAvatar = '/images/p1.png';
document.getElementById('userAvatar').src = defaultAvatar; document.getElementById('userAvatar').src = defaultAvatar;
@@ -254,7 +257,7 @@ function handleAvatarUpload(event) {
} }
}) })
.catch(error => { .catch(error => {
console.error('Error uploading avatar:', error); logger.error('Error uploading avatar:', error);
showNotification('头像上传失败,请重试', 'error'); showNotification('头像上传失败,请重试', 'error');
// 上传失败时,使用默认头像 // 上传失败时,使用默认头像

View File

@@ -7,6 +7,9 @@ import {
renderOnlineUsers renderOnlineUsers
} from './connect-directory.js'; } from './connect-directory.js';
import { createProfileSettingsController } from './profile-settings.js'; import { createProfileSettingsController } from './profile-settings.js';
import { createLogger } from './logger.js';
const logger = createLogger('connectview');
let onWsStatusChange = null; let onWsStatusChange = null;
let cachedOnlineUsers = []; let cachedOnlineUsers = [];
@@ -45,9 +48,9 @@ export async function initWebSocket() {
store.syncSocketUserInfo(); store.syncSocketUserInfo();
updateWsStatus(true); updateWsStatus(true);
await refreshOnlineUsers(); await refreshOnlineUsers();
console.log('WebSocket initialized from connectview'); logger.debug('WebSocket initialized from connectview');
} catch (error) { } catch (error) {
console.error('Failed to initialize WebSocket:', error); logger.error('Failed to initialize WebSocket:', error);
updateWsStatus(false); updateWsStatus(false);
showNotification('WebSocket连接失败请刷新页面重试', 'error'); showNotification('WebSocket连接失败请刷新页面重试', 'error');
} }
@@ -62,7 +65,7 @@ async function refreshOnlineUsers(silent = true) {
showNotification(`当前共有 ${cachedOnlineUsers.length} 个WebSocket用户在线`); showNotification(`当前共有 ${cachedOnlineUsers.length} 个WebSocket用户在线`);
} }
} catch (error) { } catch (error) {
console.error('Error fetching online users:', error); logger.error('Error fetching online users:', error);
if (!silent) { if (!silent) {
showNotification('获取在线用户失败', 'error'); showNotification('获取在线用户失败', 'error');
} }
@@ -78,7 +81,7 @@ async function getAllConnectionIds() {
updateConnectionIdList(connectionIds); updateConnectionIdList(connectionIds);
updateOnlineUsersList(cachedOnlineUsers); updateOnlineUsersList(cachedOnlineUsers);
} catch (error) { } catch (error) {
console.error('Error fetching connection IDs:', error); logger.error('Error fetching connection IDs:', error);
showNotification('获取连接信息失败', 'error'); showNotification('获取连接信息失败', 'error');
} }
} }
@@ -104,7 +107,7 @@ function getCurrentUserId() {
const settings = JSON.parse(localStorage.getItem('userSettings') || '{}'); const settings = JSON.parse(localStorage.getItem('userSettings') || '{}');
return settings.userId || settings.id || ''; return settings.userId || settings.id || '';
} catch (error) { } catch (error) {
console.error('Error parsing current user settings:', error); logger.error('Error parsing current user settings:', error);
return ''; return '';
} }
} }

View File

@@ -1,3 +1,6 @@
import { createLogger } from './logger.js';
const logger = createLogger('invite');
const DEFAULT_CALLER_NAME = '\u9080\u8bf7\u65b9'; const DEFAULT_CALLER_NAME = '\u9080\u8bf7\u65b9';
const DEFAULT_CALLER_AVATAR = '/images/p2.png'; const DEFAULT_CALLER_AVATAR = '/images/p2.png';
const DEFAULT_APPLY_REASON = '\u672a\u586b\u5199'; const DEFAULT_APPLY_REASON = '\u672a\u586b\u5199';
@@ -127,7 +130,7 @@ export function createInviteController({
targetUserId: pendingInvite.inviterUserId targetUserId: pendingInvite.inviterUserId
}); });
} catch (error) { } catch (error) {
console.error('Error accepting invite:', error); logger.error('Error accepting invite:', error);
notify('\u63a5\u53d7\u9080\u8bf7\u5931\u8d25\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5', 'error'); notify('\u63a5\u53d7\u9080\u8bf7\u5931\u8d25\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5', 'error');
return; return;
} }
@@ -152,7 +155,7 @@ export function createInviteController({
targetUserId: pendingInvite.inviterUserId targetUserId: pendingInvite.inviterUserId
}); });
} catch (error) { } catch (error) {
console.error('Error rejecting invite:', error); logger.error('Error rejecting invite:', error);
} }
} }

84
client/public/logger.js Normal file
View File

@@ -0,0 +1,84 @@
const LOG_LEVELS = {
debug: 10,
info: 20,
warn: 30,
error: 40,
silent: 50
};
const STORAGE_KEY = 'video_socket_log_level';
const DEFAULT_LEVEL = 'warn';
function normalizeLevel(level) {
if (!level) {
return DEFAULT_LEVEL;
}
const normalized = String(level).toLowerCase();
return Object.prototype.hasOwnProperty.call(LOG_LEVELS, normalized)
? normalized
: DEFAULT_LEVEL;
}
function getConfiguredLevel() {
try {
const queryLevel = new URLSearchParams(window.location.search).get('logLevel');
if (queryLevel) {
return normalizeLevel(queryLevel);
}
} catch (_error) {
}
try {
const storageLevel = localStorage.getItem(STORAGE_KEY);
if (storageLevel) {
return normalizeLevel(storageLevel);
}
} catch (_error) {
}
return DEFAULT_LEVEL;
}
function shouldLog(level) {
return LOG_LEVELS[level] >= LOG_LEVELS[getConfiguredLevel()];
}
function getConsoleMethod(level) {
switch (level) {
case 'debug':
return console.debug;
case 'info':
return console.info;
case 'warn':
return console.warn;
case 'error':
return console.error;
default:
return console.log;
}
}
function emit(level, scope, args) {
if (!shouldLog(level)) {
return;
}
const prefix = scope ? `[${scope}]` : '[app]';
getConsoleMethod(level)(prefix, ...args);
}
export function createLogger(scope) {
return {
debug: (...args) => emit('debug', scope, args),
info: (...args) => emit('info', scope, args),
warn: (...args) => emit('warn', scope, args),
error: (...args) => emit('error', scope, args)
};
}
export function setBrowserLogLevel(level) {
const normalized = normalizeLevel(level);
localStorage.setItem(STORAGE_KEY, normalized);
return normalized;
}

View File

@@ -9,6 +9,9 @@ import {
loadUserSettings loadUserSettings
} from './connectview.js'; } from './connectview.js';
import { createInviteController } from './invite-controller.js'; import { createInviteController } from './invite-controller.js';
import { createLogger } from './logger.js';
const logger = createLogger('main');
let connectionId = ''; let connectionId = '';
let currentView = 'connect'; let currentView = 'connect';
@@ -43,10 +46,10 @@ async function switchToCallView(targetConnectionId) {
renderer.renderHeaderTitle(); renderer.renderHeaderTitle();
callViewController.bindDomEvents(); callViewController.bindDomEvents();
console.log('Video call app initialized successfully'); logger.debug('Video call app initialized successfully');
return true; return true;
} catch (error) { } catch (error) {
console.error('Error initializing app:', error); logger.error('Error initializing app:', error);
showNotification('初始化失败,请刷新页面重试', 'error'); showNotification('初始化失败,请刷新页面重试', 'error');
return false; return false;
} }
@@ -116,9 +119,9 @@ window.addEventListener('DOMContentLoaded', async () => {
inviteController.showCallRequestDialog(invitePayload); inviteController.showCallRequestDialog(invitePayload);
} }
console.log('SPA initialized, showing connect view'); logger.debug('SPA initialized, showing connect view');
} catch (error) { } catch (error) {
console.error('Error initializing SPA:', error); logger.error('Error initializing SPA:', error);
showNotification('初始化失败,请刷新页面重试', 'error'); showNotification('初始化失败,请刷新页面重试', 'error');
} }
}); });

View File

@@ -1,3 +1,6 @@
import { createLogger } from './logger.js';
const logger = createLogger('profile');
const DEFAULT_AVATAR = '/images/p1.png'; const DEFAULT_AVATAR = '/images/p1.png';
const MAX_AVATAR_SIZE = 2 * 1024 * 1024; const MAX_AVATAR_SIZE = 2 * 1024 * 1024;
const USER_ID_PREFIX = 'user_'; const USER_ID_PREFIX = 'user_';
@@ -100,7 +103,7 @@ export function createProfileSettingsController({ store, notify }) {
updateUserName(settings.name || '\u6211'); updateUserName(settings.name || '\u6211');
setAvatarPreview(settings.avatar || DEFAULT_AVATAR); setAvatarPreview(settings.avatar || DEFAULT_AVATAR);
} catch (error) { } catch (error) {
console.error('Error loading user settings:', error); logger.error('Error loading user settings:', error);
setAvatarPreview(DEFAULT_AVATAR); setAvatarPreview(DEFAULT_AVATAR);
} }
} }
@@ -152,7 +155,7 @@ export function createProfileSettingsController({ store, notify }) {
saveSettings(); saveSettings();
notify('\u5934\u50cf\u4e0a\u4f20\u6210\u529f', 'success'); notify('\u5934\u50cf\u4e0a\u4f20\u6210\u529f', 'success');
} catch (error) { } catch (error) {
console.error('Error uploading avatar:', error); logger.error('Error uploading avatar:', error);
setAvatarPreview(DEFAULT_AVATAR); setAvatarPreview(DEFAULT_AVATAR);
notify('\u5934\u50cf\u4e0a\u4f20\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5', 'error'); notify('\u5934\u50cf\u4e0a\u4f20\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5', 'error');
} }

View File

@@ -1,4 +1,7 @@
import { createParticipantTile, getParticipantTile } from './renderer-participant-grid.js'; import { createParticipantTile, getParticipantTile } from './renderer-participant-grid.js';
import { createLogger } from './logger.js';
const logger = createLogger('renderer-media');
export function getVideoResolution(track) { export function getVideoResolution(track) {
if (track && track.getSettings) { if (track && track.getSettings) {
@@ -47,18 +50,18 @@ export function renderParticipantStreamMedia({
if (!tile) { if (!tile) {
tile = createParticipantTile(connectionId, displayName); tile = createParticipantTile(connectionId, displayName);
grid.appendChild(tile); grid.appendChild(tile);
console.log(`Created participant video tile for ${connectionId}`); logger.debug(`Created participant video tile for ${connectionId}`);
} }
const video = tile.querySelector('video'); const video = tile.querySelector('video');
if (video && stream) { if (video && stream) {
if (video.srcObject === stream) { if (video.srcObject === stream) {
console.log(`Same stream for participant ${connectionId}, ensuring playback`); logger.debug(`Same stream for participant ${connectionId}, ensuring playback`);
video.play().catch(error => console.log('Auto-play prevented:', error.message)); video.play().catch(error => logger.debug('Auto-play prevented:', error.message));
} else { } else {
video.srcObject = stream; video.srcObject = stream;
video.play().catch(error => console.log('Auto-play prevented:', error.message)); video.play().catch(error => logger.debug('Auto-play prevented:', error.message));
console.log(`Set remote stream for participant tile ${connectionId}`); logger.debug(`Set remote stream for participant tile ${connectionId}`);
} }
} }
@@ -86,15 +89,15 @@ export function renderSingleRemoteStreamMedia({
connectingOverlay connectingOverlay
}) { }) {
if (!remoteVideo || !stream) { if (!remoteVideo || !stream) {
console.error('Either remoteVideo element or stream is missing'); logger.error('Either remoteVideo element or stream is missing');
return; return;
} }
console.log('Rendering remote stream:', stream, 'tracks:', stream.getTracks().map(track => `${track.kind}(${track.readyState})`)); logger.debug('Rendering remote stream:', stream, 'tracks:', stream.getTracks().map(track => `${track.kind}(${track.readyState})`));
if (remoteVideo.srcObject === stream) { if (remoteVideo.srcObject === stream) {
console.log('Same stream object, track added - ensuring playback'); logger.debug('Same stream object, track added - ensuring playback');
remoteVideo.play().catch(error => console.log('Auto-play prevented:', error.message)); remoteVideo.play().catch(error => logger.debug('Auto-play prevented:', error.message));
return; return;
} }
@@ -103,7 +106,7 @@ export function renderSingleRemoteStreamMedia({
remoteVideo.playsinline = true; remoteVideo.playsinline = true;
remoteVideo.muted = false; remoteVideo.muted = false;
remoteVideo.play().catch(error => { remoteVideo.play().catch(error => {
console.log('Auto-play prevented, will retry on interaction:', error.message); logger.debug('Auto-play prevented, will retry on interaction:', error.message);
}); });
if (disconnectedOverlay) { if (disconnectedOverlay) {
@@ -112,10 +115,10 @@ export function renderSingleRemoteStreamMedia({
const videoTracks = stream.getVideoTracks(); const videoTracks = stream.getVideoTracks();
const audioTracks = stream.getAudioTracks(); const audioTracks = stream.getAudioTracks();
console.log(`Stream has ${videoTracks.length} video tracks, ${audioTracks.length} audio tracks`); logger.debug(`Stream has ${videoTracks.length} video tracks, ${audioTracks.length} audio tracks`);
if (videoTracks.length === 0) { if (videoTracks.length === 0) {
console.log('Audio-only stream, waiting for video track...'); logger.debug('Audio-only stream, waiting for video track...');
return; return;
} }
@@ -165,7 +168,7 @@ export function removeParticipantTile({
video.srcObject = null; video.srcObject = null;
} }
tile.remove(); tile.remove();
console.log(`Removed participant video tile for ${connectionId}`); logger.debug(`Removed participant video tile for ${connectionId}`);
} }
const remainingTiles = grid.querySelectorAll('[data-participant-id]'); const remainingTiles = grid.querySelectorAll('[data-participant-id]');

View File

@@ -23,6 +23,9 @@ import {
renderParticipantStreamMedia, renderParticipantStreamMedia,
renderSingleRemoteStreamMedia renderSingleRemoteStreamMedia
} from './renderer-media.js'; } from './renderer-media.js';
import { createLogger } from './logger.js';
const logger = createLogger('renderer');
const GRID_LAYOUT = { const GRID_LAYOUT = {
maxColumns: 3, maxColumns: 3,
@@ -317,13 +320,13 @@ class UIRenderer {
this.elements.localVideo.srcObject = stream; this.elements.localVideo.srcObject = stream;
this.elements.localVideo.autoplay = true; this.elements.localVideo.autoplay = true;
this.elements.localVideo.muted = true; this.elements.localVideo.muted = true;
console.log('srcObject set successfully:', this.elements.localVideo.srcObject); logger.debug('srcObject set successfully:', this.elements.localVideo.srcObject);
if (this.elements.disconnectedOverlay) { if (this.elements.disconnectedOverlay) {
this.elements.disconnectedOverlay.classList.add('hidden'); this.elements.disconnectedOverlay.classList.add('hidden');
} }
} else { } else {
console.error('Either localVideo element or stream is missing'); logger.error('Either localVideo element or stream is missing');
} }
} }
@@ -352,7 +355,7 @@ class UIRenderer {
const grid = this.elements.participantGrid; const grid = this.elements.participantGrid;
if (!grid) return; if (!grid) return;
updateParticipantTilePlaceholder(grid, participantId, showPlaceholder); updateParticipantTilePlaceholder(grid, participantId, showPlaceholder);
console.log(`Updated placeholder for participant ${participantId}: ${showPlaceholder ? 'shown' : 'hidden'}`); logger.debug(`Updated placeholder for participant ${participantId}: ${showPlaceholder ? 'shown' : 'hidden'}`);
} }
syncParticipantTileNames(participants) { syncParticipantTileNames(participants) {
@@ -369,7 +372,7 @@ class UIRenderer {
if (!grid) return; if (!grid) return;
syncParticipantTileName(grid, participantId, name); syncParticipantTileName(grid, participantId, name);
if (name) { if (name) {
console.log(`Updated tile name for participant ${participantId}: ${name}`); logger.debug(`Updated tile name for participant ${participantId}: ${name}`);
} }
} }
@@ -508,13 +511,13 @@ class UIRenderer {
} }
renderCallEnded() { renderCallEnded() {
console.log('Call ended'); logger.debug('Call ended');
clearParticipantGrid(this.elements.participantGrid); clearParticipantGrid(this.elements.participantGrid);
window.location.href = './endcall/endcall.html'; window.location.href = './endcall/endcall.html';
} }
renderParticipantLeft(connectionId) { renderParticipantLeft(connectionId) {
console.log(`Participant left: ${connectionId}, updating UI`); logger.debug(`Participant left: ${connectionId}, updating UI`);
removeParticipantTile({ removeParticipantTile({
grid: this.elements.participantGrid, grid: this.elements.participantGrid,
connectionId, connectionId,

View File

@@ -1,4 +1,7 @@
import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; import { Signaling, WebSocketSignaling } from "../../module/signaling.js";
import { createLogger } from './logger.js';
const logger = createLogger('signaling');
const INVITE_EVENT_NAMES = Object.freeze([ const INVITE_EVENT_NAMES = Object.freeze([
'invite-call', 'invite-call',
@@ -72,7 +75,7 @@ function readStoredSocketUserInfo() {
try { try {
return JSON.parse(localStorage.getItem('userSettings') || '{}'); return JSON.parse(localStorage.getItem('userSettings') || '{}');
} catch (error) { } catch (error) {
console.error('Error parsing user settings:', error); logger.error('Error parsing user settings:', error);
return {}; return {};
} }
} }

View File

@@ -8,6 +8,9 @@ import { AUDIO_CONFIG, VAD_CONFIG, VIDEO_ONLY_CONSTRAINT, buildVideoConstraints,
import { buildStatsLogPayload, createAudioAnalyser, getAudioLevel } from './media-monitoring.js'; import { buildStatsLogPayload, createAudioAnalyser, getAudioLevel } from './media-monitoring.js';
import { bindInviteSocketEvents, buildSocketUserInfoPayload, createSignalingInstance, ensureSignalingStarted, getActiveSignalingInstance, sendInviteSignal, sendSocketUserInfo } from './signaling-session.js'; import { bindInviteSocketEvents, buildSocketUserInfoPayload, createSignalingInstance, ensureSignalingStarted, getActiveSignalingInstance, sendInviteSignal, sendSocketUserInfo } from './signaling-session.js';
import { getNetworkQualityFromSummary, summarizeInboundStats } from './webrtc-stats.js'; import { getNetworkQualityFromSummary, summarizeInboundStats } from './webrtc-stats.js';
import { createLogger } from './logger.js';
const logger = createLogger('store');
class CallStateManager { class CallStateManager {
constructor() { constructor() {
this.state = { this.state = {
@@ -55,11 +58,11 @@ class CallStateManager {
} }
if (settings.resolution) { if (settings.resolution) {
this._savedResolution = settings.resolution; this._savedResolution = settings.resolution;
console.log(`已恢复分辨率设置: ${settings.resolution.width}x${settings.resolution.height}`); logger.debug(`已恢复分辨率设置: ${settings.resolution.width}x${settings.resolution.height}`);
} }
} }
catch (error) { catch (error) {
console.error('Error loading user settings:', error); logger.error('Error loading user settings:', error);
} }
} }
} }
@@ -69,9 +72,9 @@ class CallStateManager {
} }
async getLocalStream() { async getLocalStream() {
try { try {
console.log('Requesting camera permission...'); logger.debug('Requesting camera permission...');
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
console.error('getUserMedia is not supported'); logger.error('getUserMedia is not supported');
throw new Error('getUserMedia is not supported'); throw new Error('getUserMedia is not supported');
} }
const videoConstraints = buildVideoConstraints(this._savedResolution); const videoConstraints = buildVideoConstraints(this._savedResolution);
@@ -79,13 +82,13 @@ class CallStateManager {
video: videoConstraints, video: videoConstraints,
audio: AUDIO_CONFIG audio: AUDIO_CONFIG
}); });
console.log('Stream obtained successfully:', stream); logger.debug('Stream obtained successfully:', stream);
console.log('Video tracks:', stream.getVideoTracks()); logger.debug('Video tracks:', stream.getVideoTracks());
console.log('Audio tracks:', stream.getAudioTracks()); logger.debug('Audio tracks:', stream.getAudioTracks());
this.state.localStream = stream; this.state.localStream = stream;
this.state.session.localUser.mediaState.video = true; this.state.session.localUser.mediaState.video = true;
this.state.session.localUser.mediaState.audio = true; this.state.session.localUser.mediaState.audio = true;
console.log('Local stream stored, notifying UI...'); logger.debug('Local stream stored, notifying UI...');
this.notify({ type: 'LOCAL_STREAM_OBTAINED', stream }); this.notify({ type: 'LOCAL_STREAM_OBTAINED', stream });
this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: true }); this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'video', value: true });
this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: true }); this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: true });
@@ -93,7 +96,7 @@ class CallStateManager {
this.startActivityDetection(this.state.localStream, { isLocal: true }); this.startActivityDetection(this.state.localStream, { isLocal: true });
} }
catch (error) { catch (error) {
console.error('Error getting local stream:', error); logger.error('Error getting local stream:', error);
this.state.session.localUser.mediaState.video = false; this.state.session.localUser.mediaState.video = false;
this.state.session.localUser.mediaState.audio = 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: 'video', value: false });
@@ -133,7 +136,7 @@ class CallStateManager {
this.startActivityDetection(this.state.localStream, { isLocal: true }); this.startActivityDetection(this.state.localStream, { isLocal: true });
} }
catch (error) { catch (error) {
console.error('Error reopening video:', error); logger.error('Error reopening video:', error);
this.state.session.localUser.mediaState.video = false; this.state.session.localUser.mediaState.video = false;
this._notifyLocalMediaChange('video', false); this._notifyLocalMediaChange('video', false);
} }
@@ -162,7 +165,7 @@ class CallStateManager {
if (!this.renderstreaming) { if (!this.renderstreaming) {
return; return;
} }
console.log('Updating video track in WebRTC connection'); logger.debug('Updating video track in WebRTC connection');
if (this.role === 'host') { if (this.role === 'host') {
const participantIds = Object.keys(this.state.remoteStreams); const participantIds = Object.keys(this.state.remoteStreams);
for (const participantId of participantIds) { for (const participantId of participantIds) {
@@ -190,12 +193,12 @@ class CallStateManager {
for (const transceiver of videoTransceivers) { for (const transceiver of videoTransceivers) {
try { try {
await transceiver.sender.replaceTrack(newVideoTrack); await transceiver.sender.replaceTrack(newVideoTrack);
console.log(participantId logger.debug(participantId
? `Replaced video track for participant ${participantId}` ? `Replaced video track for participant ${participantId}`
: 'Successfully replaced video track'); : 'Successfully replaced video track');
} }
catch (error) { catch (error) {
console.error(participantId logger.error(participantId
? `Error replacing video track for ${participantId}:` ? `Error replacing video track for ${participantId}:`
: 'Error replacing video track:', error); : 'Error replacing video track:', error);
} }
@@ -205,14 +208,14 @@ class CallStateManager {
try { try {
if (participantId) { if (participantId) {
this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }, participantId); this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }, participantId);
console.log(`Added new video transceiver for participant ${participantId}`); logger.debug(`Added new video transceiver for participant ${participantId}`);
return; return;
} }
this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' }); this.renderstreaming.addTransceiver(newVideoTrack, { direction: 'sendonly' });
console.log('Added new video transceiver'); logger.debug('Added new video transceiver');
} }
catch (error) { catch (error) {
console.error(participantId logger.error(participantId
? `Error adding video transceiver for ${participantId}:` ? `Error adding video transceiver for ${participantId}:`
: 'Error adding video transceiver:', error); : 'Error adding video transceiver:', error);
} }
@@ -262,10 +265,10 @@ class CallStateManager {
this._signaling = signaling; this._signaling = signaling;
this._inviteEventSignaling = bindInviteSocketEvents(this._signaling, this.socketEventHandlers, this._inviteEventSignaling); this._inviteEventSignaling = bindInviteSocketEvents(this._signaling, this.socketEventHandlers, this._inviteEventSignaling);
if (reused) { if (reused) {
console.log('Signaling already connected, reusing existing instance'); logger.debug('Signaling already connected, reusing existing instance');
return this._signaling; return this._signaling;
} }
console.log('Signaling connected (WebSocket only, no room yet)'); logger.debug('Signaling connected (WebSocket only, no room yet)');
return this._signaling; return this._signaling;
} }
getActiveSignaling() { getActiveSignaling() {
@@ -295,7 +298,7 @@ class CallStateManager {
this.state.session.status = 'connecting'; this.state.session.status = 'connecting';
this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' }); this.notify({ type: 'CALL_STATUS_CHANGE', status: 'connecting' });
if (!this.state.localStream) { if (!this.state.localStream) {
console.log('Local stream not available, waiting for initialization...'); logger.debug('Local stream not available, waiting for initialization...');
await new Promise((resolve) => { await new Promise((resolve) => {
const checkStream = () => { const checkStream = () => {
if (this.state.localStream) { if (this.state.localStream) {
@@ -320,7 +323,7 @@ class CallStateManager {
} }
_registerCallbacks() { _registerCallbacks() {
this.renderstreaming.onNewPeer = (participantId) => { this.renderstreaming.onNewPeer = (participantId) => {
console.log(`New peer created for ${participantId}, adding local tracks`); logger.debug(`New peer created for ${participantId}, adding local tracks`);
if (this.state.localStream) { if (this.state.localStream) {
const tracks = this.state.localStream.getTracks(); const tracks = this.state.localStream.getTracks();
for (const track of tracks) { for (const track of tracks) {
@@ -337,7 +340,7 @@ class CallStateManager {
if (data.participantId) { if (data.participantId) {
this.selfParticipantId = data.participantId; this.selfParticipantId = data.participantId;
} }
console.log(`Connected as ${this.role}, participantId: ${this.selfParticipantId}`); logger.debug(`Connected as ${this.role}, participantId: ${this.selfParticipantId}`);
} }
this.state.session.status = 'ongoing'; this.state.session.status = 'ongoing';
this.notify({ type: 'CALL_STATUS_CHANGE', status: 'ongoing' }); this.notify({ type: 'CALL_STATUS_CHANGE', status: 'ongoing' });
@@ -349,7 +352,7 @@ class CallStateManager {
} }
this.state.session.localUser.mediaState.audio = false; this.state.session.localUser.mediaState.audio = false;
this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: false }); this.notify({ type: 'LOCAL_MEDIA_CHANGE', mediaType: 'audio', value: false });
console.log('Participant joined with audio muted by default'); logger.debug('Participant joined with audio muted by default');
} }
this.sendMessage('user-info', { this.sendMessage('user-info', {
id: this.state.session.localUser.id, id: this.state.session.localUser.id,
@@ -361,16 +364,16 @@ class CallStateManager {
this.showStatsMessage(); this.showStatsMessage();
} }
else { else {
console.error('Local stream is not available'); logger.error('Local stream is not available');
showNotification('本地视频流不可用', 'error'); showNotification('本地视频流不可用', 'error');
} }
}; };
this.renderstreaming.onDisconnect = () => { this.renderstreaming.onDisconnect = () => {
console.log('Received disconnect from server, host left or room closed'); logger.debug('Received disconnect from server, host left or room closed');
this.hangUp(); this.hangUp();
}; };
this.renderstreaming.onGotAnswer = (connectionId) => { this.renderstreaming.onGotAnswer = (connectionId) => {
console.log('SDP Answer received, resetting encoding parameters for connectionId:', connectionId); logger.debug('SDP Answer received, resetting encoding parameters for connectionId:', connectionId);
if (this.role === 'host') { if (this.role === 'host') {
const allParticipantIds = Object.keys(this.state.remoteStreams || {}); const allParticipantIds = Object.keys(this.state.remoteStreams || {});
for (const pid of allParticipantIds) { for (const pid of allParticipantIds) {
@@ -382,13 +385,13 @@ class CallStateManager {
} }
}; };
this.renderstreaming.onParticipantJoined = (participantId) => { this.renderstreaming.onParticipantJoined = (participantId) => {
console.log(`Participant joined: ${participantId}`); logger.debug(`Participant joined: ${participantId}`);
this._upsertParticipant(participantId); this._upsertParticipant(participantId);
this._notifyParticipantsUpdate(); this._notifyParticipantsUpdate();
this.broadcastParticipantsList(); this.broadcastParticipantsList();
}; };
this.renderstreaming.onParticipantLeft = (participantId) => { this.renderstreaming.onParticipantLeft = (participantId) => {
console.log(`Participant left: ${participantId}, room still active`); logger.debug(`Participant left: ${participantId}, room still active`);
this.updateRemoteUserStatus('offline'); this.updateRemoteUserStatus('offline');
this.updateRemoteUserNetworkQuality('no_signal'); this.updateRemoteUserNetworkQuality('no_signal');
showNotification('对方已离开通话', 'warning'); showNotification('对方已离开通话', 'warning');
@@ -428,14 +431,14 @@ class CallStateManager {
} }
this.durationSynced = false; this.durationSynced = false;
const isHost = this.role === 'host'; const isHost = this.role === 'host';
console.log(`Disconnect peer on ${this.connectionId}. Role: ${this.role}`); logger.debug(`Disconnect peer on ${this.connectionId}. Role: ${this.role}`);
if (this.renderstreaming) { if (this.renderstreaming) {
try { try {
await this.renderstreaming.deleteConnection(); await this.renderstreaming.deleteConnection();
await this.renderstreaming.stop(); await this.renderstreaming.stop();
} }
catch (error) { catch (error) {
console.error('Error during hangUp:', error); logger.error('Error during hangUp:', error);
} }
this.renderstreaming = null; this.renderstreaming = null;
} }
@@ -463,7 +466,7 @@ class CallStateManager {
const isHost = this.role === 'host'; const isHost = this.role === 'host';
const targetStream = this._getOrCreateRemoteStream(trackParticipantId, isHost); const targetStream = this._getOrCreateRemoteStream(trackParticipantId, isHost);
this._replaceTrackOfSameKind(targetStream, data.track); this._replaceTrackOfSameKind(targetStream, data.track);
console.log('Added new track:', data.track.kind, 'for participant:', trackParticipantId); logger.debug('Added new track:', data.track.kind, 'for participant:', trackParticipantId);
if (isHost && !this.state.participants[trackParticipantId]) { if (isHost && !this.state.participants[trackParticipantId]) {
this._upsertParticipant(trackParticipantId); this._upsertParticipant(trackParticipantId);
this._notifyParticipantsUpdate(); this._notifyParticipantsUpdate();
@@ -500,7 +503,7 @@ class CallStateManager {
const existingTracks = targetStream.getTracks().filter(existingTrack => existingTrack.kind === track.kind); const existingTracks = targetStream.getTracks().filter(existingTrack => existingTrack.kind === track.kind);
existingTracks.forEach(existingTrack => { existingTracks.forEach(existingTrack => {
targetStream.removeTrack(existingTrack); targetStream.removeTrack(existingTrack);
console.log('Removed old track:', existingTrack.kind); logger.debug('Removed old track:', existingTrack.kind);
}); });
targetStream.addTrack(track); targetStream.addTrack(track);
} }
@@ -512,13 +515,13 @@ class CallStateManager {
connectionId: trackParticipantId, connectionId: trackParticipantId,
isHost isHost
}); });
console.log('Notified UI about remote stream update'); logger.debug('Notified UI about remote stream update');
}; };
if (trackKind === 'audio' && targetStream.getVideoTracks().length === 0) { if (trackKind === 'audio' && targetStream.getVideoTracks().length === 0) {
console.log('Audio track arrived first, delaying stream notification for video track...'); logger.debug('Audio track arrived first, delaying stream notification for video track...');
setTimeout(() => { setTimeout(() => {
const nowHasVideo = targetStream.getVideoTracks().length > 0; const nowHasVideo = targetStream.getVideoTracks().length > 0;
console.log(`After delay, stream has video: ${nowHasVideo}`); logger.debug(`After delay, stream has video: ${nowHasVideo}`);
notifyStreamUpdate(); notifyStreamUpdate();
}, 200); }, 200);
return; return;
@@ -526,7 +529,7 @@ class CallStateManager {
notifyStreamUpdate(); notifyStreamUpdate();
} }
_handleRenderStreamingMessage(data) { _handleRenderStreamingMessage(data) {
console.log('收到信令消息:', data); logger.debug('收到信令消息:', data);
switch (data.type) { switch (data.type) {
case 'chat-message': case 'chat-message':
this._handleChatMessage(data); this._handleChatMessage(data);
@@ -578,7 +581,7 @@ class CallStateManager {
} }
} }
_handleMediaStateChangedMessage(data) { _handleMediaStateChangedMessage(data) {
console.log('收到媒体状态更新:', data.data, 'from participant:', data.participantId); logger.debug('收到媒体状态更新:', data.data, 'from participant:', data.participantId);
if (this.role === 'host') { if (this.role === 'host') {
if (data.participantId && this.state.participants[data.participantId]) { if (data.participantId && this.state.participants[data.participantId]) {
this._upsertParticipant(data.participantId, { this._upsertParticipant(data.participantId, {
@@ -600,12 +603,12 @@ class CallStateManager {
if (data.participantId === this.selfParticipantId) { if (data.participantId === this.selfParticipantId) {
return; return;
} }
console.log('Received media-state-changed from Host, updating remoteUser:', data.data); logger.debug('Received media-state-changed from Host, updating remoteUser:', data.data);
this.updateRemoteMedia(data.data, data.participantId); this.updateRemoteMedia(data.data, data.participantId);
this._notifyParticipantsUpdate(); this._notifyParticipantsUpdate();
} }
_handleUserInfoMessage(data) { _handleUserInfoMessage(data) {
console.log('收到用户信息:', data.data, 'from participant:', data.participantId); logger.debug('收到用户信息:', data.data, 'from participant:', data.participantId);
if (!data.data) { if (!data.data) {
return; return;
} }
@@ -629,7 +632,7 @@ class CallStateManager {
if (this.role === 'host' || !data.data) { if (this.role === 'host' || !data.data) {
return; return;
} }
console.log('收到成员同步列表:', data.data); logger.debug('收到成员同步列表:', data.data);
this.state.participants = omitParticipant(data.data, this.selfParticipantId); this.state.participants = omitParticipant(data.data, this.selfParticipantId);
this._notifyParticipantsUpdate(); this._notifyParticipantsUpdate();
this._syncCallDuration(data.callDuration); this._syncCallDuration(data.callDuration);
@@ -646,7 +649,7 @@ class CallStateManager {
this.durationSynced = true; this.durationSynced = true;
this._startDurationTimer(); this._startDurationTimer();
this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration }); this.notify({ type: 'DURATION_UPDATE', duration: this.state.session.duration });
console.log(`Call duration synced: ${callDuration} seconds`); logger.debug(`Call duration synced: ${callDuration} seconds`);
} }
_startDurationTimer() { _startDurationTimer() {
if (this.durationInterval) { if (this.durationInterval) {
@@ -706,7 +709,7 @@ class CallStateManager {
data: memberList, data: memberList,
callDuration: this.state.session.duration callDuration: this.state.session.duration
}); });
console.log('Broadcast participants list:', Object.keys(memberList)); logger.debug('Broadcast participants list:', Object.keys(memberList));
} }
setCodecPreferences(participantId) { setCodecPreferences(participantId) {
const capabilities = RTCRtpSender.getCapabilities('video'); const capabilities = RTCRtpSender.getCapabilities('video');
@@ -744,10 +747,10 @@ class CallStateManager {
t.setCodecPreferences(selectedCodecs); t.setCodecPreferences(selectedCodecs);
} }
catch (e) { catch (e) {
console.error('Error setting codec preferences:', e); logger.error('Error setting codec preferences:', e);
} }
}); });
console.log(`Codec preferences set: ${selectedCodecs.map(c => c.mimeType).join(' > ')}`); logger.debug(`Codec preferences set: ${selectedCodecs.map(c => c.mimeType).join(' > ')}`);
} }
} }
} }
@@ -777,10 +780,10 @@ class CallStateManager {
params.degradationPreference = 'maintain-resolution'; params.degradationPreference = 'maintain-resolution';
} }
sender.setParameters(params); sender.setParameters(params);
console.log(`Set video encoding: maxBitrate=${maxBitrate / 1000000}Mbps, scaleResolutionDownBy=1.0, xGoogleMinBitrate=${Math.floor(maxBitrate * 0.5)}${participantId ? ` for ${participantId}` : ''}`); logger.debug(`Set video encoding: maxBitrate=${maxBitrate / 1000000}Mbps, scaleResolutionDownBy=1.0, xGoogleMinBitrate=${Math.floor(maxBitrate * 0.5)}${participantId ? ` for ${participantId}` : ''}`);
} }
catch (error) { catch (error) {
console.error('Error setting video encoding parameters:', error); logger.error('Error setting video encoding parameters:', error);
} }
} }
} }
@@ -802,7 +805,7 @@ class CallStateManager {
height: { ideal: height, max: height }, height: { ideal: height, max: height },
frameRate: { ideal: 30, max: 30 } frameRate: { ideal: 30, max: 30 }
}); });
console.log(`分辨率已切换为 ${width}x${height}`); logger.debug(`分辨率已切换为 ${width}x${height}`);
const maxBitrate = getTargetResolutionBitrate(height); const maxBitrate = getTargetResolutionBitrate(height);
this._applyMaxBitrate(maxBitrate); this._applyMaxBitrate(maxBitrate);
const userSettings = JSON.parse(localStorage.getItem('userSettings') || '{}'); const userSettings = JSON.parse(localStorage.getItem('userSettings') || '{}');
@@ -812,7 +815,7 @@ class CallStateManager {
showNotification('已切换为 ' + label, 'success'); showNotification('已切换为 ' + label, 'success');
} }
catch (error) { catch (error) {
console.error('切换分辨率失败:', error); logger.error('切换分辨率失败:', error);
showNotification('切换分辨率失败,摄像头可能不支持该分辨率', 'error'); showNotification('切换分辨率失败,摄像头可能不支持该分辨率', 'error');
} }
} }
@@ -835,10 +838,10 @@ class CallStateManager {
} }
params.encodings[0].maxBitrate = maxBitrate; params.encodings[0].maxBitrate = maxBitrate;
sender.setParameters(params); sender.setParameters(params);
console.log(`Updated maxBitrate to ${maxBitrate} for ${pid || 'self'}`); logger.debug(`Updated maxBitrate to ${maxBitrate} for ${pid || 'self'}`);
} }
catch (error) { catch (error) {
console.error('Error updating maxBitrate:', error); logger.error('Error updating maxBitrate:', error);
} }
} }
} }
@@ -865,7 +868,7 @@ class CallStateManager {
this.updateRemoteMedia({ isSpeaking }); this.updateRemoteMedia({ isSpeaking });
} }
async endCall() { async endCall() {
console.log(`endCall called. Role: ${this.role}`); logger.debug(`endCall called. Role: ${this.role}`);
await this.hangUp(); await this.hangUp();
} }
async joinCall(connectionId) { async joinCall(connectionId) {
@@ -898,7 +901,7 @@ class CallStateManager {
} }
} }
catch (error) { catch (error) {
console.error('Error detecting network quality:', error); logger.error('Error detecting network quality:', error);
} }
} }
startActivityDetection(stream, { isLocal = false } = {}) { startActivityDetection(stream, { isLocal = false } = {}) {
@@ -936,10 +939,10 @@ class CallStateManager {
} }
}; };
detectActivity(); detectActivity();
console.log(`${isLocal ? 'Local' : 'Remote'} activity detection started`); logger.debug(`${isLocal ? 'Local' : 'Remote'} activity detection started`);
} }
catch (error) { catch (error) {
console.error(`Error starting ${isLocal ? 'local' : 'remote'} activity detection:`, error); logger.error(`Error starting ${isLocal ? 'local' : 'remote'} activity detection:`, error);
} }
} }
startNetworkQualityDetection() { startNetworkQualityDetection() {
@@ -958,7 +961,7 @@ class CallStateManager {
userId: this.state.session.localUser.id, userId: this.state.session.localUser.id,
...this.state.session.localUser.mediaState ...this.state.session.localUser.mediaState
}; };
console.log('[WebSocket Emit] media-state-changed:', payload); logger.debug('[WebSocket Emit] media-state-changed:', payload);
if (this.renderstreaming) { if (this.renderstreaming) {
this.renderstreaming.sendMessage({ this.renderstreaming.sendMessage({
type: 'media-state-changed', type: 'media-state-changed',
@@ -967,7 +970,7 @@ class CallStateManager {
} }
} }
async showStatsMessage() { async showStatsMessage() {
console.log('Showing stats message'); logger.debug('Showing stats message');
await this.detectNetworkQuality(); await this.detectNetworkQuality();
this.statsInterval = setInterval(async () => { this.statsInterval = setInterval(async () => {
if (!this.renderstreaming) { if (!this.renderstreaming) {
@@ -980,19 +983,19 @@ class CallStateManager {
} }
const statsSummary = summarizeInboundStats(stats); const statsSummary = summarizeInboundStats(stats);
const statsLog = buildStatsLogPayload(this.state.session.remoteUser.networkQuality, statsSummary); const statsLog = buildStatsLogPayload(this.state.session.remoteUser.networkQuality, statsSummary);
console.log('=== WebRTC Statistics ==='); logger.debug('=== WebRTC Statistics ===');
console.log(`Network Quality: ${statsLog.networkQuality}`); logger.debug(`Network Quality: ${statsLog.networkQuality}`);
console.log('Video Stats:', statsLog.video); logger.debug('Video Stats:', statsLog.video);
console.log('Audio Stats:', statsLog.audio); logger.debug('Audio Stats:', statsLog.audio);
console.log('========================'); logger.debug('========================');
} }
catch (error) { catch (error) {
console.error('Error showing stats message:', error); logger.error('Error showing stats message:', error);
} }
}, 5000); }, 5000);
} }
clearStatsMessage() { clearStatsMessage() {
console.log('Clearing stats message'); logger.debug('Clearing stats message');
if (this.statsInterval) { if (this.statsInterval) {
clearInterval(this.statsInterval); clearInterval(this.statsInterval);
this.statsInterval = null; this.statsInterval = null;

File diff suppressed because it is too large Load Diff