From ae30084737c8ec6831ea56af472ff8dfcf43d515 Mon Sep 17 00:00:00 2001 From: Rob Walch Date: Wed, 10 Jan 2024 16:50:10 -0800 Subject: [PATCH] Null inline class JavaScript Event callback properties on destroy --- api-extractor/report/hls.js.api.md | 8 ++----- src/controller/base-stream-controller.ts | 25 +++++++++------------ src/controller/buffer-controller.ts | 6 +++++ src/controller/eme-controller.ts | 18 +++++---------- src/controller/latency-controller.ts | 15 ++++++------- src/controller/stream-controller.ts | 25 +++++++++------------ src/controller/subtitle-track-controller.ts | 6 +++-- tests/unit/controller/latency-controller.ts | 2 +- 8 files changed, 47 insertions(+), 58 deletions(-) diff --git a/api-extractor/report/hls.js.api.md b/api-extractor/report/hls.js.api.md index 24aa184abd6..33a139ef9f1 100644 --- a/api-extractor/report/hls.js.api.md +++ b/api-extractor/report/hls.js.api.md @@ -443,16 +443,12 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP // (undocumented) protected onMediaDetaching(): void; // (undocumented) - protected onMediaEnded(): void; + protected onMediaEnded: () => void; // (undocumented) - protected onMediaSeeking(): void; + protected onMediaSeeking: () => void; // (undocumented) protected onTickEnd(): void; // (undocumented) - protected onvended: EventListener | null; - // (undocumented) - protected onvseeking: EventListener | null; - // (undocumented) protected playlistType: PlaylistLevelType; // (undocumented) protected recoverWorkerError(data: ErrorData): void; diff --git a/src/controller/base-stream-controller.ts b/src/controller/base-stream-controller.ts index 35bd7b5b3c4..0d50dfb3a1f 100644 --- a/src/controller/base-stream-controller.ts +++ b/src/controller/base-stream-controller.ts @@ -97,8 +97,6 @@ export default class BaseStreamController protected startFragRequested: boolean = false; protected decrypter: Decrypter; protected initPTS: RationalTimestamp[] = []; - protected onvseeking: EventListener | null = null; - protected onvended: EventListener | null = null; private readonly logPrefix: string = ''; protected log: (msg: any) => void; @@ -197,10 +195,8 @@ export default class BaseStreamController data: MediaAttachedData, ) { const media = (this.media = this.mediaBuffer = data.media); - this.onvseeking = this.onMediaSeeking.bind(this) as EventListener; - this.onvended = this.onMediaEnded.bind(this) as EventListener; - media.addEventListener('seeking', this.onvseeking); - media.addEventListener('ended', this.onvended); + media.addEventListener('seeking', this.onMediaSeeking); + media.addEventListener('ended', this.onMediaEnded); const config = this.config; if (this.levels && config.autoStartLoad && this.state === State.STOPPED) { this.startLoad(config.startPosition); @@ -215,10 +211,9 @@ export default class BaseStreamController } // remove video listeners - if (media && this.onvseeking && this.onvended) { - media.removeEventListener('seeking', this.onvseeking); - media.removeEventListener('ended', this.onvended); - this.onvseeking = this.onvended = null; + if (media) { + media.removeEventListener('seeking', this.onMediaSeeking); + media.removeEventListener('ended', this.onMediaEnded); } if (this.keyLoader) { this.keyLoader.detach(); @@ -229,7 +224,7 @@ export default class BaseStreamController this.stopLoad(); } - protected onMediaSeeking() { + protected onMediaSeeking = () => { const { config, fragCurrent, media, mediaBuffer, state } = this; const currentTime: number = media ? media.currentTime : 0; const bufferInfo = BufferHelper.bufferInfo( @@ -292,12 +287,12 @@ export default class BaseStreamController // Async tick to speed up processing this.tickImmediate(); - } + }; - protected onMediaEnded() { + protected onMediaEnded = () => { // reset startPosition and lastCurrentTime to restart playback @ stream beginning this.startPosition = this.lastCurrentTime = 0; - } + }; protected onManifestLoaded( event: Events.MANIFEST_LOADED, @@ -312,7 +307,7 @@ export default class BaseStreamController this.stopLoad(); super.onHandlerDestroying(); // @ts-ignore - this.hls = null; + this.hls = this.onMediaSeeking = this.onMediaEnded = null; } protected onHandlerDestroyed() { diff --git a/src/controller/buffer-controller.ts b/src/controller/buffer-controller.ts index dbed9725520..efbbe4415cb 100755 --- a/src/controller/buffer-controller.ts +++ b/src/controller/buffer-controller.ts @@ -110,6 +110,12 @@ export default class BufferController implements ComponentAPI { this.lastMpegAudioChunk = null; // @ts-ignore this.hls = null; + // @ts-ignore + this._onMediaSourceOpen = this._onMediaSourceClose = null; + // @ts-ignore + this._onMediaSourceEnded = null; + // @ts-ignore + this._onStartStreaming = this._onEndStreaming = null; } protected registerListeners() { diff --git a/src/controller/eme-controller.ts b/src/controller/eme-controller.ts index ae2c40f249e..27303a5f698 100644 --- a/src/controller/eme-controller.ts +++ b/src/controller/eme-controller.ts @@ -90,8 +90,6 @@ class EMEController implements ComponentAPI { private setMediaKeysQueue: Promise[] = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : []; - private onMediaEncrypted = this._onMediaEncrypted.bind(this); - private onWaitingForKey = this._onWaitingForKey.bind(this); private debug: (msg: any) => void = logger.debug.bind(logger, LOGGER_PREFIX); private log: (msg: any) => void = logger.log.bind(logger, LOGGER_PREFIX); @@ -113,13 +111,9 @@ class EMEController implements ComponentAPI { config.licenseXhrSetup = config.licenseResponseCallback = undefined; config.drmSystems = config.drmSystemOptions = {}; // @ts-ignore - this.hls = - this.onMediaEncrypted = - this.onWaitingForKey = - this.keyIdToKeySessionPromise = - null as any; + this.hls = this.config = this.keyIdToKeySessionPromise = null; // @ts-ignore - this.config = null; + this.onMediaEncrypted = this.onWaitingForKey = null; } private registerListeners() { @@ -523,7 +517,7 @@ class EMEController implements ComponentAPI { return this.attemptKeySystemAccess(keySystemsToAttempt); } - private _onMediaEncrypted(event: MediaEncryptedEvent) { + private onMediaEncrypted = (event: MediaEncryptedEvent) => { const { initDataType, initData } = event; this.debug(`"${event.type}" event: init data type: "${initDataType}"`); @@ -639,11 +633,11 @@ class EMEController implements ComponentAPI { ); } keySessionContextPromise.catch((error) => this.handleError(error)); - } + }; - private _onWaitingForKey(event: Event) { + private onWaitingForKey = (event: Event) => { this.log(`"${event.type}" event`); - } + }; private attemptSetMediaKeys( keySystem: KeySystems, diff --git a/src/controller/latency-controller.ts b/src/controller/latency-controller.ts index 8918c43e610..77830588c0e 100644 --- a/src/controller/latency-controller.ts +++ b/src/controller/latency-controller.ts @@ -19,7 +19,6 @@ export default class LatencyController implements ComponentAPI { private currentTime: number = 0; private stallCount: number = 0; private _latency: number | null = null; - private timeupdateHandler = () => this.timeupdate(); constructor(hls: Hls) { this.hls = hls; @@ -126,7 +125,7 @@ export default class LatencyController implements ComponentAPI { this.onMediaDetaching(); this.levelDetails = null; // @ts-ignore - this.hls = this.timeupdateHandler = null; + this.hls = this.onTimeupdate = null; } private registerListeners() { @@ -150,12 +149,12 @@ export default class LatencyController implements ComponentAPI { data: MediaAttachingData, ) { this.media = data.media; - this.media.addEventListener('timeupdate', this.timeupdateHandler); + this.media.addEventListener('timeupdate', this.onTimeupdate); } private onMediaDetaching() { if (this.media) { - this.media.removeEventListener('timeupdate', this.timeupdateHandler); + this.media.removeEventListener('timeupdate', this.onTimeupdate); this.media = null; } } @@ -172,10 +171,10 @@ export default class LatencyController implements ComponentAPI { ) { this.levelDetails = details; if (details.advanced) { - this.timeupdate(); + this.onTimeupdate(); } if (!details.live && this.media) { - this.media.removeEventListener('timeupdate', this.timeupdateHandler); + this.media.removeEventListener('timeupdate', this.onTimeupdate); } } @@ -191,7 +190,7 @@ export default class LatencyController implements ComponentAPI { } } - private timeupdate() { + private onTimeupdate = () => { const { media, levelDetails } = this; if (!media || !levelDetails) { return; @@ -242,7 +241,7 @@ export default class LatencyController implements ComponentAPI { } else if (media.playbackRate !== 1 && media.playbackRate !== 0) { media.playbackRate = 1; } - } + }; private estimateLiveEdge(): number | null { const { levelDetails } = this; diff --git a/src/controller/stream-controller.ts b/src/controller/stream-controller.ts index 51332515e29..be0714af0e2 100644 --- a/src/controller/stream-controller.ts +++ b/src/controller/stream-controller.ts @@ -49,8 +49,6 @@ export default class StreamController private altAudio: boolean = false; private audioOnly: boolean = false; private fragPlaying: Fragment | null = null; - private onvplaying: EventListener | null = null; - private onvseeked: EventListener | null = null; private fragLastKbps: number = 0; private couldBacktrack: boolean = false; private backtrackFragment: Fragment | null = null; @@ -117,6 +115,8 @@ export default class StreamController protected onHandlerDestroying() { this._unregisterListeners(); + // @ts-ignore + this.onMediaPlaying = this.onMediaSeeked = null; super.onHandlerDestroying(); } @@ -515,10 +515,8 @@ export default class StreamController ) { super.onMediaAttached(event, data); const media = data.media; - this.onvplaying = this.onMediaPlaying.bind(this); - this.onvseeked = this.onMediaSeeked.bind(this); - media.addEventListener('playing', this.onvplaying as EventListener); - media.addEventListener('seeked', this.onvseeked as EventListener); + media.addEventListener('playing', this.onMediaPlaying); + media.addEventListener('seeked', this.onMediaSeeked); this.gapController = new GapController( this.config, media, @@ -529,10 +527,9 @@ export default class StreamController protected onMediaDetaching() { const { media } = this; - if (media && this.onvplaying && this.onvseeked) { - media.removeEventListener('playing', this.onvplaying); - media.removeEventListener('seeked', this.onvseeked); - this.onvplaying = this.onvseeked = null; + if (media) { + media.removeEventListener('playing', this.onMediaPlaying); + media.removeEventListener('seeked', this.onMediaSeeked); this.videoBuffer = null; } this.fragPlaying = null; @@ -543,12 +540,12 @@ export default class StreamController super.onMediaDetaching(); } - private onMediaPlaying() { + private onMediaPlaying = () => { // tick to speed up FRAG_CHANGED triggering this.tick(); - } + }; - private onMediaSeeked() { + private onMediaSeeked = () => { const media = this.media; const currentTime = media ? media.currentTime : null; if (Number.isFinite(currentTime)) { @@ -568,7 +565,7 @@ export default class StreamController // tick to speed up FRAG_CHANGED triggering this.tick(); - } + }; private onManifestLoading() { // reset buffer on manifest loading diff --git a/src/controller/subtitle-track-controller.ts b/src/controller/subtitle-track-controller.ts index 75e28294a9b..1c8616f9bdd 100644 --- a/src/controller/subtitle-track-controller.ts +++ b/src/controller/subtitle-track-controller.ts @@ -35,11 +35,12 @@ class SubtitleTrackController extends BasePlaylistController { private currentTrack: MediaPlaylist | null = null; private selectDefaultTrack: boolean = true; private queuedDefaultTrack: number = -1; - private asyncPollTrackChange: () => void = () => this.pollTrackChange(0); private useTextTrackPolling: boolean = false; private subtitlePollingInterval: number = -1; private _subtitleDisplay: boolean = true; + private asyncPollTrackChange = () => this.pollTrackChange(0); + constructor(hls: Hls) { super(hls, '[subtitle-track-controller]'); this.registerListeners(); @@ -50,7 +51,8 @@ class SubtitleTrackController extends BasePlaylistController { this.tracks.length = 0; this.tracksInGroup.length = 0; this.currentTrack = null; - this.onTextTracksChanged = this.asyncPollTrackChange = null as any; + // @ts-ignore + this.onTextTracksChanged = this.asyncPollTrackChange = null; super.destroy(); } diff --git a/tests/unit/controller/latency-controller.ts b/tests/unit/controller/latency-controller.ts index 26ea06bec06..360ffd77db7 100644 --- a/tests/unit/controller/latency-controller.ts +++ b/tests/unit/controller/latency-controller.ts @@ -79,7 +79,7 @@ describe('LatencyController', function () { currentTimeStub.get(() => currentTime); currentTimeStub.set((value: number) => { currentTime = value; - latencyController['timeupdate'](); + latencyController['onTimeupdate'](); }); });