diff --git a/web/player.html b/web/player.html index 87c7679..bf41a13 100644 --- a/web/player.html +++ b/web/player.html @@ -255,23 +255,32 @@ const hls = new Hls({ maxBufferLength: 120, enableWorker: true, - liveSyncDurationCount: 6, // Slightly more buffer for micro-cut protection - nudgeOffset: 0.6, // More aggressive jump over corrupted frames - nudgeMaxRetries: 25, - maxLiveSyncPlaybackRate: 1.15, - // Turbo-Start specific - startLevel: 0, - initialLiveManifestSize: 1, - abrEwmaDefaultEstimate: 700000, - manifestLoadingRetryDelay: 500, - levelLoadingRetryDelay: 500 + liveSyncDurationCount: 10, // Buffer-First: 10 segments safety margin + liveMaxLatencyDurationCount: 20, + nudgeOffset: 0.8, // More aggressive jump over corrupted frames + nudgeMaxRetries: 30, + maxLiveSyncPlaybackRate: 1.1, // Slower catch-up to avoid chaos + // Stabilization + initialLiveManifestSize: 3, // Wait for more segments before starting + abrEwmaDefaultEstimate: 1000000, + manifestLoadingRetryDelay: 1000, + levelLoadingRetryDelay: 1000 }); window.hlsInstance = hls; hls.loadSource(url); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () => { hideLoading(); - video.play().catch(() => playOverlay.style.display = 'flex'); + // Wait for a small buffer before playing to avoid chaos + const checkBuffer = setInterval(() => { + if (video.buffered.length > 0) { + const bufferEnd = video.buffered.end(0); + if (bufferEnd > 1.5) { // 1.5s buffer-first + clearInterval(checkBuffer); + video.play().catch(() => playOverlay.style.display = 'flex'); + } + } + }, 200); }); hls.on(Hls.Events.LEVEL_LOADED, (e, d) => { if (d.details && d.details.totalduration > injectedDuration) window.currentHlsDuration = d.details.totalduration; @@ -292,12 +301,23 @@ if (!mpegts.isSupported()) return false; const player = mpegts.createPlayer({ type: 'mpegts', isLive: isLive, url: url }, { enableWorker: true, - stashInitialSize: 256 * 1024, // Optimized Turbo Start - maxStashSize: 20 * 1024 * 1024 // 20MB buffer capacity + stashInitialSize: 512 * 1024, // Buffer-First: 512KB + enableStashBuffer: true, + liveBufferLatencyChasing: false, // Avoid chaotic catch-up + maxStashSize: 30 * 1024 * 1024 }); player.attachMediaElement(video); player.load(); - player.play().catch(() => playOverlay.style.display = 'flex'); + + // Wait for buffer to fill slightly before playing + const checkBuffer = setInterval(() => { + if (video.buffered.length > 0) { + if (video.buffered.end(0) > 1.0) { + clearInterval(checkBuffer); + player.play().catch(() => playOverlay.style.display = 'flex'); + } + } + }, 200); player.on(mpegts.Events.ERROR, (type, detail) => { log('MpegTS Error: ' + type + ' - ' + detail); diff --git a/web/player_lite.html b/web/player_lite.html index cbda247..663d483 100644 --- a/web/player_lite.html +++ b/web/player_lite.html @@ -296,19 +296,21 @@ url: url }, { enableWorker: true, - stashInitialSize: 256 * 1024, // Optimized Turbo Start: 256KB initial buffer + stashInitialSize: 512 * 1024, enableStashBuffer: true, - liveBufferLatencyChasing: true, - liveBufferLatencyChasingOnPaused: true, - liveBufferLatencyMaxLatency: 10.0, - liveBufferLatencyMinLatency: 2.0, - lazyLoad: false, - maxStashSize: 20 * 1024 * 1024 + liveBufferLatencyChasing: false, + maxStashSize: 30 * 1024 * 1024 }); player.attachMediaElement(video); player.load(); - player.play().catch(() => playOverlay.style.display = 'flex'); + + const checkBuffer = setInterval(() => { + if (video.buffered.length > 0 && video.buffered.end(0) > 1.0) { + clearInterval(checkBuffer); + player.play().catch(() => playOverlay.style.display = 'flex'); + } + }, 200); player.on(mpegts.Events.ERROR, (type, detail, info) => { log('MpegTS Error: ' + type + ' - ' + detail); diff --git a/web/player_mobile.html b/web/player_mobile.html index aae5ced..27f8670 100644 --- a/web/player_mobile.html +++ b/web/player_mobile.html @@ -233,25 +233,27 @@ const hls = new Hls({ maxBufferLength: 60, maxMaxBufferLength: 120, - liveSyncDurationCount: 5, // Balanced sync + liveSyncDurationCount: 10, // Buffer-First safety liveMaxLatencyDurationCount: 20, enableWorker: true, - lowLatencyMode: false, // Disabled for stability against micro-cuts - // Robustness - nudgeOffset: 0.6, // More aggressive jump over corrupted frames - nudgeMaxRetries: 25, - maxLiveSyncPlaybackRate: 1.2, - // Turbo-Start specific - startLevel: 0, - initialLiveManifestSize: 1, - abrEwmaDefaultEstimate: 700000, - manifestLoadingRetryDelay: 500, - levelLoadingRetryDelay: 500 + lowLatencyMode: false, + nudgeOffset: 0.8, + nudgeMaxRetries: 30, + maxLiveSyncPlaybackRate: 1.1, + initialLiveManifestSize: 3, + abrEwmaDefaultEstimate: 1000000, + manifestLoadingRetryDelay: 1000, + levelLoadingRetryDelay: 1000 }); hls.loadSource(streamUrl); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () => { - video.play().catch(e => playOverlay.style.display = 'flex'); + const checkBuffer = setInterval(() => { + if (video.buffered.length > 0 && video.buffered.end(0) > 1.5) { + clearInterval(checkBuffer); + video.play().catch(e => playOverlay.style.display = 'flex'); + } + }, 200); }); hls.on(Hls.Events.ERROR, (e, d) => { if (d.fatal) { @@ -271,13 +273,20 @@ url: streamUrl }, { enableWorker: true, - stashInitialSize: 128 * 1024, // Turbo Start: 128KB initial buffer + stashInitialSize: 512 * 1024, enableStashBuffer: true, - maxStashSize: 20 * 1024 * 1024 // 20MB Max for stability + liveBufferLatencyChasing: false, + maxStashSize: 30 * 1024 * 1024 }); player.attachMediaElement(video); player.load(); - player.play().catch(e => playOverlay.style.display = 'flex'); + + const checkBuffer = setInterval(() => { + if (video.buffered.length > 0 && video.buffered.end(0) > 1.0) { + clearInterval(checkBuffer); + player.play().catch(e => playOverlay.style.display = 'flex'); + } + }, 200); return; }