From 8ed53a35e29041b7361dfa5d80acbe33d12026fc 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 | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/player.js b/lib/player.js index 9a6f8dc236..6c6e0123e0 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2110,6 +2110,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); } @@ -2161,6 +2169,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; + } + const trackEvent = /** @type {!TrackEvent} */(e); if (trackEvent.track) { const track = trackEvent.track; @@ -2216,13 +2230,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, @@ -2377,12 +2384,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(); + }); } @@ -2450,12 +2461,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 chaptersTracks = this.getChaptersTracks_(); for (const chaptersTrack of chaptersTracks) { chaptersTrack.mode = 'hidden'; } - }).tickNow().tickAfter(/* seconds= */ 0.5); + }).tickNow().tickAfter(0.5); + + this.cleanupOnUnload_.push(() => { + timer.stop(); + }); } /**