7080865c by David LaPalomento

Merge pull request #515 from 'tenacex-feature/byterange-support-dev' into development

Add support for EXT-X-BYTERANGE
2 parents 2a8faddc 16f9203f
......@@ -894,7 +894,8 @@ videojs.HlsHandler.prototype.fillBuffer = function(mediaIndex) {
// we have entered a state where we are fetching the same segment,
// try to walk forward
if (this.lastSegmentLoaded_ &&
this.lastSegmentLoaded_ === this.playlistUriToUrl(segment.uri)) {
this.playlistUriToUrl(this.lastSegmentLoaded_.uri) === this.playlistUriToUrl(segment.uri) &&
this.lastSegmentLoaded_.byterange === segment.byterange) {
return this.fillBuffer(mediaIndex + 1);
}
......@@ -961,6 +962,29 @@ videojs.HlsHandler.prototype.playlistUriToUrl = function(segmentRelativeUrl) {
return playListUrl;
};
/* Turns segment byterange into a string suitable for use in
* HTTP Range requests
*/
videojs.HlsHandler.prototype.byterangeStr_ = function(byterange) {
var byterangeStart, byterangeEnd;
// `byterangeEnd` is one less than `offset + length` because the HTTP range
// header uses inclusive ranges
byterangeEnd = byterange.offset + byterange.length - 1;
byterangeStart = byterange.offset;
return "bytes=" + byterangeStart + "-" + byterangeEnd;
};
/* Defines headers for use in the xhr request for a particular segment.
*/
videojs.HlsHandler.prototype.segmentXhrHeaders_ = function(segment) {
var headers = {};
if ('byterange' in segment) {
headers['Range'] = this.byterangeStr_(segment.byterange);
}
return headers;
};
/*
* Sets `bandwidth`, `segmentXhrTime`, and appends to the `bytesReceived.
* Expects an object with:
......@@ -1054,7 +1078,8 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
// Set xhr timeout to 150% of the segment duration to allow us
// some time to switch renditions in the event of a catastrophic
// decrease in network performance or a server issue.
timeout: (segment.duration * 1.5) * 1000
timeout: (segment.duration * 1.5) * 1000,
headers: this.segmentXhrHeaders_(segment)
}, function(error, request) {
// This is a timeout of a previously aborted segment request
// so simply ignore it
......@@ -1085,7 +1110,7 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
return;
}
self.lastSegmentLoaded_ = segmentInfo.uri;
self.lastSegmentLoaded_ = segment;
self.setBandwidth(request);
if (segment.key) {
......
......@@ -28,9 +28,13 @@
request.timedout = false;
}
// videojs.xhr no longer consider status codes outside of 200 and 0 (for file uris) to be
// errors but the old XHR did so emulate that behavior
if (!error && response.statusCode !== 200 && response.statusCode !== 0) {
// videojs.xhr no longer considers status codes outside of 200 and 0
// (for file uris) to be errors, but the old XHR did, so emulate that
// behavior. Status 206 may be used in response to byterange requests.
if (!error &&
response.statusCode !== 200 &&
response.statusCode !== 206 &&
response.statusCode !== 0) {
error = new Error('XHR Failed with a response of: ' +
(request && (request.response || request.responseText)));
}
......
......@@ -324,6 +324,56 @@ test('starts playing if autoplay is specified', function() {
strictEqual(1, plays, 'play was called');
});
test('XHR requests first byte range on play', function() {
player.src({
src: 'manifest/playlist.m3u8',
type: 'application/vnd.apple.mpegurl'
});
player.tech_.triggerReady();
clock.tick(1);
player.tech_.trigger('play');
openMediaSource(player);
standardXHRResponse(requests[0]);
equal(requests[1].headers.Range, "bytes=0-522827");
});
test('Seeking requests correct byte range', function() {
player.src({
src: 'manifest/playlist.m3u8',
type: 'application/vnd.apple.mpegurl'
});
player.tech_.triggerReady();
clock.tick(1);
player.tech_.trigger('play');
openMediaSource(player);
standardXHRResponse(requests[0]);
player.tech_.hls.sourceBuffer.trigger('updateend');
clock.tick(1);
player.currentTime(40);
clock.tick(1);
equal(requests[2].headers.Range, "bytes=2299992-2835603");
});
test('if buffered, will request second segment byte range', function() {
player.src({
src: 'manifest/playlist.m3u8',
type: 'application/vnd.apple.mpegurl'
});
player.tech_.triggerReady();
clock.tick(1);
player.tech_.trigger('play');
openMediaSource(player);
player.tech_.buffered = function() {
return videojs.createTimeRange(0, 20);
};
standardXHRResponse(requests[0]);
standardXHRResponse(requests[1]);
player.tech_.hls.sourceBuffer.trigger('updateend');
player.tech_.hls.checkBuffer_();
clock.tick(100);
equal(requests[2].headers.Range, "bytes=1823412-2299991");
});
test('autoplay seeks to the live point after playlist load', function() {
var currentTime = 0;
player.autoplay(true);
......