From 6c71b0ee63fce62c9074788e255363dbbc9ba4e1 Mon Sep 17 00:00:00 2001 From: baconz Date: Sun, 2 Jul 2023 23:07:29 -0700 Subject: [PATCH] fix: gap jumping when gap exists at start position (#5384) Before playback starts the video element reports as seeking == true, but because we haven't installed our seek listener yet, the gap controller does not receive the seek event. To work around this, we explicitly tell the gap controller when playback starts so that it knows the startup position, and can synthesize a seek event. --- lib/media/gap_jumping_controller.js | 19 +++++++++++++++++-- lib/media/playhead.js | 11 +++++++++++ lib/media/video_wrapper.js | 7 ++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/media/gap_jumping_controller.js b/lib/media/gap_jumping_controller.js index cea9059c58..27d93ab6c1 100644 --- a/lib/media/gap_jumping_controller.js +++ b/lib/media/gap_jumping_controller.js @@ -58,6 +58,9 @@ shaka.media.GapJumpingController = class { /** @private {number} */ this.prevReadyState_ = video.readyState; + /** @private {number} */ + this.startTime_ = 0; + /** @private {number} */ this.gapsJumped_ = 0; @@ -123,6 +126,18 @@ shaka.media.GapJumpingController = class { this.onPollGapJump_(); } + /** + * Called when playback has started and the video element is + * listening for seeks. + * + * @param {number} startTime + */ + onStarted(startTime) { + if (this.video_.seeking && !this.seekingEventReceived_) { + this.seekingEventReceived_ = true; + this.startTime_ = startTime; + } + } /** Called when a seek has started. */ onSeeking() { @@ -164,8 +179,8 @@ shaka.media.GapJumpingController = class { // while paused on a livestream. We make an exception for time 0, since we // may be _required_ to seek on startup before play can begin, but only if // autoplay is enabled. - if (this.video_.paused && (this.video_.currentTime != 0 || - (!this.video_.autoplay && this.video_.currentTime == 0))) { + if (this.video_.paused && (this.video_.currentTime != this.startTime_ || + (!this.video_.autoplay && this.video_.currentTime == this.startTime_))) { return; } diff --git a/lib/media/playhead.js b/lib/media/playhead.js index b788dcd095..a42fc3f860 100644 --- a/lib/media/playhead.js +++ b/lib/media/playhead.js @@ -251,6 +251,7 @@ shaka.media.MediaSourcePlayhead = class { this.videoWrapper_ = new shaka.media.VideoWrapper( mediaElement, () => this.onSeeking_(), + (realStartTime) => this.onStarted_(realStartTime), () => this.getStartTime_(startTime)); /** @type {shaka.util.Timer} */ @@ -390,6 +391,16 @@ shaka.media.MediaSourcePlayhead = class { } } + /** + * Called when the video element has started up and is listening for new seeks + * + * @param {number} startTime + * @private + */ + onStarted_(startTime) { + this.gapController_.onStarted(startTime); + } + /** * Handles when a seek happens on the video. * diff --git a/lib/media/video_wrapper.js b/lib/media/video_wrapper.js index 67f49ad6df..c67c7c67bc 100644 --- a/lib/media/video_wrapper.js +++ b/lib/media/video_wrapper.js @@ -27,15 +27,19 @@ shaka.media.VideoWrapper = class { /** * @param {!HTMLMediaElement} video * @param {function()} onSeek Called when the video seeks. + * @param {function(number)} onStarted Called when the video has started. * @param {function():number} getStartTime Calle to get the time to start at. */ - constructor(video, onSeek, getStartTime) { + constructor(video, onSeek, onStarted, getStartTime) { /** @private {HTMLMediaElement} */ this.video_ = video; /** @private {function()} */ this.onSeek_ = onSeek; + /** @private {function(number)} */ + this.onStarted_ = onStarted; + /** @private {?number} */ this.startTime_ = null; @@ -173,6 +177,7 @@ shaka.media.VideoWrapper = class { this.started_ = true; this.eventManager_.listen(this.video_, 'seeking', () => this.onSeek_()); + this.onStarted_(this.video_.currentTime); } };