Skip to content

Commit

Permalink
Fixes livestreams with no seek range.
Browse files Browse the repository at this point in the history
When the availability window of a live stream is very narrow, in
at least some cases, the playhead can end up starting before the
availability window. In that case, the stream will fail to load unless
gap jumping is set up to jump long gaps.
This makes the playhead jump ahead if it falls behind the availability
window, to avoid that situation (and others that might have the same
effect.)

Closes #916

Change-Id: I87f8c70ba6053d3524a1546e57d55cb6528cc683
  • Loading branch information
theodab authored and joeyparrish committed Aug 7, 2017
1 parent 4bfa3d2 commit 7f7e8cc
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
13 changes: 13 additions & 0 deletions lib/media/playhead.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,19 @@ shaka.media.Playhead.prototype.onPollGapJump_ = function() {
var currentTime = this.video_.currentTime;
var buffered = this.video_.buffered;

// If seeking is not possible, clamp the playhead manually here.
var timeline = this.manifest_.presentationTimeline;
var availabilityStart = timeline.getSegmentAvailabilityStart();
if (currentTime < availabilityStart) {
// The availability window has moved past the playhead.
// Move ahead to catch up.
var targetTime = this.reposition_(currentTime);
shaka.log.info('Jumping forward ' + (targetTime - currentTime) +
' seconds to catch up with the availability window.');
this.movePlayhead_(currentTime, targetTime);
return;
}

var gapIndex = shaka.media.TimeRangesUtils.getGapIndex(buffered, currentTime);

// The current time is unbuffered or is too far from a gap.
Expand Down
29 changes: 29 additions & 0 deletions test/media/playhead_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,35 @@ describe('Playhead', function() {
expect(onSeek).toHaveBeenCalled();
});

it('handles live manifests with no seek range', function() {
video.buffered = createFakeBuffered([{start: 1000, end: 1030}]);
video.readyState = HTMLMediaElement.HAVE_METADATA;

timeline.isLive.and.returnValue(true);
timeline.getSegmentAvailabilityStart.and.returnValue(1000);
timeline.getSegmentAvailabilityEnd.and.returnValue(1000);
timeline.getSegmentAvailabilityDuration.and.returnValue(1000);

playhead = new shaka.media.Playhead(
video,
manifest,
config,
5 /* startTime */,
Util.spyFunc(onSeek),
Util.spyFunc(onEvent));
expect(video.currentTime).toBe(1000);
video.on['seeking']();

// The availability window slips ahead.
timeline.getSegmentAvailabilityStart.and.returnValue(1030);
timeline.getSegmentAvailabilityEnd.and.returnValue(1030);
video.on['waiting']();
// We expect this to move to 15 seconds ahead of the start of the
// availability window, due to the rebuffering goal (10s) and the 5s
// for the Chromecast.
expect(video.currentTime).toBe(1045);
});

describe('clamps playhead after resuming', function() {
beforeEach(function() {
video.readyState = HTMLMediaElement.HAVE_METADATA;
Expand Down

0 comments on commit 7f7e8cc

Please sign in to comment.