1
0
mirror of https://github.com/videojs/video.js.git synced 2024-12-02 09:11:54 +02:00

fix: user and programmatic seeks with live streams (#7210)

This commit is contained in:
Brandon Casey 2021-05-10 18:42:17 -04:00 committed by GitHub
parent d4a08deb10
commit 39485fc4c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 14 deletions

View File

@ -186,6 +186,21 @@ class SeekBar extends Slider {
return percent;
}
/**
* Prevent liveThreshold from causing seeks to seem like they
* are not happening from a user perspective.
*
* @param {number} ct
* current time to seek to
*/
userSeek_(ct) {
if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {
this.player_.liveTracker.nextSeekedFromUser();
}
this.player_.currentTime(ct);
}
/**
* Get the value of current time but allows for smooth scrubbing,
* when player can't keep up.
@ -303,7 +318,7 @@ class SeekBar extends Slider {
}
// Set new time (tell player to seek to new time)
this.player_.currentTime(newTime);
this.userSeek_(newTime);
}
enable() {
@ -366,14 +381,14 @@ class SeekBar extends Slider {
* Move more quickly fast forward for keyboard-only users
*/
stepForward() {
this.player_.currentTime(this.player_.currentTime() + STEP_SECONDS);
this.userSeek_(this.player_.currentTime() + STEP_SECONDS);
}
/**
* Move more quickly rewind for keyboard-only users
*/
stepBack() {
this.player_.currentTime(this.player_.currentTime() - STEP_SECONDS);
this.userSeek_(this.player_.currentTime() - STEP_SECONDS);
}
/**
@ -409,6 +424,8 @@ class SeekBar extends Slider {
* @listens keydown
*/
handleKeyDown(event) {
const liveTracker = this.player_.liveTracker;
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
event.preventDefault();
event.stopPropagation();
@ -416,25 +433,33 @@ class SeekBar extends Slider {
} else if (keycode.isEventKey(event, 'Home')) {
event.preventDefault();
event.stopPropagation();
this.player_.currentTime(0);
this.userSeek_(0);
} else if (keycode.isEventKey(event, 'End')) {
event.preventDefault();
event.stopPropagation();
this.player_.currentTime(this.player_.duration());
if (liveTracker && liveTracker.isLive()) {
this.userSeek_(liveTracker.liveCurrentTime());
} else {
this.userSeek_(this.player_.duration());
}
} else if (/^[0-9]$/.test(keycode(event))) {
event.preventDefault();
event.stopPropagation();
const gotoFraction = (keycode.codes[keycode(event)] - keycode.codes['0']) * 10.0 / 100.0;
this.player_.currentTime(this.player_.duration() * gotoFraction);
if (liveTracker && liveTracker.isLive()) {
this.userSeek_(liveTracker.seekableStart() + (liveTracker.liveWindow() * gotoFraction));
} else {
this.userSeek_(this.player_.duration() * gotoFraction);
}
} else if (keycode.isEventKey(event, 'PgDn')) {
event.preventDefault();
event.stopPropagation();
this.player_.currentTime(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
this.userSeek_(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
} else if (keycode.isEventKey(event, 'PgUp')) {
event.preventDefault();
event.stopPropagation();
this.player_.currentTime(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
this.userSeek_(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
} else {
// Pass keydown handling up for unsupported keys
super.handleKeyDown(event);

View File

@ -191,8 +191,8 @@ class LiveTracker extends Component {
handleSeeked() {
const timeDiff = Math.abs(this.liveCurrentTime() - this.player_.currentTime());
this.seekedBehindLive_ = this.skipNextSeeked_ ? false : timeDiff > 2;
this.skipNextSeeked_ = false;
this.seekedBehindLive_ = this.nextSeekedFromUser_ && timeDiff > 2;
this.nextSeekedFromUser_ = false;
this.trackLive_();
}
@ -215,7 +215,7 @@ class LiveTracker extends Component {
this.behindLiveEdge_ = true;
this.timeupdateSeen_ = false;
this.seekedBehindLive_ = false;
this.skipNextSeeked_ = false;
this.nextSeekedFromUser_ = false;
this.clearInterval(this.trackingInterval_);
this.trackingInterval_ = null;
@ -227,6 +227,15 @@ class LiveTracker extends Component {
this.off(this.player_, 'timeupdate', this.seekToLiveEdge_);
}
/**
* The next seeked event is from the user. Meaning that any seek
* > 2s behind live will be considered behind live for real and
* liveTolerance will be ignored.
*/
nextSeekedFromUser() {
this.nextSeekedFromUser_ = true;
}
/**
* stop tracking live playback
*/
@ -375,8 +384,7 @@ class LiveTracker extends Component {
if (this.atLiveEdge()) {
return;
}
// skipNextSeeked_
this.skipNextSeeked_ = true;
this.nextSeekedFromUser_ = false;
this.player_.currentTime(this.liveCurrentTime());
}

View File

@ -148,7 +148,7 @@ QUnit.module('LiveTracker', () => {
assert.ok(this.liveTracker.behindLiveEdge(), 'behindLiveEdge live edge');
});
QUnit.test('is behindLiveEdge when seeking backwards', function(assert) {
QUnit.test('is behindLiveEdge when seeking behind liveTolerance with API', function(assert) {
this.liveTracker.options_.liveTolerance = 6;
this.player.seekable = () => createTimeRanges(0, 20);
this.player.trigger('timeupdate');
@ -157,6 +157,23 @@ QUnit.module('LiveTracker', () => {
assert.ok(this.liveTracker.atLiveEdge(), 'at live edge');
this.player.currentTime = () => 14;
this.player.trigger('seeked');
assert.equal(this.liveEdgeChanges, 1, 'should have one live edge change');
assert.ok(this.liveTracker.behindLiveEdge(), 'behindLiveEdge live edge');
});
QUnit.test('is behindLiveEdge when seeking >2s behind with ui', function(assert) {
this.liveTracker.options_.liveTolerance = 6;
this.player.seekable = () => createTimeRanges(0, 20);
this.player.trigger('timeupdate');
this.player.currentTime = () => 20;
this.clock.tick(1000);
assert.ok(this.liveTracker.atLiveEdge(), 'at live edge');
this.liveTracker.nextSeekedFromUser();
this.player.currentTime = () => 17;
this.player.trigger('seeked');