Merge pull request #4682 from IgorA100/patch-723160

Fix: Remove unused listeners when stopping a stream.
This commit is contained in:
Isaac Connor
2026-03-08 10:40:20 -04:00
committed by GitHub
2 changed files with 50 additions and 6 deletions

View File

@@ -30,6 +30,7 @@ function MonitorStream(monitorData) {
this.wsMSE = null;
this.streamStartTime = 0; // Initial point of flow start time. Used for flow lag time analysis.
this.waitingStart;
this.handlerEventListener = {};
this.mseListenerSourceopenBind = null;
this.streamListenerBind = null;
this.mseSourceBufferListenerUpdateendBind = null;
@@ -441,7 +442,7 @@ function MonitorStream(monitorData) {
clearInterval(this.statusCmdTimer); // Fix for issues in Chromium when quickly hiding/showing a page. Doesn't clear statusCmdTimer when minimizing a page https://stackoverflow.com/questions/9501813/clearinterval-not-working
this.statusCmdTimer = setInterval(this.statusCmdQuery.bind(this), statusRefreshTimeout);
this.started = true;
this.streamListenerBind();
this.handlerEventListener['killStream'] = this.streamListenerBind();
if (typeof observerMontage !== 'undefined') observerMontage.observe(stream);
this.activePlayer = 'go2rtc';
@@ -482,7 +483,7 @@ function MonitorStream(monitorData) {
attachVideo(this);
this.statusCmdTimer = setInterval(this.statusCmdQuery.bind(this), statusRefreshTimeout);
this.started = true;
this.streamListenerBind();
this.handlerEventListener['killStream'] = this.streamListenerBind();
this.activePlayer = 'janus';
this.updateStreamInfo('Janus', 'loading');
return;
@@ -554,7 +555,7 @@ function MonitorStream(monitorData) {
clearInterval(this.statusCmdTimer); // Fix for issues in Chromium when quickly hiding/showing a page. Doesn't clear statusCmdTimer when minimizing a page https://stackoverflow.com/questions/9501813/clearinterval-not-working
this.statusCmdTimer = setInterval(this.statusCmdQuery.bind(this), statusRefreshTimeout);
this.started = true;
this.streamListenerBind();
this.handlerEventListener['killStream'] = this.streamListenerBind();
this.updateStreamInfo((typeof players !== "undefined" && players) ? players[this.activePlayer] : 'RTSP2Web ' + this.RTSP2WebType, 'loading');
return;
} else {
@@ -618,12 +619,14 @@ function MonitorStream(monitorData) {
}
} // end if paused or not
this.started = true;
this.streamListenerBind();
this.handlerEventListener['killStream'] = this.streamListenerBind();
this.activePlayer = 'zms';
this.updateStreamInfo('ZMS MJPEG');
}; // this.start
this.stop = function() {
manageEventListener.removeEventListener(this.handlerEventListener['killStream']);
/* Stop should stop the stream (killing zms) but NOT set src=''; This leaves the last jpeg up on screen instead of a broken image */
const stream = this.getElement();
if (!stream) {
@@ -1976,10 +1979,10 @@ function startRTSP2WebPlay(videoEl, url, stream) {
}
function streamListener(stream) {
window.addEventListener('beforeunload', function(event) {
return manageEventListener.addEventListener(window, 'beforeunload', function() {
console.log('streamListener');
stream.kill();
});
}, {capture: false});
}
function mseListenerSourceopen(context, videoEl, url) {

View File

@@ -2867,4 +2867,45 @@ const waitUntil = (condition, timeout = 0) => {
});
};
// https://stackoverflow.com/a/69273090
class ManageEventListener {
#listeners = {}; // # in a JS class signifies private
#idx = 1;
// add event listener, returns integer ID of new listener
addEventListener(element, type, listener, options = {}) {
this.#privateAddEventListener(element, this.#idx, type, listener, options);
return this.#idx++;
}
// add event listener with custom ID (avoids need to retrieve return ID since you are providing it yourself)
addEventListenerById(element, id, type, listener, options = {}) {
this.#privateAddEventListener(element, id, type, listener, options);
return id;
}
#privateAddEventListener(element, id, type, listener, options) {
if (this.#listeners[id]) throw Error(`A listener with id ${id} already exists`);
element.addEventListener(type, listener, options);
this.#listeners[id] = {element, type, listener, options};
}
// remove event listener with given ID, returns ID of removed listener or null (if listener with given ID does not exist)
removeEventListener(id) {
const listen = this.#listeners[id];
if (listen) {
listen.element.removeEventListener(listen.type, listen.listener, listen.options);
delete this.#listeners[id];
}
return !!listen ? id : null;
}
// returns number of events listeners
length() {
return Object.keys(this.#listeners).length;
}
}
const manageEventListener = new ManageEventListener();
window.manageEventListener = manageEventListener;
$j( window ).on("load", initPageGeneral);