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 @@ ...@@ -94,6 +94,10 @@
94 94
95 PlaylistLoader.prototype.init.call(this); 95 PlaylistLoader.prototype.init.call(this);
96 96
97 // a flag that disables "expired time"-tracking this setting has
98 // no effect when not playing a live stream
99 this.trackExpiredTime_ = false;
100
97 if (!srcUrl) { 101 if (!srcUrl) {
98 throw new Error('A non-empty playlist URL is required'); 102 throw new Error('A non-empty playlist URL is required');
99 } 103 }
...@@ -267,6 +271,12 @@ ...@@ -267,6 +271,12 @@
267 loader.bandwidth = xhr.bandwidth; 271 loader.bandwidth = xhr.bandwidth;
268 }; 272 };
269 273
274 // In a live list, don't keep track of the expired time until
275 // HLS tells us that "first play" has commenced
276 loader.on('firstplay', function() {
277 this.trackExpiredTime_ = true;
278 });
279
270 // live playlist staleness timeout 280 // live playlist staleness timeout
271 loader.on('mediaupdatetimeout', function() { 281 loader.on('mediaupdatetimeout', function() {
272 if (loader.state !== 'HAVE_METADATA') { 282 if (loader.state !== 'HAVE_METADATA') {
...@@ -360,6 +370,14 @@ ...@@ -360,6 +370,14 @@
360 return; 370 return;
361 } 371 }
362 372
373 // don't track expired time until this flag is truthy
374 if (!this.trackExpiredTime_) {
375 return;
376 }
377
378 // if the update was the result of a rendition switch do not
379 // attempt to calculate expired_ since media-sequences need not
380 // correlate between renditions/variants
363 if (update.uri !== outdated.uri) { 381 if (update.uri !== outdated.uri) {
364 return; 382 return;
365 } 383 }
......
...@@ -165,7 +165,7 @@ videojs.HlsHandler.prototype.src = function(src) { ...@@ -165,7 +165,7 @@ videojs.HlsHandler.prototype.src = function(src) {
165 } 165 }
166 this.playlists = new videojs.Hls.PlaylistLoader(this.source_.src, this.options_.withCredentials); 166 this.playlists = new videojs.Hls.PlaylistLoader(this.source_.src, this.options_.withCredentials);
167 167
168 this.tech_.on('canplay', this.setupFirstPlay.bind(this)); 168 this.tech_.one('canplay', this.setupFirstPlay.bind(this));
169 169
170 this.playlists.on('loadedmetadata', function() { 170 this.playlists.on('loadedmetadata', function() {
171 oldMediaPlaylist = this.playlists.media(); 171 oldMediaPlaylist = this.playlists.media();
...@@ -428,7 +428,10 @@ videojs.HlsHandler.prototype.setupFirstPlay = function() { ...@@ -428,7 +428,10 @@ videojs.HlsHandler.prototype.setupFirstPlay = function() {
428 428
429 // 5) the video element or flash player is in a readyState of 429 // 5) the video element or flash player is in a readyState of
430 // at least HAVE_FUTURE_DATA 430 // at least HAVE_FUTURE_DATA
431 this.tech_.readyState >= 3) { 431 this.tech_.readyState() >= 1) {
432
433 // trigger the playlist loader to start "expired time"-tracking
434 this.playlists.trigger('firstplay');
432 435
433 // seek to the latest media position for live videos 436 // seek to the latest media position for live videos
434 seekable = this.seekable(); 437 seekable = this.seekable();
......
...@@ -177,8 +177,37 @@ ...@@ -177,8 +177,37 @@
177 strictEqual(loader.state, 'HAVE_METADATA', 'the state is correct'); 177 strictEqual(loader.state, 'HAVE_METADATA', 'the state is correct');
178 }); 178 });
179 179
180 test('does not increment expired seconds before firstplay is triggered', function() {
181 var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
182 requests.pop().respond(200, null,
183 '#EXTM3U\n' +
184 '#EXT-X-MEDIA-SEQUENCE:0\n' +
185 '#EXTINF:10,\n' +
186 '0.ts\n' +
187 '#EXTINF:10,\n' +
188 '1.ts\n' +
189 '#EXTINF:10,\n' +
190 '2.ts\n' +
191 '#EXTINF:10,\n' +
192 '3.ts\n');
193 clock.tick(10 * 1000); // 10s, one target duration
194 requests.pop().respond(200, null,
195 '#EXTM3U\n' +
196 '#EXT-X-MEDIA-SEQUENCE:1\n' +
197 '#EXTINF:10,\n' +
198 '1.ts\n' +
199 '#EXTINF:10,\n' +
200 '2.ts\n' +
201 '#EXTINF:10,\n' +
202 '3.ts\n' +
203 '#EXTINF:10,\n' +
204 '4.ts\n');
205 equal(loader.expired_, 0, 'expired one segment');
206 });
207
180 test('increments expired seconds after a segment is removed', function() { 208 test('increments expired seconds after a segment is removed', function() {
181 var loader = new videojs.Hls.PlaylistLoader('live.m3u8'); 209 var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
210 loader.trigger('firstplay');
182 requests.pop().respond(200, null, 211 requests.pop().respond(200, null,
183 '#EXTM3U\n' + 212 '#EXTM3U\n' +
184 '#EXT-X-MEDIA-SEQUENCE:0\n' + 213 '#EXT-X-MEDIA-SEQUENCE:0\n' +
...@@ -207,6 +236,7 @@ ...@@ -207,6 +236,7 @@
207 236
208 test('increments expired seconds after a discontinuity', function() { 237 test('increments expired seconds after a discontinuity', function() {
209 var loader = new videojs.Hls.PlaylistLoader('live.m3u8'); 238 var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
239 loader.trigger('firstplay');
210 requests.pop().respond(200, null, 240 requests.pop().respond(200, null,
211 '#EXTM3U\n' + 241 '#EXTM3U\n' +
212 '#EXT-X-MEDIA-SEQUENCE:0\n' + 242 '#EXT-X-MEDIA-SEQUENCE:0\n' +
...@@ -249,6 +279,7 @@ ...@@ -249,6 +279,7 @@
249 279
250 test('tracks expired seconds properly when two discontinuities expire at once', function() { 280 test('tracks expired seconds properly when two discontinuities expire at once', function() {
251 var loader = new videojs.Hls.PlaylistLoader('live.m3u8'); 281 var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
282 loader.trigger('firstplay');
252 requests.pop().respond(200, null, 283 requests.pop().respond(200, null,
253 '#EXTM3U\n' + 284 '#EXTM3U\n' +
254 '#EXT-X-MEDIA-SEQUENCE:0\n' + 285 '#EXT-X-MEDIA-SEQUENCE:0\n' +
...@@ -274,6 +305,7 @@ ...@@ -274,6 +305,7 @@
274 305
275 test('estimates expired if an entire window elapses between live playlist updates', function() { 306 test('estimates expired if an entire window elapses between live playlist updates', function() {
276 var loader = new videojs.Hls.PlaylistLoader('live.m3u8'); 307 var loader = new videojs.Hls.PlaylistLoader('live.m3u8');
308 loader.trigger('firstplay');
277 requests.pop().respond(200, null, 309 requests.pop().respond(200, null,
278 '#EXTM3U\n' + 310 '#EXTM3U\n' +
279 '#EXT-X-MEDIA-SEQUENCE:0\n' + 311 '#EXT-X-MEDIA-SEQUENCE:0\n' +
...@@ -826,6 +858,7 @@ ...@@ -826,6 +858,7 @@
826 858
827 test('prefers precise segment timing when tracking expired time', function() { 859 test('prefers precise segment timing when tracking expired time', function() {
828 var loader = new videojs.Hls.PlaylistLoader('media.m3u8'); 860 var loader = new videojs.Hls.PlaylistLoader('media.m3u8');
861 loader.trigger('firstplay');
829 requests.shift().respond(200, null, 862 requests.shift().respond(200, null,
830 '#EXTM3U\n' + 863 '#EXTM3U\n' +
831 '#EXT-X-MEDIA-SEQUENCE:1001\n' + 864 '#EXT-X-MEDIA-SEQUENCE:1001\n' +
......
...@@ -335,7 +335,7 @@ test('autoplay seeks to the live point after playlist load', function() { ...@@ -335,7 +335,7 @@ test('autoplay seeks to the live point after playlist load', function() {
335 type: 'application/vnd.apple.mpegurl' 335 type: 'application/vnd.apple.mpegurl'
336 }); 336 });
337 openMediaSource(player); 337 openMediaSource(player);
338 player.tech_.readyState = 3; 338 player.tech_.readyState = function(){return 1;};
339 player.tech_.trigger('play'); 339 player.tech_.trigger('play');
340 standardXHRResponse(requests.shift()); 340 standardXHRResponse(requests.shift());
341 clock.tick(1); 341 clock.tick(1);
...@@ -357,7 +357,7 @@ test('autoplay seeks to the live point after media source open', function() { ...@@ -357,7 +357,7 @@ test('autoplay seeks to the live point after media source open', function() {
357 clock.tick(1); 357 clock.tick(1);
358 standardXHRResponse(requests.shift()); 358 standardXHRResponse(requests.shift());
359 openMediaSource(player); 359 openMediaSource(player);
360 player.tech_.readyState = 3; 360 player.tech_.readyState = function(){return 1;};
361 player.tech_.trigger('play'); 361 player.tech_.trigger('play');
362 clock.tick(1); 362 clock.tick(1);
363 363
...@@ -410,7 +410,7 @@ test('calls `remove` on sourceBuffer to when loading a live segment', function() ...@@ -410,7 +410,7 @@ test('calls `remove` on sourceBuffer to when loading a live segment', function()
410 player.tech_.hls.playlists.trigger('loadedmetadata'); 410 player.tech_.hls.playlists.trigger('loadedmetadata');
411 player.tech_.trigger('canplay'); 411 player.tech_.trigger('canplay');
412 player.tech_.paused = function() { return false; }; 412 player.tech_.paused = function() { return false; };
413 player.tech_.readyState = 3; 413 player.tech_.readyState = function(){return 1;};
414 player.tech_.trigger('play'); 414 player.tech_.trigger('play');
415 415
416 clock.tick(1); 416 clock.tick(1);
...@@ -1688,7 +1688,7 @@ test('live playlist starts three target durations before live', function() { ...@@ -1688,7 +1688,7 @@ test('live playlist starts three target durations before live', function() {
1688 equal(requests.length, 0, 'no outstanding segment request'); 1688 equal(requests.length, 0, 'no outstanding segment request');
1689 1689
1690 player.tech_.paused = function() { return false; }; 1690 player.tech_.paused = function() { return false; };
1691 player.tech_.readyState = 3; 1691 player.tech_.readyState = function(){return 1;};
1692 player.tech_.trigger('play'); 1692 player.tech_.trigger('play');
1693 clock.tick(1); 1693 clock.tick(1);
1694 mediaPlaylist = player.tech_.hls.playlists.media(); 1694 mediaPlaylist = player.tech_.hls.playlists.media();
...@@ -1709,7 +1709,7 @@ test('live playlist starts with correct currentTime value', function() { ...@@ -1709,7 +1709,7 @@ test('live playlist starts with correct currentTime value', function() {
1709 player.tech_.hls.playlists.trigger('loadedmetadata'); 1709 player.tech_.hls.playlists.trigger('loadedmetadata');
1710 1710
1711 player.tech_.paused = function() { return false; }; 1711 player.tech_.paused = function() { return false; };
1712 player.tech_.readyState = 3; 1712 player.tech_.readyState = function(){return 1;};
1713 player.tech_.trigger('play'); 1713 player.tech_.trigger('play');
1714 clock.tick(1); 1714 clock.tick(1);
1715 1715
......