From da14ae427c951c7af39f9a2b50a4cb3a89957ede Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 30 Mar 2022 19:26:41 -0700 Subject: [PATCH] fix: Fix exceptions when quickly shutting down src= on Safari (#4088) Some events and timers were used to process track changes with src= playback on Safari, but they did not properly clean up when the player was unloaded or destroyed. In the case that this happened quickly after starting playback, exceptions would be thrown or tracks could manipulated after new content began. This fixes the cleanup of these timers and events to be aware of Player unloads or destruction. Closes #4087 --- lib/player.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/player.js b/lib/player.js index ab20d040c8..158c5da572 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2120,6 +2120,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.playhead_ = new shaka.media.SrcEqualsPlayhead(has.mediaElement); + // This flag is used below in the language preference setup and + // track-management to check if this load was canceled before the necessary + // events fired. + let unloaded = false; + this.cleanupOnUnload_.push(() => { + unloaded = true; + }); + if (has.startTime != null) { this.playhead_.setStartTime(has.startTime); } @@ -2171,6 +2179,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } if (this.video_.textTracks) { this.eventManager_.listen(this.video_.textTracks, 'addtrack', (e) => { + // If we have moved on to another piece of content while waiting for + // the above event, we should not process tracks here. + if (unloaded) { + return; + } + this.onTracksChanged_(); this.processTimedMetadataSrcEqls_(/** @type {!TrackEvent} */(e)); }); @@ -2212,13 +2226,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { fullyLoaded.resolve(); }); - // This flag is used below in the language preference setup to check if this - // load was canceled before the necessary events fire. - let unloaded = false; - this.cleanupOnUnload_.push(() => { - unloaded = true; - }); - // We can't switch to preferred languages, though, until the data is loaded. shaka.util.MediaReadyState.waitForReadyState(this.video_, HTMLMediaElement.HAVE_CURRENT_DATA, @@ -2376,12 +2383,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // In Safari the initial assignment does not always work, so we schedule // this process to be repeated several times to ensure that it has been put // in the correct mode. - new shaka.util.Timer(() => { + const timer = new shaka.util.Timer(() => { const textTracks = this.getMetadataTracks_(); for (const textTrack of textTracks) { textTrack.mode = 'hidden'; } - }).tickNow().tickAfter(/* seconds= */ 0.5); + }).tickNow().tickAfter(0.5); + + this.cleanupOnUnload_.push(() => { + timer.stop(); + }); }