From 5187422899506ef1e15563e3fc26b5ca463a8d83 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sat, 19 Jul 2025 19:51:44 +0300 Subject: [PATCH 1/8] Fix: Always load hls.js library (watch.php) Because now we switch players "on the fly" --- web/skins/classic/views/watch.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index d2500d8456..a8c3b86400 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -103,16 +103,12 @@ } #Whether to show the controls button $hasPtzControls = false; -$hasHLS = false; foreach ($monitors as $m) { if (( ZM_OPT_CONTROL && $m->Controllable() && canView('Control') && $m->Type() != 'WebSite' )) { //If there is control for at least one camera, then we display the block. $hasPtzControls = true; } - if (($m->RTSP2WebEnabled() and $m->RTSP2WebType == 'HLS')) { - $hasHLS = true; - } - if ($hasPtzControls && $hasHLS) { + if ($hasPtzControls) { break; } } @@ -534,13 +530,7 @@ class="table-sm table-borderless" - - Date: Sun, 20 Jul 2025 01:33:56 +0300 Subject: [PATCH 2/8] Fix: Correct switching of players (MonitorStream.js) - When changing the player, set the correct value in "this.RTSP2WebType" - Incorrect placement of brackets in the conditions when starting a stream - When stopping "webrtc", clear "stream.srcObject" - When executing ".stopMse", limit the promise wait time to 500ms and, in case of failure, execute reject() --- web/js/MonitorStream.js | 43 ++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 5ec8c79e42..8abec2932b 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -84,6 +84,19 @@ function MonitorStream(monitorData) { this.player = ''; this.setPlayer = function(p) { + if (-1 != p.indexOf('go2rtc')) { + + } else if (-1 != p.indexOf('rtsp2web')){ + if (-1 != p.indexOf('_hls')) { + this.RTSP2WebType = 'HLS'; + } else if (-1 != p.indexOf('_mse')) { + this.RTSP2WebType = 'MSE'; + } else if (-1 != p.indexOf('_webrtc')) { + this.RTSP2WebType = 'WebRTC'; + } + } else if (-1 != p.indexOf('janus')){ + + } return this.player = p; }; @@ -257,7 +270,7 @@ function MonitorStream(monitorData) { $j('#volumeControls').hide(); - if (this.Go2RTCEnabled && ((!this.player) || (-1 != this.player.indexOf('go2rtc')))) { + if ((this.Go2RTCEnabled && !this.player) || (-1 != this.player.indexOf('go2rtc'))) { if (ZM_GO2RTC_PATH) { const url = new URL(ZM_GO2RTC_PATH); @@ -293,7 +306,7 @@ function MonitorStream(monitorData) { } } - if (((!this.player) || (-1 !== this.player.indexOf('janus'))) && this.janusEnabled) { + if ((this.janusEnabled && !this.player) || (-1 != this.player.indexOf('janus'))) { let server; if (ZM_JANUS_PATH) { server = ZM_JANUS_PATH; @@ -317,7 +330,7 @@ function MonitorStream(monitorData) { this.streamListenerBind(); return; } - if (this.RTSP2WebEnabled && ((!this.player) || (-1 !== this.player.indexOf('rtsp2web')))) { + if ((this.RTSP2WebEnabled && !this.player) || (-1 != this.player.indexOf('rtsp2web'))) { if (ZM_RTSP2WEB_PATH) { let stream = this.getElement(); if (stream.nodeName != 'VIDEO') { @@ -417,10 +430,13 @@ function MonitorStream(monitorData) { }; // this.start this.stop = function() { + const stream = this.getElement(); + if (!stream) { + console.warn(`! ${dateTimeToISOLocal(new Date())} Stream for ID=${this.id} it is impossible to stop because it is not found.`); + return; + } console.debug(`! ${dateTimeToISOLocal(new Date())} Stream for ID=${this.id} STOPPED`); if ( 1 ) { - const stream = this.getElement(); - if (!stream) return; if (stream.src) { let src = stream.src; if (-1 === src.indexOf('mode=')) { @@ -442,6 +458,7 @@ function MonitorStream(monitorData) { if (this.RTSP2WebEnabled) { if (this.webrtc) { if (this.webrtc.close) this.webrtc.close(); + stream.srcObject = null; this.webrtc = null; } if (this.hls) { @@ -488,6 +505,10 @@ function MonitorStream(monitorData) { this.removeEventListener('updateend', onBufferRemoved); resolve(); } + setTimeout(function() { + // We can't wait forever, which means everything is bad, for example, the "src" attribute was removed from the object + reject(); + }, 500); }) .then(() => { if (this.mseSourceBuffer) { @@ -499,6 +520,14 @@ function MonitorStream(monitorData) { this.mseStreamingStarted = false; this.mseSourceBuffer = null; this.MSEBufferCleared = true; + }) + .catch((error) => { + console.warn(`${dateTimeToISOLocal(new Date())} An error occurred while stopMse() for ID=${this.id}`, error); + this.closeWebSocket(); + this.mse = null; + this.mseStreamingStarted = false; + this.mseSourceBuffer = null; + this.MSEBufferCleared = true; }); }; @@ -1029,8 +1058,8 @@ function MonitorStream(monitorData) { .done(this.getStatusCmdResponse.bind(this)) .fail(logAjaxFail); - if (this.Go2RTCEnabled && ((!this.player) || (-1 != this.player.indexOf('go2rtc')))) { - } else if (this.RTSP2WebEnabled && ((!this.player) || (-1 !== this.player.indexOf('rtsp2web')))) { + if ((this.Go2RTCEnabled && !this.player) || (-1 != this.player.indexOf('go2rtc'))) { + } else if ((this.RTSP2WebEnabled && !this.player) || (-1 != this.player.indexOf('rtsp2web'))) { // We correct the lag from real time. Relevant for long viewing and network problems. if (this.RTSP2WebType == 'MSE') { const videoEl = document.getElementById("liveStream" + this.id); From 3c744084c2b96d87624cdfd3d07e25ed365fc948 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sun, 20 Jul 2025 01:56:46 +0300 Subject: [PATCH 3/8] Remove Timeout and perform "reject()" immediately at the moment of unsuccessful attempt to delete MSE buffer (MonitorStream.js) --- web/js/MonitorStream.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 8abec2932b..1549d9cdc2 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -86,7 +86,7 @@ function MonitorStream(monitorData) { this.setPlayer = function(p) { if (-1 != p.indexOf('go2rtc')) { - } else if (-1 != p.indexOf('rtsp2web')){ + } else if (-1 != p.indexOf('rtsp2web')) { if (-1 != p.indexOf('_hls')) { this.RTSP2WebType = 'HLS'; } else if (-1 != p.indexOf('_mse')) { @@ -94,7 +94,7 @@ function MonitorStream(monitorData) { } else if (-1 != p.indexOf('_webrtc')) { this.RTSP2WebType = 'WebRTC'; } - } else if (-1 != p.indexOf('janus')){ + } else if (-1 != p.indexOf('janus')) { } return this.player = p; @@ -484,12 +484,13 @@ function MonitorStream(monitorData) { this.mseSourceBuffer.addEventListener('updateend', onBufferRemoved, this); try { /* - Very, very rarely, on the MOTAGE PAGE THERE MAY BE AN ERROR OF THE TYPE: TypeError: Failed to execute 'remove' on 'SourceBuffer': The start provided (0) is outside the range (0, 0). - Possibly due to high CPU load, the browser does not have time to process. + Very, very rarely, on the MONTAGE PAGE THERE MAY BE AN ERROR OF THE TYPE: TypeError: Failed to execute 'remove' on 'SourceBuffer': The start provided (0) is outside the range (0, 0). + Possibly due to high CPU load, the browser does not have time to process or the "src" attribute was removed from the object. */ this.mseSourceBuffer.remove(0, Infinity); } catch (e) { console.warn(`${dateTimeToISOLocal(new Date())} An error occurred while cleaning Source Buffer for ID=${this.id}`, e); + reject(); } } @@ -505,10 +506,6 @@ function MonitorStream(monitorData) { this.removeEventListener('updateend', onBufferRemoved); resolve(); } - setTimeout(function() { - // We can't wait forever, which means everything is bad, for example, the "src" attribute was removed from the object - reject(); - }, 500); }) .then(() => { if (this.mseSourceBuffer) { From 394f90fb1fa63a3567089ca744c239b09e5b9b68 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sun, 20 Jul 2025 02:01:49 +0300 Subject: [PATCH 4/8] Update MonitorStream.js --- web/js/MonitorStream.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 1549d9cdc2..7e90c15fdb 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -490,7 +490,7 @@ function MonitorStream(monitorData) { this.mseSourceBuffer.remove(0, Infinity); } catch (e) { console.warn(`${dateTimeToISOLocal(new Date())} An error occurred while cleaning Source Buffer for ID=${this.id}`, e); - reject(); + reject(e); } } From 51c2083ef603d53ccac58da31c85f70bcc2c0d80 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sun, 20 Jul 2025 11:33:59 +0300 Subject: [PATCH 5/8] Returned the conditions as they were before (MonitorStream.js) --- web/js/MonitorStream.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 7e90c15fdb..2e2d0fcf2d 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -270,7 +270,7 @@ function MonitorStream(monitorData) { $j('#volumeControls').hide(); - if ((this.Go2RTCEnabled && !this.player) || (-1 != this.player.indexOf('go2rtc'))) { + if (this.Go2RTCEnabled && ((!this.player) || (-1 !== this.player.indexOf('go2rtc')))) { if (ZM_GO2RTC_PATH) { const url = new URL(ZM_GO2RTC_PATH); @@ -306,7 +306,7 @@ function MonitorStream(monitorData) { } } - if ((this.janusEnabled && !this.player) || (-1 != this.player.indexOf('janus'))) { + if (this.janusEnabled && ((!this.player) || (-1 !== this.player.indexOf('janus')))) { let server; if (ZM_JANUS_PATH) { server = ZM_JANUS_PATH; @@ -330,7 +330,8 @@ function MonitorStream(monitorData) { this.streamListenerBind(); return; } - if ((this.RTSP2WebEnabled && !this.player) || (-1 != this.player.indexOf('rtsp2web'))) { + + if (this.RTSP2WebEnabled && ((!this.player) || (-1 !== this.player.indexOf('rtsp2web')))) { if (ZM_RTSP2WEB_PATH) { let stream = this.getElement(); if (stream.nodeName != 'VIDEO') { From fcfc58e6a8c3578f8b64acb9c47d08fd32dd7b01 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sun, 20 Jul 2025 11:52:51 +0300 Subject: [PATCH 6/8] Don't change "src" attribute when using RTSP2Web (MonitorStream.js) --- web/js/MonitorStream.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 2e2d0fcf2d..b1cfff0a4e 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -437,7 +437,8 @@ function MonitorStream(monitorData) { return; } console.debug(`! ${dateTimeToISOLocal(new Date())} Stream for ID=${this.id} STOPPED`); - if ( 1 ) { + //if ( 1 ) { + if (-1 === this.player.indexOf('rtsp2web')) { if (stream.src) { let src = stream.src; if (-1 === src.indexOf('mode=')) { @@ -542,7 +543,7 @@ function MonitorStream(monitorData) { stream.onload = null; // this.stop tells zms to stop streaming, but the process remains. We need to turn the stream into an image. - if (stream.src) { + if (stream.src && -1 === this.player.indexOf('rtsp2web')) { stream.src = ''; } this.stop(); From e8ef6d729ee33e994db58aa530a935a37bf0058c Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Mon, 21 Jul 2025 11:21:06 +0300 Subject: [PATCH 7/8] Stream stopping fix for RTSP2Web and Go2Rtc (MonitorStream.js) Flow stops for Go2Rtc require further adjustment. --- web/js/MonitorStream.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index b1cfff0a4e..3aa79d010a 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -339,6 +339,9 @@ function MonitorStream(monitorData) { const stream_container = stream.parentNode; const new_stream = this.element = document.createElement('video'); new_stream.id = stream.id; // should be liveStream+id + new_stream.setAttribute("autoplay", ""); + new_stream.setAttribute("muted", ""); + new_stream.setAttribute("playsinline", ""); new_stream.style = stream.style; // Copy any applied styles stream.remove(); stream_container.appendChild(new_stream); @@ -457,7 +460,13 @@ function MonitorStream(monitorData) { this.statusCmdTimer = clearInterval(this.statusCmdTimer); this.streamCmdTimer = clearInterval(this.streamCmdTimer); this.started = false; - if (this.RTSP2WebEnabled) { + if (-1 !== this.player.indexOf('go2rtc')) { + if (this.webrtc) { + if (this.webrtc.close) this.webrtc.close(); + stream.srcObject = null; + this.webrtc = null; + } + } else if (-1 !== this.player.indexOf('rtsp2web')) { if (this.webrtc) { if (this.webrtc.close) this.webrtc.close(); stream.srcObject = null; From b2e0d696ba87315631cb60901a0554cd45f67b23 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Mon, 21 Jul 2025 12:47:31 +0300 Subject: [PATCH 8/8] Revert "if" (MonitorStream.js) --- web/js/MonitorStream.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 3aa79d010a..fb5d732b11 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -1066,8 +1066,8 @@ function MonitorStream(monitorData) { .done(this.getStatusCmdResponse.bind(this)) .fail(logAjaxFail); - if ((this.Go2RTCEnabled && !this.player) || (-1 != this.player.indexOf('go2rtc'))) { - } else if ((this.RTSP2WebEnabled && !this.player) || (-1 != this.player.indexOf('rtsp2web'))) { + if (this.Go2RTCEnabled && ((!this.player) || (-1 !== this.player.indexOf('go2rtc')))) { + } else if (this.RTSP2WebEnabled && ((!this.player) || (-1 !== this.player.indexOf('rtsp2web')))) { // We correct the lag from real time. Relevant for long viewing and network problems. if (this.RTSP2WebType == 'MSE') { const videoEl = document.getElementById("liveStream" + this.id);