From ca08230fbe85d66176c7fa1fb4f9782d0ab364fc 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 b22b502372..7e4892caa1 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2217,6 +2217,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); } @@ -2268,6 +2276,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; @@ -2327,13 +2341,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, @@ -2488,12 +2495,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(); + }); } @@ -2561,12 +2572,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(); + }); } /**