优化目录结构
This commit is contained in:
191
client/public/call/media/renderer-media.js
Normal file
191
client/public/call/media/renderer-media.js
Normal file
@@ -0,0 +1,191 @@
|
||||
import { createParticipantTile, getParticipantTile } from '../participants/renderer-participant-grid.js';
|
||||
import { createLogger } from '../../shared/logger.js';
|
||||
|
||||
const logger = createLogger('renderer-media');
|
||||
|
||||
export function getVideoResolution(track) {
|
||||
if (track && track.getSettings) {
|
||||
const settings = track.getSettings();
|
||||
return {
|
||||
width: settings.width || 640,
|
||||
height: settings.height || 480
|
||||
};
|
||||
}
|
||||
|
||||
return { width: 640, height: 480 };
|
||||
}
|
||||
|
||||
export function adjustVideoSize(videoElement) {
|
||||
if (!videoElement) return;
|
||||
|
||||
const container = videoElement.parentElement;
|
||||
if (!container) return;
|
||||
|
||||
videoElement.style.transform = 'translateZ(0)';
|
||||
videoElement.style.willChange = 'transform';
|
||||
container.style.display = 'flex';
|
||||
container.style.alignItems = 'center';
|
||||
container.style.justifyContent = 'center';
|
||||
videoElement.style.imageRendering = 'auto';
|
||||
videoElement.style.maxWidth = '100%';
|
||||
videoElement.style.maxHeight = '100%';
|
||||
videoElement.style.objectFit = 'contain';
|
||||
}
|
||||
|
||||
export function renderParticipantStreamMedia({
|
||||
grid,
|
||||
stream,
|
||||
connectionId,
|
||||
displayName,
|
||||
getGridTemplateColumns,
|
||||
remoteVideo,
|
||||
connectingOverlay,
|
||||
remoteVideoPlaceholder
|
||||
}) {
|
||||
if (!grid) return;
|
||||
|
||||
grid.classList.remove('hidden');
|
||||
|
||||
let tile = getParticipantTile(grid, connectionId);
|
||||
if (!tile) {
|
||||
tile = createParticipantTile(connectionId, displayName);
|
||||
grid.appendChild(tile);
|
||||
logger.debug(`Created participant video tile for ${connectionId}`);
|
||||
}
|
||||
|
||||
const video = tile.querySelector('video');
|
||||
if (video && stream) {
|
||||
if (video.srcObject === stream) {
|
||||
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 => logger.debug('Auto-play prevented:', error.message));
|
||||
logger.debug(`Set remote stream for participant tile ${connectionId}`);
|
||||
}
|
||||
}
|
||||
|
||||
const remoteVideoContainer = remoteVideo?.closest('.absolute.inset-0.video-fade-in');
|
||||
if (remoteVideoContainer) {
|
||||
remoteVideoContainer.classList.add('hidden');
|
||||
}
|
||||
|
||||
const tileCount = grid.querySelectorAll('[data-participant-id]').length;
|
||||
grid.style.gridTemplateColumns = getGridTemplateColumns(tileCount);
|
||||
|
||||
if (connectingOverlay) {
|
||||
connectingOverlay.classList.add('hidden');
|
||||
}
|
||||
if (remoteVideoPlaceholder) {
|
||||
remoteVideoPlaceholder.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
export function renderSingleRemoteStreamMedia({
|
||||
remoteVideo,
|
||||
stream,
|
||||
disconnectedOverlay,
|
||||
remoteVideoPlaceholder,
|
||||
connectingOverlay
|
||||
}) {
|
||||
if (!remoteVideo || !stream) {
|
||||
logger.error('Either remoteVideo element or stream is missing');
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug('Rendering remote stream:', stream, 'tracks:', stream.getTracks().map(track => `${track.kind}(${track.readyState})`));
|
||||
|
||||
if (remoteVideo.srcObject === stream) {
|
||||
logger.debug('Same stream object, track added - ensuring playback');
|
||||
remoteVideo.play().catch(error => logger.debug('Auto-play prevented:', error.message));
|
||||
return;
|
||||
}
|
||||
|
||||
remoteVideo.srcObject = stream;
|
||||
remoteVideo.autoplay = true;
|
||||
remoteVideo.playsinline = true;
|
||||
remoteVideo.muted = false;
|
||||
remoteVideo.play().catch(error => {
|
||||
logger.debug('Auto-play prevented, will retry on interaction:', error.message);
|
||||
});
|
||||
|
||||
if (disconnectedOverlay) {
|
||||
disconnectedOverlay.classList.add('hidden');
|
||||
}
|
||||
|
||||
const videoTracks = stream.getVideoTracks();
|
||||
const audioTracks = stream.getAudioTracks();
|
||||
logger.debug(`Stream has ${videoTracks.length} video tracks, ${audioTracks.length} audio tracks`);
|
||||
|
||||
if (videoTracks.length === 0) {
|
||||
logger.debug('Audio-only stream, waiting for video track...');
|
||||
return;
|
||||
}
|
||||
|
||||
if (remoteVideoPlaceholder) {
|
||||
remoteVideoPlaceholder.classList.add('hidden');
|
||||
}
|
||||
if (connectingOverlay) {
|
||||
connectingOverlay.classList.add('hidden');
|
||||
}
|
||||
|
||||
const activeVideoTrack = videoTracks.find(track => track.readyState === 'live');
|
||||
if (!activeVideoTrack) return;
|
||||
|
||||
adjustVideoSize(remoteVideo, getVideoResolution(activeVideoTrack));
|
||||
activeVideoTrack.addEventListener('resize', () => {
|
||||
adjustVideoSize(remoteVideo, getVideoResolution(activeVideoTrack));
|
||||
});
|
||||
}
|
||||
|
||||
export function clearParticipantGrid(grid) {
|
||||
if (!grid) return;
|
||||
|
||||
grid.querySelectorAll('[data-participant-id]').forEach(tile => {
|
||||
const video = tile.querySelector('video');
|
||||
if (video) {
|
||||
video.srcObject = null;
|
||||
}
|
||||
tile.remove();
|
||||
});
|
||||
grid.classList.add('hidden');
|
||||
}
|
||||
|
||||
export function removeParticipantTile({
|
||||
grid,
|
||||
connectionId,
|
||||
getGridTemplateColumns,
|
||||
remoteVideo,
|
||||
remoteVideoPlaceholder,
|
||||
remoteNetworkIndicator
|
||||
}) {
|
||||
if (!grid) return;
|
||||
|
||||
const tile = getParticipantTile(grid, connectionId);
|
||||
if (tile) {
|
||||
const video = tile.querySelector('video');
|
||||
if (video) {
|
||||
video.srcObject = null;
|
||||
}
|
||||
tile.remove();
|
||||
logger.debug(`Removed participant video tile for ${connectionId}`);
|
||||
}
|
||||
|
||||
const remainingTiles = grid.querySelectorAll('[data-participant-id]');
|
||||
if (remainingTiles.length === 0) {
|
||||
grid.classList.add('hidden');
|
||||
const remoteVideoContainer = remoteVideo?.closest('.absolute.inset-0.video-fade-in');
|
||||
if (remoteVideoContainer) {
|
||||
remoteVideoContainer.classList.remove('hidden');
|
||||
}
|
||||
if (remoteVideoPlaceholder) {
|
||||
remoteVideoPlaceholder.classList.remove('hidden');
|
||||
}
|
||||
} else {
|
||||
grid.style.gridTemplateColumns = getGridTemplateColumns(remainingTiles.length);
|
||||
}
|
||||
|
||||
if (remoteNetworkIndicator) {
|
||||
remoteNetworkIndicator.className = 'w-2 h-2 bg-gray-500 rounded-full';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user