Skip to content

Commit 831961b

Browse files
brandonocaseygkatsev
authored andcommitted
fix(liveui): seek to live should be immediate and other tweaks (videojs#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.
1 parent 62f9e78 commit 831961b

File tree

3 files changed

+43
-38
lines changed

3 files changed

+43
-38
lines changed

src/js/control-bar/progress-control/seek-bar.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class SeekBar extends Slider {
5252
this.on(this.player_, 'timeupdate', this.update);
5353
this.on(this.player_, 'ended', this.handleEnded);
5454
this.on(this.player_, 'durationchange', this.update);
55+
this.on(this.player_.liveTracker, 'liveedgechange', this.update);
5556

5657
// when playing, let's ensure we smoothly update the play progress bar
5758
// via an interval
@@ -109,7 +110,7 @@ class SeekBar extends Slider {
109110
let duration = this.player_.duration();
110111

111112
if (liveTracker.isLive()) {
112-
duration = this.player_.liveTracker.seekableEnd();
113+
duration = this.player_.liveTracker.liveCurrentTime();
113114
}
114115

115116
if (liveTracker.seekableEnd() === Infinity) {
@@ -255,12 +256,7 @@ class SeekBar extends Slider {
255256
}
256257
} else {
257258
const seekableStart = liveTracker.seekableStart();
258-
const seekableEnd = liveTracker.seekableEnd();
259-
260-
if (distance === 1) {
261-
liveTracker.seekToLiveEdge();
262-
return;
263-
}
259+
const seekableEnd = liveTracker.liveCurrentTime();
264260

265261
newTime = seekableStart + (distance * liveTracker.liveWindow());
266262

src/js/live-tracker.js

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class LiveTracker extends Component {
1616
}
1717

1818
isBehind_() {
19+
// don't report that we are behind until a timeupdate has been seen
20+
if (!this.timeupdateSeen_) {
21+
return false;
22+
}
1923
const liveCurrentTime = this.liveCurrentTime();
2024
const currentTime = this.player_.currentTime();
2125
const seekableIncrement = this.seekableIncrement_;
@@ -49,7 +53,7 @@ class LiveTracker extends Component {
4953
// end against current time, with a fudge value of half a second.
5054
if (newSeekEnd !== this.lastSeekEnd_) {
5155
if (this.lastSeekEnd_) {
52-
this.seekableIncrement_ = newSeekEnd - this.lastSeekEnd_;
56+
this.seekableIncrement_ = Math.abs(newSeekEnd - this.lastSeekEnd_);
5357
}
5458

5559
this.pastSeekEnd_ = 0;
@@ -90,6 +94,21 @@ class LiveTracker extends Component {
9094

9195
this.on(this.player_, 'play', this.trackLive_);
9296
this.on(this.player_, 'pause', this.trackLive_);
97+
this.one(this.player_, 'play', this.handlePlay);
98+
99+
// this is to prevent showing that we are not live
100+
// before a video starts to play
101+
if (!this.timeupdateSeen_) {
102+
this.handleTimeupdate = () => {
103+
this.timeupdateSeen_ = true;
104+
this.handleTimeupdate = null;
105+
};
106+
this.one(this.player_, 'timeupdate', this.handleTimeupdate);
107+
}
108+
}
109+
110+
handlePlay() {
111+
this.one(this.player_, 'timeupdate', this.seekToLiveEdge);
93112
}
94113

95114
/**
@@ -100,13 +119,20 @@ class LiveTracker extends Component {
100119
this.pastSeekEnd_ = 0;
101120
this.lastSeekEnd_ = null;
102121
this.behindLiveEdge_ = null;
122+
this.timeupdateSeen_ = false;
103123

104124
this.clearInterval(this.trackingInterval_);
105125
this.trackingInterval_ = null;
106126
this.seekableIncrement_ = 12;
107127

108128
this.off(this.player_, 'play', this.trackLive_);
109129
this.off(this.player_, 'pause', this.trackLive_);
130+
this.off(this.player_, 'play', this.handlePlay);
131+
this.off(this.player_, 'timeupdate', this.seekToLiveEdge);
132+
if (this.handleTimeupdate) {
133+
this.off(this.player_, 'timeupdate', this.handleTimeupdate);
134+
this.handleTimeupdate = null;
135+
}
110136
}
111137

112138
/**
@@ -159,13 +185,13 @@ class LiveTracker extends Component {
159185
* Get the live time window
160186
*/
161187
liveWindow() {
162-
const seekableEnd = this.seekableEnd();
188+
const liveCurrentTime = this.liveCurrentTime();
163189

164-
if (seekableEnd === Infinity) {
190+
if (liveCurrentTime === Infinity) {
165191
return Infinity;
166192
}
167193

168-
return seekableEnd - this.seekableStart();
194+
return liveCurrentTime - this.seekableStart();
169195
}
170196

171197
/**
@@ -218,13 +244,11 @@ class LiveTracker extends Component {
218244
return;
219245
}
220246

221-
this.player().pause();
222-
this.player().addClass('vjs-waiting');
223-
this.one('seekableendchange', () => {
224-
this.player().removeClass('vjs-waiting');
225-
this.player().currentTime(this.seekableEnd());
226-
this.player().play();
227-
});
247+
this.player_.currentTime(this.liveCurrentTime());
248+
249+
if (this.player_.paused()) {
250+
this.player_.play();
251+
}
228252
}
229253

230254
dispose() {

test/unit/live-tracker.test.js

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ QUnit.module('LiveTracker', () => {
6666
});
6767

6868
QUnit.test('Triggers liveedgechange when we fall behind and catch up', function(assert) {
69+
this.player.trigger('timeupdate');
6970
this.player.currentTime = () => 0;
7071
this.clock.tick(20000);
7172

@@ -94,10 +95,9 @@ QUnit.module('LiveTracker', () => {
9495
});
9596

9697
QUnit.test('seeks to live edge on seekableendchange', function(assert) {
98+
this.player.trigger('timeupdate');
9799

98100
this.liveTracker.seekableIncrement_ = 2;
99-
let pauseCalls = 0;
100-
let playCalls = 0;
101101
let currentTime = 0;
102102

103103
this.player.currentTime = (ct) => {
@@ -107,28 +107,13 @@ QUnit.module('LiveTracker', () => {
107107
return 0;
108108
};
109109

110-
this.player.play = () => {
111-
playCalls++;
112-
};
113-
114-
this.player.pause = () => {
115-
pauseCalls++;
116-
};
117110
this.clock.tick(3000);
118111

119112
assert.ok(this.liveTracker.pastSeekEnd() > 2, 'pastSeekEnd should be over 2s');
120113

121114
this.liveTracker.seekToLiveEdge();
122115

123-
assert.ok(this.player.hasClass('vjs-waiting'), 'player should be waiting');
124-
assert.equal(pauseCalls, 1, 'should be paused');
125-
this.player.seekable = () => createTimeRanges(0, 2);
126-
127-
this.clock.tick(30);
128-
assert.equal(this.seekableEndChanges, 1, 'should be one seek end change');
129-
assert.equal(currentTime, 2, 'should have seeked to seekableEnd');
130-
assert.equal(playCalls, 1, 'should be playing');
131-
assert.notOk(this.player.hasClass('vjs-waiting'), 'player should not be waiting');
116+
assert.equal(currentTime, this.liveTracker.liveCurrentTime(), 'should have seeked to liveCurrentTime');
132117
});
133118

134119
QUnit.test('does not seek to to live edge if at live edge', function(assert) {
@@ -169,15 +154,15 @@ QUnit.module('LiveTracker', () => {
169154
QUnit.test('single seekable, helpers should be correct', function(assert) {
170155
// simple
171156
this.player.seekable = () => createTimeRanges(10, 50);
172-
assert.strictEqual(this.liveTracker.liveWindow(), 40, 'liveWindow is 40s');
157+
assert.strictEqual(this.liveTracker.liveWindow(), 40.03, 'liveWindow is 40s');
173158
assert.strictEqual(this.liveTracker.seekableStart(), 10, 'seekableStart is 10s');
174159
assert.strictEqual(this.liveTracker.seekableEnd(), 50, 'seekableEnd is 50s');
175160
});
176161

177162
QUnit.test('multiple seekables, helpers should be correct', function(assert) {
178163
// multiple
179164
this.player.seekable = () => createTimeRanges([[0, 1], [2, 3], [4, 5]]);
180-
assert.strictEqual(this.liveTracker.liveWindow(), 5, 'liveWindow is 5s');
165+
assert.strictEqual(this.liveTracker.liveWindow(), 5.03, 'liveWindow is 5s');
181166
assert.strictEqual(this.liveTracker.seekableStart(), 0, 'seekableStart is 0s');
182167
assert.strictEqual(this.liveTracker.seekableEnd(), 5, 'seekableEnd is 5s');
183168
});

0 commit comments

Comments
 (0)