From 16c1810b0321724b0daa44cf7f4736b0b0983153 Mon Sep 17 00:00:00 2001 From: Aidan Ridley Date: Mon, 9 Aug 2021 19:11:25 -0600 Subject: [PATCH] Feat(player): Add updateStartTime method to play (#3491) This provides a way to decide on a start time after the manifestparsed event, but before the load process ends. --- lib/cast/cast_utils.js | 1 + lib/player.js | 31 +++++++++++++++++++++++++++++++ test/player_integration.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/lib/cast/cast_utils.js b/lib/cast/cast_utils.js index 67990454f1..d50a1f9c7c 100644 --- a/lib/cast/cast_utils.js +++ b/lib/cast/cast_utils.js @@ -388,6 +388,7 @@ shaka.cast.CastUtils.PlayerVoidMethods = [ 'selectVariantsByLabel', 'setTextTrackVisibility', 'trickPlay', + 'updateStartTime', 'goToLive', ]; diff --git a/lib/player.js b/lib/player.js index a1eec70e5a..82cf400f8d 100644 --- a/lib/player.js +++ b/lib/player.js @@ -533,6 +533,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget { /** @private {!Array.} */ this.cleanupOnUnload_ = []; + /** + * This playback start position will be used when + * updateStartTime() has been called to provide an updated + * start position during the media loading process. + * + * @private {?number} + */ + this.updatedStartTime_ = null; + if (dependencyInjector) { dependencyInjector(this); } @@ -1046,6 +1055,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return this.wrapWalkerListenersWithPromise_(events); } + /** + * Provides a way to update the stream start position during the media loading + * process. Can for example be called from the manifestparsed + * event handler to update the start position based on information in the + * manifest. + * + * @param {number} startTime + * @export + */ + updateStartTime(startTime) { + this.updatedStartTime_ = startTime; + } + /** * Tell the player to load the content at assetUri and start * playback at startTime. Before calling load, @@ -1066,6 +1088,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @export */ load(assetUri, startTime, mimeType) { + this.updatedStartTime_ = null; + // Do not allow the player to be used after |destroy| is called. if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) { return Promise.reject(this.createAbortLoadError_()); @@ -1804,6 +1828,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // something we are now depending on. has.startTime = wants.startTime; + // If updateStartTime() has been called since load() was invoked use the + // requested startTime + if (this.updatedStartTime_ != null) { + has.startTime = this.updatedStartTime_; + this.updatedStartTime_ = null; + } + // Store a reference to values in |has| after asserting so that closure will // know that they will still be non-null between calls to await. const mediaElement = has.mediaElement; diff --git a/test/player_integration.js b/test/player_integration.js index 8281958386..0560485174 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -87,6 +87,41 @@ describe('Player', () => { }); }); // describe('attach') + describe('updateStartTime() in manifestparsed event handler', () => { + it('does not get segments prior to startTime', async () => { + player.addEventListener('manifestparsed', () => { + player.updateStartTime(24); + }); + const results = { + requestedVideoSegment0: false, + requestedVideoSegment1: false, + requestedVideoSegment2: false, + }; + const expected = { + requestedVideoSegment0: false, + requestedVideoSegment1: false, + requestedVideoSegment2: true, + }; + player.getNetworkingEngine().registerRequestFilter( + (type, request) => { + if (request.uris[0] == 'test:sintel/video/0') { + results.requestedVideoSegment0 = true; + } + if (request.uris[0] == 'test:sintel/video/1') { + results.requestedVideoSegment1 = true; + } + if (request.uris[0] == 'test:sintel/video/2') { + results.requestedVideoSegment2 = true; + } + }); + await player.load('test:sintel_compiled'); + video.play(); + await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 25, 30); + expect(results).toEqual(expected); + }); + }); + + describe('getStats', () => { it('gives stats about current stream', async () => { // This is tested more in player_unit.js. This is here to test the public