Merge branch 'main' into dev
This commit is contained in:
@@ -474,7 +474,9 @@ class VideoPlayer {
|
|||||||
// Transcoded streams are fragmented MP4 - play directly with <video> element
|
// Transcoded streams are fragmented MP4 - play directly with <video> element
|
||||||
console.log('[Player] Playing transcoded stream directly:', transcodeUrl);
|
console.log('[Player] Playing transcoded stream directly:', transcodeUrl);
|
||||||
this.video.src = transcodeUrl;
|
this.video.src = transcodeUrl;
|
||||||
this.video.play().catch(e => console.log('[Player] Autoplay prevented:', e));
|
this.video.play().catch(e => {
|
||||||
|
if (e.name !== 'AbortError') console.log('[Player] Autoplay prevented:', e);
|
||||||
|
});
|
||||||
|
|
||||||
// Update UI and dispatch events
|
// Update UI and dispatch events
|
||||||
this.updateNowPlaying(channel);
|
this.updateNowPlaying(channel);
|
||||||
@@ -513,7 +515,9 @@ class VideoPlayer {
|
|||||||
console.log('[Player] Stream type:', isRawTs ? 'Raw TS' : 'Extension-less (assumed TS)');
|
console.log('[Player] Stream type:', isRawTs ? 'Raw TS' : 'Extension-less (assumed TS)');
|
||||||
const remuxUrl = this.getRemuxUrl(streamUrl);
|
const remuxUrl = this.getRemuxUrl(streamUrl);
|
||||||
this.video.src = remuxUrl;
|
this.video.src = remuxUrl;
|
||||||
this.video.play().catch(e => console.log('[Player] Autoplay prevented:', e));
|
this.video.play().catch(e => {
|
||||||
|
if (e.name !== 'AbortError') console.log('[Player] Autoplay prevented:', e);
|
||||||
|
});
|
||||||
|
|
||||||
// Update UI and dispatch events
|
// Update UI and dispatch events
|
||||||
this.updateNowPlaying(channel);
|
this.updateNowPlaying(channel);
|
||||||
@@ -542,7 +546,9 @@ class VideoPlayer {
|
|||||||
this.hls.attachMedia(this.video);
|
this.hls.attachMedia(this.video);
|
||||||
|
|
||||||
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
this.video.play().catch(e => console.log('Autoplay prevented:', e));
|
this.video.play().catch(e => {
|
||||||
|
if (e.name !== 'AbortError') console.log('Autoplay prevented:', e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-attach error handler for the new Hls instance
|
// Re-attach error handler for the new Hls instance
|
||||||
@@ -592,17 +598,22 @@ class VideoPlayer {
|
|||||||
// Priority 2: Native HLS support (Safari on iOS/macOS where HLS.js may not work)
|
// Priority 2: Native HLS support (Safari on iOS/macOS where HLS.js may not work)
|
||||||
this.video.src = finalUrl;
|
this.video.src = finalUrl;
|
||||||
this.video.play().catch(e => {
|
this.video.play().catch(e => {
|
||||||
|
if (e.name === 'AbortError') return; // Ignore interruption by new load
|
||||||
console.log('Autoplay prevented, trying proxy if CORS error:', e);
|
console.log('Autoplay prevented, trying proxy if CORS error:', e);
|
||||||
if (!this.isUsingProxy) {
|
if (!this.isUsingProxy) {
|
||||||
this.isUsingProxy = true;
|
this.isUsingProxy = true;
|
||||||
this.video.src = this.getProxiedUrl(streamUrl);
|
this.video.src = this.getProxiedUrl(streamUrl);
|
||||||
this.video.play().catch(err => console.error('Proxy play failed:', err));
|
this.video.play().catch(err => {
|
||||||
|
if (err.name !== 'AbortError') console.error('Proxy play failed:', err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Priority 3: Try direct playback for non-HLS streams
|
// Priority 3: Try direct playback for non-HLS streams
|
||||||
this.video.src = finalUrl;
|
this.video.src = finalUrl;
|
||||||
this.video.play().catch(e => console.log('Autoplay prevented:', e));
|
this.video.play().catch(e => {
|
||||||
|
if (e.name !== 'AbortError') console.log('Autoplay prevented:', e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update now playing info
|
// Update now playing info
|
||||||
|
|||||||
+10
-2
@@ -26,10 +26,15 @@ router.get('/', (req, res) => {
|
|||||||
const args = [
|
const args = [
|
||||||
'-hide_banner',
|
'-hide_banner',
|
||||||
'-loglevel', 'warning',
|
'-loglevel', 'warning',
|
||||||
// Error resilience: discard corrupt packets, generate timestamps
|
// Low-latency startup: reduce probe/analyze time for faster first bytes
|
||||||
'-fflags', '+genpts+discardcorrupt+igndts',
|
'-probesize', '32768',
|
||||||
|
'-analyzeduration', '0',
|
||||||
|
// Error resilience: discard corrupt packets, generate timestamps, ignore DTS, no buffering
|
||||||
|
'-fflags', '+genpts+discardcorrupt+igndts+nobuffer',
|
||||||
// Ignore errors in stream and continue
|
// Ignore errors in stream and continue
|
||||||
'-err_detect', 'ignore_err',
|
'-err_detect', 'ignore_err',
|
||||||
|
// Limit max demux delay to prevent buffering issues with bad timestamps
|
||||||
|
'-max_delay', '5000000',
|
||||||
// Reconnect settings for network drops
|
// Reconnect settings for network drops
|
||||||
'-reconnect', '1',
|
'-reconnect', '1',
|
||||||
'-reconnect_streamed', '1',
|
'-reconnect_streamed', '1',
|
||||||
@@ -40,6 +45,9 @@ router.get('/', (req, res) => {
|
|||||||
// Convert AAC from ADTS format (TS) to ASC format (MP4)
|
// Convert AAC from ADTS format (TS) to ASC format (MP4)
|
||||||
// Required when remuxing MPEG-TS with AAC audio to MP4
|
// Required when remuxing MPEG-TS with AAC audio to MP4
|
||||||
'-bsf:a', 'aac_adtstoasc',
|
'-bsf:a', 'aac_adtstoasc',
|
||||||
|
// Handle timestamp discontinuities at output
|
||||||
|
'-fps_mode', 'passthrough',
|
||||||
|
'-max_muxing_queue_size', '1024',
|
||||||
// Fragmented MP4 for streaming (browser-compatible)
|
// Fragmented MP4 for streaming (browser-compatible)
|
||||||
'-f', 'mp4',
|
'-f', 'mp4',
|
||||||
'-movflags', 'frag_keyframe+empty_moov+default_base_moof',
|
'-movflags', 'frag_keyframe+empty_moov+default_base_moof',
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ router.get('/', (req, res) => {
|
|||||||
const args = [
|
const args = [
|
||||||
'-hide_banner',
|
'-hide_banner',
|
||||||
'-loglevel', 'warning',
|
'-loglevel', 'warning',
|
||||||
// Error resilience: discard corrupt packets, generate timestamps, ignore DTS
|
// Low-latency startup: reduce probe/analyze time for faster first bytes
|
||||||
'-fflags', '+genpts+discardcorrupt+igndts',
|
'-probesize', '32768',
|
||||||
|
'-analyzeduration', '0',
|
||||||
|
// Error resilience: discard corrupt packets, generate timestamps, ignore DTS, no buffering
|
||||||
|
'-fflags', '+genpts+discardcorrupt+igndts+nobuffer',
|
||||||
// Ignore errors in stream and continue
|
// Ignore errors in stream and continue
|
||||||
'-err_detect', 'ignore_err',
|
'-err_detect', 'ignore_err',
|
||||||
// Limit max demux delay to prevent buffering issues with bad timestamps
|
// Limit max demux delay to prevent buffering issues with bad timestamps
|
||||||
|
|||||||
Reference in New Issue
Block a user