From 28cb9fd4dc24522f772aa214bd0c4493bd1ff0d3 Mon Sep 17 00:00:00 2001 From: Adam Waldron Date: Tue, 16 Jul 2024 22:28:30 -0700 Subject: [PATCH] fix: fastQualitySwitch stability (#1525) --- src/playlist-controller.js | 9 +--- test/playlist-controller.test.js | 70 +++++++------------------------- 2 files changed, 17 insertions(+), 62 deletions(-) diff --git a/src/playlist-controller.js b/src/playlist-controller.js index 1a32bb9b3..46708c829 100644 --- a/src/playlist-controller.js +++ b/src/playlist-controller.js @@ -1059,15 +1059,10 @@ export class PlaylistController extends videojs.EventTarget { runFastQualitySwitch_() { this.waitingForFastQualityPlaylistReceived_ = false; - // Delete all buffered data to allow an immediate quality switch, then seek to give - // the browser a kick to remove any cached frames from the previous rendtion (.04 seconds - // ahead was roughly the minimum that will accomplish this across a variety of content - // in IE and Edge, but seeking in place is sufficient on all other browsers) - // Edge/IE bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14600375/ - // Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=651904 + // Delete all buffered data to allow an immediate quality switch. this.mainSegmentLoader_.pause(); this.mainSegmentLoader_.resetEverything(() => { - this.tech_.setCurrentTime(this.tech_.currentTime()); + this.mainSegmentLoader_.load(); }); // don't need to reset audio as it is reset when media changes diff --git a/test/playlist-controller.test.js b/test/playlist-controller.test.js index ebded8451..a58e7aa3c 100644 --- a/test/playlist-controller.test.js +++ b/test/playlist-controller.test.js @@ -688,10 +688,11 @@ QUnit.test( } ); -QUnit.test('resets everything for a fast quality change', function(assert) { +QUnit.test('resets everything for a fast quality change then calls load', function(assert) { let resyncs = 0; let resets = 0; let removeFuncArgs = {}; + const done = assert.async(); this.playlistController.mediaSource.trigger('sourceopen'); // main @@ -709,16 +710,24 @@ QUnit.test('resets everything for a fast quality change', function(assert) { const origResetEverything = segmentLoader.resetEverything; const origRemove = segmentLoader.remove; + const origLoad = segmentLoader.load; - segmentLoader.resetEverything = () => { + // ensure load is called + segmentLoader.load = () => { + done(); + origLoad.call(segmentLoader); + }; + + segmentLoader.resetEverything = (doneFn) => { resets++; - origResetEverything.call(segmentLoader); + origResetEverything.call(segmentLoader, doneFn); }; - segmentLoader.remove = (start, end) => { + segmentLoader.remove = (start, end, doneFn) => { assert.equal(end, Infinity, 'on a remove all, end should be Infinity'); - - origRemove.call(segmentLoader, start, end); + assert.ok(doneFn); + doneFn(); + origRemove.call(segmentLoader, start, end, doneFn); }; segmentLoader.startingMediaInfo_ = { hasVideo: true }; @@ -777,55 +786,6 @@ QUnit.test('loadVttJs should be passed to the vttSegmentLoader and rejected on v }); }); -QUnit.test('seeks in place for fast quality switch on non-IE/Edge browsers', function(assert) { - let seeks = 0; - - this.playlistController.mediaSource.trigger('sourceopen'); - // main - this.standardXHRResponse(this.requests.shift()); - // media - this.standardXHRResponse(this.requests.shift()); - - const segmentLoader = this.playlistController.mainSegmentLoader_; - - return requestAndAppendSegment({ - request: this.requests.shift(), - segmentLoader, - clock: this.clock - }).then(() => { - // media is changed - this.playlistController.selectPlaylist = () => { - const playlists = this.playlistController.main().playlists; - const currentPlaylist = this.playlistController.media(); - - return playlists.find((playlist) => playlist !== currentPlaylist); - }; - - this.player.tech_.on('seeking', function() { - seeks++; - }); - - const timeBeforeSwitch = this.player.currentTime(); - - // mock buffered values so removes are processed - segmentLoader.sourceUpdater_.audioBuffer.buffered = createTimeRanges([[0, 10]]); - segmentLoader.sourceUpdater_.videoBuffer.buffered = createTimeRanges([[0, 10]]); - - this.playlistController.runFastQualitySwitch_(); - // trigger updateend to indicate the end of the remove operation - segmentLoader.sourceUpdater_.audioBuffer.trigger('updateend'); - segmentLoader.sourceUpdater_.videoBuffer.trigger('updateend'); - this.clock.tick(1); - - assert.equal( - this.player.currentTime(), - timeBeforeSwitch, - 'current time remains the same on fast quality switch' - ); - assert.equal(seeks, 1, 'seek event occurs on fast quality switch'); - }); -}); - QUnit.test('basic timeToLoadedData, mediaAppends, appendsToLoadedData stats', function(assert) { this.player.tech_.trigger('loadstart'); this.playlistController.mediaSource.trigger('sourceopen');