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:
parent
62f9e78cf2
commit
831961b373
@ -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());
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user