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 - 消息数据
*/
function handleChatMessage(data) {
console.log('处理聊天:', data);
logger.debug('处理聊天:', data);
addMessage(data);
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();
displayConnectionIds(data.connectionIds);
} catch (error) {
console.error('Error fetching connection IDs:', error);
logger.error('Error fetching connection IDs:', error);
showNotification('获取连接ID失败', 'error');
}
}
@@ -164,7 +167,7 @@ function loadUserSettings() {
document.getElementById('userAvatar').src = avatar;
document.getElementById('avatarPreview').src = avatar;
} catch (error) {
console.error('Error loading user settings:', error);
logger.error('Error loading user settings:', error);
// 加载失败时使用默认头像
const defaultAvatar = '/images/p1.png';
document.getElementById('userAvatar').src = defaultAvatar;
@@ -254,7 +257,7 @@ function handleAvatarUpload(event) {
}
})
.catch(error => {
console.error('Error uploading avatar:', error);
logger.error('Error uploading avatar:', error);
showNotification('头像上传失败,请重试', 'error');
// 上传失败时,使用默认头像

View File

@@ -7,6 +7,9 @@ import {
renderOnlineUsers
} from './connect-directory.js';
import { createProfileSettingsController } from './profile-settings.js';
import { createLogger } from './logger.js';
const logger = createLogger('connectview');
let onWsStatusChange = null;
let cachedOnlineUsers = [];
@@ -45,9 +48,9 @@ export async function initWebSocket() {
store.syncSocketUserInfo();
updateWsStatus(true);
await refreshOnlineUsers();
console.log('WebSocket initialized from connectview');
logger.debug('WebSocket initialized from connectview');
} catch (error) {
console.error('Failed to initialize WebSocket:', error);
logger.error('Failed to initialize WebSocket:', error);
updateWsStatus(false);
showNotification('WebSocket连接失败请刷新页面重试', 'error');
}
@@ -62,7 +65,7 @@ async function refreshOnlineUsers(silent = true) {
showNotification(`当前共有 ${cachedOnlineUsers.length} 个WebSocket用户在线`);
}
} catch (error) {
console.error('Error fetching online users:', error);
logger.error('Error fetching online users:', error);
if (!silent) {
showNotification('获取在线用户失败', 'error');
}
@@ -78,7 +81,7 @@ async function getAllConnectionIds() {
updateConnectionIdList(connectionIds);
updateOnlineUsersList(cachedOnlineUsers);
} catch (error) {
console.error('Error fetching connection IDs:', error);
logger.error('Error fetching connection IDs:', error);
showNotification('获取连接信息失败', 'error');
}
}
@@ -104,7 +107,7 @@ function getCurrentUserId() {
const settings = JSON.parse(localStorage.getItem('userSettings') || '{}');
return settings.userId || settings.id || '';
} catch (error) {
console.error('Error parsing current user settings:', error);
logger.error('Error parsing current user settings:', error);
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_AVATAR = '/images/p2.png';
const DEFAULT_APPLY_REASON = '\u672a\u586b\u5199';
@@ -127,7 +130,7 @@ export function createInviteController({
targetUserId: pendingInvite.inviterUserId
});
} 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');
return;
}
@@ -152,7 +155,7 @@ export function createInviteController({
targetUserId: pendingInvite.inviterUserId
});
} 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
} from './connectview.js';
import { createInviteController } from './invite-controller.js';
import { createLogger } from './logger.js';
const logger = createLogger('main');
let connectionId = '';
let currentView = 'connect';
@@ -43,10 +46,10 @@ async function switchToCallView(targetConnectionId) {
renderer.renderHeaderTitle();
callViewController.bindDomEvents();
console.log('Video call app initialized successfully');
logger.debug('Video call app initialized successfully');
return true;
} catch (error) {
console.error('Error initializing app:', error);
logger.error('Error initializing app:', error);
showNotification('初始化失败,请刷新页面重试', 'error');
return false;
}
@@ -116,9 +119,9 @@ window.addEventListener('DOMContentLoaded', async () => {
inviteController.showCallRequestDialog(invitePayload);
}
console.log('SPA initialized, showing connect view');
logger.debug('SPA initialized, showing connect view');
} catch (error) {
console.error('Error initializing SPA:', error);
logger.error('Error initializing SPA:', 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 MAX_AVATAR_SIZE = 2 * 1024 * 1024;
const USER_ID_PREFIX = 'user_';
@@ -100,7 +103,7 @@ export function createProfileSettingsController({ store, notify }) {
updateUserName(settings.name || '\u6211');
setAvatarPreview(settings.avatar || DEFAULT_AVATAR);
} catch (error) {
console.error('Error loading user settings:', error);
logger.error('Error loading user settings:', error);
setAvatarPreview(DEFAULT_AVATAR);
}
}
@@ -152,7 +155,7 @@ export function createProfileSettingsController({ store, notify }) {
saveSettings();
notify('\u5934\u50cf\u4e0a\u4f20\u6210\u529f', 'success');
} catch (error) {
console.error('Error uploading avatar:', error);
logger.error('Error uploading avatar:', error);
setAvatarPreview(DEFAULT_AVATAR);
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 { createLogger } from './logger.js';
const logger = createLogger('renderer-media');
export function getVideoResolution(track) {
if (track && track.getSettings) {
@@ -47,18 +50,18 @@ export function renderParticipantStreamMedia({
if (!tile) {
tile = createParticipantTile(connectionId, displayName);
grid.appendChild(tile);
console.log(`Created participant video tile for ${connectionId}`);
logger.debug(`Created participant video tile for ${connectionId}`);
}
const video = tile.querySelector('video');
if (video && stream) {
if (video.srcObject === stream) {
console.log(`Same stream for participant ${connectionId}, ensuring playback`);
video.play().catch(error => console.log('Auto-play prevented:', error.message));
logger.debug(`Same stream for participant ${connectionId}, ensuring playback`);
video.play().catch(error => logger.debug('Auto-play prevented:', error.message));
} else {
video.srcObject = stream;
video.play().catch(error => console.log('Auto-play prevented:', error.message));
console.log(`Set remote stream for participant tile ${connectionId}`);
video.play().catch(error => logger.debug('Auto-play prevented:', error.message));
logger.debug(`Set remote stream for participant tile ${connectionId}`);
}
}
@@ -86,15 +89,15 @@ export function renderSingleRemoteStreamMedia({
connectingOverlay
}) {
if (!remoteVideo || !stream) {
console.error('Either remoteVideo element or stream is missing');
logger.error('Either remoteVideo element or stream is missing');
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) {
console.log('Same stream object, track added - ensuring playback');
remoteVideo.play().catch(error => console.log('Auto-play prevented:', error.message));
logger.debug('Same stream object, track added - ensuring playback');
remoteVideo.play().catch(error => logger.debug('Auto-play prevented:', error.message));
return;
}
@@ -103,7 +106,7 @@ export function renderSingleRemoteStreamMedia({
remoteVideo.playsinline = true;
remoteVideo.muted = false;
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) {
@@ -112,10 +115,10 @@ export function renderSingleRemoteStreamMedia({
const videoTracks = stream.getVideoTracks();
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) {
console.log('Audio-only stream, waiting for video track...');
logger.debug('Audio-only stream, waiting for video track...');
return;
}
@@ -165,7 +168,7 @@ export function removeParticipantTile({
video.srcObject = null;
}
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]');

View File

@@ -23,6 +23,9 @@ import {
renderParticipantStreamMedia,
renderSingleRemoteStreamMedia
} from './renderer-media.js';
import { createLogger } from './logger.js';
const logger = createLogger('renderer');
const GRID_LAYOUT = {
maxColumns: 3,
@@ -317,13 +320,13 @@ class UIRenderer {
this.elements.localVideo.srcObject = stream;
this.elements.localVideo.autoplay = 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) {
this.elements.disconnectedOverlay.classList.add('hidden');
}
} 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;
if (!grid) return;
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) {
@@ -369,7 +372,7 @@ class UIRenderer {
if (!grid) return;
syncParticipantTileName(grid, participantId, 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() {
console.log('Call ended');
logger.debug('Call ended');
clearParticipantGrid(this.elements.participantGrid);
window.location.href = './endcall/endcall.html';
}
renderParticipantLeft(connectionId) {
console.log(`Participant left: ${connectionId}, updating UI`);
logger.debug(`Participant left: ${connectionId}, updating UI`);
removeParticipantTile({
grid: this.elements.participantGrid,
connectionId,

View File

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

File diff suppressed because it is too large Load Diff