diff --git a/web/js/MonitorStream.js b/web/js/MonitorStream.js index 28787e60f6..e77567c826 100644 --- a/web/js/MonitorStream.js +++ b/web/js/MonitorStream.js @@ -744,8 +744,7 @@ function MonitorStream(monitorData) { this.webrtc = null; } if (this.hls) { - this.hls.destroy(); - this.hls = null; + hlsDestroy(this.hls); } if (-1 !== this.activePlayer.indexOf('mse')) { this.stopMse(); @@ -1791,17 +1790,41 @@ function MonitorStream(monitorData) { maxBufferLength: 10, maxMaxBufferLength: 30, }); + + /* For debug ALL events HLS + const self = this; + Object.keys(Hls.Events).forEach(function(eventName) { + self.hls.on(Hls.Events[eventName], function(event, data) { + console.debug('HLS Event = ', eventName); + console.debug('HLS Event data = ', data); + }); + }); + */ + + this.hls.on(Hls.Events.MEDIA_ATTACHING, function(event, data) { + console.debug(`HLS Event = MEDIA_ATTACHING for monitor ID=${this.id}`); + }, this); + this.hls.on(Hls.Events.BUFFER_CODECS, function(event, data) { + // Triggers if there is an audio track. + console.log(`For monitor with ID=${this.id}, the "${data.audio.codec}" audio codec is used.`); + if (data.audio.codec.indexOf('mp4a.40.') > -1) { + // AAC: mp4a.40.2 - HLS can't play it, so the "Loading" status will always be displayed. + // PCM, G.711A, G.711Mu, G.726, G.723 - no audio track + this.updateStreamInfo('', `Error. AAC codec "${data.audio.codec}" is not supported.`); //HLS + this.streamErrorRegistration(); + hlsDestroy(this.hls); + this.restart(this.currentChannelStream); + } + }, this); this.hls.on(Hls.Events.MEDIA_ATTACHED, function(event, data) { console.log(`Video and hls.js are now bound together for monitor ID=${this.id}`); - this.updateStreamInfo('', ''); //HLS - //getTracksFromStream(this); //HLS }, this); this.hls.on(Hls.Events.ERROR, function(event, data) { console.warn("HLS Event = ERROR", "\n", "event:", event, "\n", "errorType:", data.type, "\n", "errorDetails:", data.details, "\n", "errorFatal:", data.fatal); + if (!data || !data.fatal) return; this.updateStreamInfo('', 'Error'); //HLS this.streamErrorRegistration(); - if (!data || !data.fatal) return; - this.hls.destroy(); + hlsDestroy(this.hls); this.restart(this.currentChannelStream); }, this); this.hls.loadSource(hlsUrl.href); @@ -1809,6 +1832,11 @@ function MonitorStream(monitorData) { } else if (stream.canPlayType('application/vnd.apple.mpegurl')) { stream.src = hlsUrl.href; } + + video_el.onplay = (event) => { + this.updateStreamInfo('', ''); + this.resetCountStreamErrors(this.activePlayer); + }; this.activePlayer = 'rtsp2web_hls'; } else if (-1 !== this.player.indexOf('mse')) { const mseUrl = rtsp2webModUrl; @@ -1965,15 +1993,6 @@ function MonitorStream(monitorData) { } }; - this.streamErrorRegistration = function() { - const currentPlayer = this.player; - for (const key in this.playerPriority) { - if (-1 !== currentPlayer.indexOf(this.playerPriority[key]['name'])) { - this.playerPriority[key]['countErrors'] = parseInt(this.playerPriority[key]['countErrors'], 10) + 1; - } - } - }; - this.selectNextPlayer = function(currentPlayer = null) { if (this.defaultPlayer == this.player) { // This means we need to start the bypass from the beginning, since we started playback from the default player, which may be in the middle of the list. @@ -2012,6 +2031,16 @@ function MonitorStream(monitorData) { this.restart(this.currentChannelStream); } }; + + this.streamErrorRegistration = function() { + const currentPlayer = this.player; + for (const key in this.playerPriority) { + if (-1 !== currentPlayer.indexOf(this.playerPriority[key]['name'])) { + this.playerPriority[key]['countErrors'] = parseInt(this.playerPriority[key]['countErrors'], 10) + 1; + break; + } + } + }; } // end class MonitorStream /* +++ Janus */ @@ -2237,7 +2266,7 @@ function startRTSP2WebPlay(videoEl, url, stream) { } }, error: function(xhr, status, error) { - console.warn('Error request localDescription:', error, xhr.responseText); + console.warn('RTSP2Web_webrtc Error request localDescription:', error, xhr.responseText); stream.updateStreamInfo('', 'Error'); //WEBRTC stream.streamErrorRegistration(); stream.restart(stream.currentChannelStream); diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 132892c332..88115a245d 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -1581,6 +1581,7 @@ function createRtsp2webStream(container, img, monitorId, fallbackToMjpeg, eventS if (Hls.isSupported()) { const hls = new Hls(); + video._hls = hls; hls.loadSource(hlsUrl); hls.attachMedia(video); @@ -1589,6 +1590,7 @@ function createRtsp2webStream(container, img, monitorId, fallbackToMjpeg, eventS if (infoStatusBar) infoStatusBar.innerHTML = ' [RTSP2Web Loading] '; thumbnailVideoPlay(video, 'RTSP2Web', eventStart, statusBar); console.debug("HLS Event = MEDIA_ATTACHED"); + clearTimeout(video._fallbackTimer); }); hls.on(Hls.Events.FRAG_LOADED, () => { console.debug("HLS Event = FRAG_LOADED"); @@ -1605,12 +1607,11 @@ function createRtsp2webStream(container, img, monitorId, fallbackToMjpeg, eventS hls.on(Hls.Events.ERROR, function(event, data) { console.warn("HLS Event = ERROR", "\n", "event:", event, "\n", "errorType:", data.type, "\n", "errorDetails:", data.details, "\n", "errorFatal:", data.fatal); if (!data || !data.fatal) return; - hls.destroy(); + hlsDestroy(hls); clearTimeout(video._fallbackTimer); video.remove(); fallbackToMjpeg(); }); - video._hls = hls; } else if (video.canPlayType('application/vnd.apple.mpegurl')) { // Native HLS support (Safari) video.src = hlsUrl; @@ -1629,7 +1630,7 @@ function createRtsp2webStream(container, img, monitorId, fallbackToMjpeg, eventS // Fallback after 5s if video hasn't loaded video._fallbackTimer = setTimeout(function() { if (video.readyState < 2) { - if (video._hls) video._hls.destroy(); + if (video._hls) hlsDestroy(video._hls); video.remove(); fallbackToMjpeg(); } @@ -1640,6 +1641,19 @@ function createRtsp2webStream(container, img, monitorId, fallbackToMjpeg, eventS }); } +const hlsDestroy = function(hls) { + if (hls && Hls) { + Object.keys(Hls.Events).forEach(function(eventName) { + hls.off(Hls.Events[eventName], function(event, data) { + }); + }); + hls.destroy(); + hls = null; + } else { + console.warn("Hls cannot be destroyed because it is not loaded."); + } +}; + function thumbnailVideoPlay(video, currentMode, eventStart, statusBar) { const infoStatusBar = (statusBar) ? statusBar.querySelector("#info-status-bar") : null; video.play().then(() => { @@ -1798,7 +1812,7 @@ function playEventHLS(container, img, monitorId, fallbackToMjpeg, statusBar, eve // If the index.m3u8 manifest is bad, playback may not start, although there will be no errors. if (video.readyState < 2) { video.remove(); - hls.destroy(); + hlsDestroy(hls); tryPlayMp4(container, img, monitorId, fallbackToMjpeg, statusBar); } }, 2000); @@ -1819,7 +1833,7 @@ function playEventHLS(container, img, monitorId, fallbackToMjpeg, statusBar, eve console.warn("HLS Event = ERROR", "\n", "event:", event, "\n", "errorType:", data.type, "\n", "errorDetails:", data.details, "\n", "errorFatal:", data.fatal); if (!data || !data.fatal) return; video.remove(); - hls.destroy(); + hlsDestroy(hls); clearTimeout(video._fallbackTimer); tryPlayMp4(container, img, monitorId, fallbackToMjpeg, statusBar); }); @@ -1896,10 +1910,7 @@ function cleanupVideoElement(video) { if (!video) return; if (video._fallbackTimer) clearTimeout(video._fallbackTimer); clearInterval(video._fallbackTimerTime); - if (video._hls) { - video._hls.destroy(); - video._hls = null; - } + if (video._hls) hlsDestroy(video._hls); video.pause(); video.src = ''; video.load();