1
0
mirror of https://github.com/videojs/video.js.git synced 2024-11-24 08:42:25 +02:00

fix(liveui): seek to live should be immediate and other tweaks (#5650)

- Make sure that we seek to live playback on the first timeupdate
- Do not report that we are not live before playback has started (a timeupdate has been seen)
- Prevent negative seekable increments
- We can seek past the seekable value in the video element, so we use that to seek to live, rather than waiting for a seekable end change.
This commit is contained in:
Brandon Casey 2018-12-06 15:15:18 -05:00 committed by Gary Katsevman
parent 62f9e78cf2
commit 831961b373
3 changed files with 43 additions and 38 deletions

View File

@ -52,6 +52,7 @@ class SeekBar extends Slider {
this.on(this.player_, 'timeupdate', this.update);
this.on(this.player_, 'ended', this.handleEnded);
this.on(this.player_, 'durationchange', this.update);
this.on(this.player_.liveTracker, 'liveedgechange', this.update);
// when playing, let's ensure we smoothly update the play progress bar
// via an interval
@ -109,7 +110,7 @@ class SeekBar extends Slider {
let duration = this.player_.duration();
if (liveTracker.isLive()) {
duration = this.player_.liveTracker.seekableEnd();
duration = this.player_.liveTracker.liveCurrentTime();
}
if (liveTracker.seekableEnd() === Infinity) {
@ -255,12 +256,7 @@ class SeekBar extends Slider {
}
} else {
const seekableStart = liveTracker.seekableStart();
const seekableEnd = liveTracker.seekableEnd();
if (distance === 1) {
liveTracker.seekToLiveEdge();
return;
}
const seekableEnd = liveTracker.liveCurrentTime();
newTime = seekableStart + (distance * liveTracker.liveWindow());

View File

@ -16,6 +16,10 @@ class LiveTracker extends Component {
}
isBehind_() {
// don't report that we are behind until a timeupdate has been seen
if (!this.timeupdateSeen_) {
return false;
}
const liveCurrentTime = this.liveCurrentTime();
const currentTime = this.player_.currentTime();
const seekableIncrement = this.seekableIncrement_;
@ -49,7 +53,7 @@ class LiveTracker extends Component {
// end against current time, with a fudge value of half a second.
if (newSeekEnd !== this.lastSeekEnd_) {
if (this.lastSeekEnd_) {
this.seekableIncrement_ = newSeekEnd - this.lastSeekEnd_;
this.seekableIncrement_ = Math.abs(newSeekEnd - this.lastSeekEnd_);
}
this.pastSeekEnd_ = 0;
@ -90,6 +94,21 @@ class LiveTracker extends Component {
this.on(this.player_, 'play', this.trackLive_);
this.on(this.player_, 'pause', this.trackLive_);
this.one(this.player_, 'play', this.handlePlay);
// this is to prevent showing that we are not live
// before a video starts to play
if (!this.timeupdateSeen_) {
this.handleTimeupdate = () => {
this.timeupdateSeen_ = true;
this.handleTimeupdate = null;
};
this.one(this.player_, 'timeupdate', this.handleTimeupdate);
}
}
handlePlay() {
this.one(this.player_, 'timeupdate', this.seekToLiveEdge);
}
/**
@ -100,6 +119,7 @@ class LiveTracker extends Component {
this.pastSeekEnd_ = 0;
this.lastSeekEnd_ = null;
this.behindLiveEdge_ = null;
this.timeupdateSeen_ = false;
this.clearInterval(this.trackingInterval_);
this.trackingInterval_ = null;
@ -107,6 +127,12 @@ class LiveTracker extends Component {
this.off(this.player_, 'play', this.trackLive_);
this.off(this.player_, 'pause', this.trackLive_);
this.off(this.player_, 'play', this.handlePlay);
this.off(this.player_, 'timeupdate', this.seekToLiveEdge);
if (this.handleTimeupdate) {
this.off(this.player_, 'timeupdate', this.handleTimeupdate);
this.handleTimeupdate = null;
}
}
/**
@ -159,13 +185,13 @@ class LiveTracker extends Component {
* Get the live time window
*/
liveWindow() {
const seekableEnd = this.seekableEnd();
const liveCurrentTime = this.liveCurrentTime();
if (seekableEnd === Infinity) {
if (liveCurrentTime === Infinity) {
return Infinity;
}
return seekableEnd - this.seekableStart();
return liveCurrentTime - this.seekableStart();
}
/**
@ -218,13 +244,11 @@ class LiveTracker extends Component {
return;
}
this.player().pause();
this.player().addClass('vjs-waiting');
this.one('seekableendchange', () => {
this.player().removeClass('vjs-waiting');
this.player().currentTime(this.seekableEnd());
this.player().play();
});
this.player_.currentTime(this.liveCurrentTime());
if (this.player_.paused()) {
this.player_.play();
}
}
dispose() {

View File

@ -66,6 +66,7 @@ QUnit.module('LiveTracker', () => {
});
QUnit.test('Triggers liveedgechange when we fall behind and catch up', function(assert) {
this.player.trigger('timeupdate');
this.player.currentTime = () => 0;
this.clock.tick(20000);
@ -94,10 +95,9 @@ QUnit.module('LiveTracker', () => {
});
QUnit.test('seeks to live edge on seekableendchange', function(assert) {
this.player.trigger('timeupdate');
this.liveTracker.seekableIncrement_ = 2;
let pauseCalls = 0;
let playCalls = 0;
let currentTime = 0;
this.player.currentTime = (ct) => {
@ -107,28 +107,13 @@ QUnit.module('LiveTracker', () => {
return 0;
};
this.player.play = () => {
playCalls++;
};
this.player.pause = () => {
pauseCalls++;
};
this.clock.tick(3000);
assert.ok(this.liveTracker.pastSeekEnd() > 2, 'pastSeekEnd should be over 2s');
this.liveTracker.seekToLiveEdge();
assert.ok(this.player.hasClass('vjs-waiting'), 'player should be waiting');
assert.equal(pauseCalls, 1, 'should be paused');
this.player.seekable = () => createTimeRanges(0, 2);
this.clock.tick(30);
assert.equal(this.seekableEndChanges, 1, 'should be one seek end change');
assert.equal(currentTime, 2, 'should have seeked to seekableEnd');
assert.equal(playCalls, 1, 'should be playing');
assert.notOk(this.player.hasClass('vjs-waiting'), 'player should not be waiting');
assert.equal(currentTime, this.liveTracker.liveCurrentTime(), 'should have seeked to liveCurrentTime');
});
QUnit.test('does not seek to to live edge if at live edge', function(assert) {
@ -169,7 +154,7 @@ QUnit.module('LiveTracker', () => {
QUnit.test('single seekable, helpers should be correct', function(assert) {
// simple
this.player.seekable = () => createTimeRanges(10, 50);
assert.strictEqual(this.liveTracker.liveWindow(), 40, 'liveWindow is 40s');
assert.strictEqual(this.liveTracker.liveWindow(), 40.03, 'liveWindow is 40s');
assert.strictEqual(this.liveTracker.seekableStart(), 10, 'seekableStart is 10s');
assert.strictEqual(this.liveTracker.seekableEnd(), 50, 'seekableEnd is 50s');
});
@ -177,7 +162,7 @@ QUnit.module('LiveTracker', () => {
QUnit.test('multiple seekables, helpers should be correct', function(assert) {
// multiple
this.player.seekable = () => createTimeRanges([[0, 1], [2, 3], [4, 5]]);
assert.strictEqual(this.liveTracker.liveWindow(), 5, 'liveWindow is 5s');
assert.strictEqual(this.liveTracker.liveWindow(), 5.03, 'liveWindow is 5s');
assert.strictEqual(this.liveTracker.seekableStart(), 0, 'seekableStart is 0s');
assert.strictEqual(this.liveTracker.seekableEnd(), 5, 'seekableEnd is 5s');
});