61350b49 by Jon-Carlos Rivera

Merge pull request #476 from videojs/firefox-live

Fix the fixes for Firefox
2 parents 71c97305 53210b25
......@@ -94,6 +94,10 @@
PlaylistLoader.prototype.init.call(this);
// a flag that disables "expired time"-tracking this setting has
// no effect when not playing a live stream
this.trackExpiredTime_ = false;
if (!srcUrl) {
throw new Error('A non-empty playlist URL is required');
}
......@@ -267,6 +271,12 @@
loader.bandwidth = xhr.bandwidth;
};
// In a live list, don't keep track of the expired time until
// HLS tells us that "first play" has commenced
loader.on('firstplay', function() {
this.trackExpiredTime_ = true;
});
// live playlist staleness timeout
loader.on('mediaupdatetimeout', function() {
if (loader.state !== 'HAVE_METADATA') {
......@@ -360,6 +370,14 @@
return;
}
// don't track expired time until this flag is truthy
if (!this.trackExpiredTime_) {
return;
}
// if the update was the result of a rendition switch do not
// attempt to calculate expired_ since media-sequences need not
// correlate between renditions/variants
if (update.uri !== outdated.uri) {
return;
}
......
......@@ -165,7 +165,7 @@ videojs.HlsHandler.prototype.src = function(src) {
}
this.playlists = new videojs.Hls.PlaylistLoader(this.source_.src, this.options_.withCredentials);
this.tech_.on('canplay', this.setupFirstPlay.bind(this));
this.tech_.one('canplay', this.setupFirstPlay.bind(this));
this.playlists.on('loadedmetadata', function() {
oldMediaPlaylist = this.playlists.media();
......@@ -428,7 +428,10 @@ videojs.HlsHandler.prototype.setupFirstPlay = function() {
// 5) the video element or flash player is in a readyState of
// at least HAVE_FUTURE_DATA
this.tech_.readyState >= 3) {
this.tech_.readyState() >= 1) {
// trigger the playlist loader to start "expired time"-tracking
this.playlists.trigger('firstplay');
// seek to the latest media position for live videos
seekable = this.seekable();
......
......@@ -177,8 +177,37 @@
strictEqual(loader.state, 'HAVE_METADATA', 'the state is correct');
});
test('does not increment expired seconds before firstplay is triggered', function() {
var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:0\n' +
'#EXTINF:10,\n' +
'0.ts\n' +
'#EXTINF:10,\n' +
'1.ts\n' +
'#EXTINF:10,\n' +
'2.ts\n' +
'#EXTINF:10,\n' +
'3.ts\n');
clock.tick(10 * 1000); // 10s, one target duration
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:1\n' +
'#EXTINF:10,\n' +
'1.ts\n' +
'#EXTINF:10,\n' +
'2.ts\n' +
'#EXTINF:10,\n' +
'3.ts\n' +
'#EXTINF:10,\n' +
'4.ts\n');
equal(loader.expired_, 0, 'expired one segment');
});
test('increments expired seconds after a segment is removed', function() {
var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
loader.trigger('firstplay');
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:0\n' +
......@@ -207,6 +236,7 @@
test('increments expired seconds after a discontinuity', function() {
var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
loader.trigger('firstplay');
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:0\n' +
......@@ -249,6 +279,7 @@
test('tracks expired seconds properly when two discontinuities expire at once', function() {
var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
loader.trigger('firstplay');
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:0\n' +
......@@ -274,6 +305,7 @@
test('estimates expired if an entire window elapses between live playlist updates', function() {
var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
loader.trigger('firstplay');
requests.pop().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:0\n' +
......@@ -826,6 +858,7 @@
test('prefers precise segment timing when tracking expired time', function() {
var loader = new videojs.Hls.PlaylistLoader('media.m3u8');
loader.trigger('firstplay');
requests.shift().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-MEDIA-SEQUENCE:1001\n' +
......
......@@ -335,7 +335,7 @@ test('autoplay seeks to the live point after playlist load', function() {
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
player.tech_.readyState = 3;
player.tech_.readyState = function(){return 1;};
player.tech_.trigger('play');
standardXHRResponse(requests.shift());
clock.tick(1);
......@@ -357,7 +357,7 @@ test('autoplay seeks to the live point after media source open', function() {
clock.tick(1);
standardXHRResponse(requests.shift());
openMediaSource(player);
player.tech_.readyState = 3;
player.tech_.readyState = function(){return 1;};
player.tech_.trigger('play');
clock.tick(1);
......@@ -410,7 +410,7 @@ test('calls `remove` on sourceBuffer to when loading a live segment', function()
player.tech_.hls.playlists.trigger('loadedmetadata');
player.tech_.trigger('canplay');
player.tech_.paused = function() { return false; };
player.tech_.readyState = 3;
player.tech_.readyState = function(){return 1;};
player.tech_.trigger('play');
clock.tick(1);
......@@ -1688,7 +1688,7 @@ test('live playlist starts three target durations before live', function() {
equal(requests.length, 0, 'no outstanding segment request');
player.tech_.paused = function() { return false; };
player.tech_.readyState = 3;
player.tech_.readyState = function(){return 1;};
player.tech_.trigger('play');
clock.tick(1);
mediaPlaylist = player.tech_.hls.playlists.media();
......@@ -1709,7 +1709,7 @@ test('live playlist starts with correct currentTime value', function() {
player.tech_.hls.playlists.trigger('loadedmetadata');
player.tech_.paused = function() { return false; };
player.tech_.readyState = 3;
player.tech_.readyState = function(){return 1;};
player.tech_.trigger('play');
clock.tick(1);
......