38836d4d by David LaPalomento

Seek to a safe position when resuming live playlists

If the player has fallen out of the live window, seek back to the earliest safe position when playback resumes. If the player is paused too far ahead of the live point, seek back to the latest safe position when resuming.
1 parent 4f2d554c
...@@ -321,12 +321,21 @@ videojs.Hls.prototype.play = function() { ...@@ -321,12 +321,21 @@ videojs.Hls.prototype.play = function() {
321 this.mediaIndex = 0; 321 this.mediaIndex = 0;
322 } 322 }
323 323
324 // seek to the latest safe point in the media timeline when first 324 // we may need to seek to begin playing safely for live playlists
325 // playing live streams 325 if (this.duration() === Infinity) {
326 if (this.duration() === Infinity && 326
327 this.playlists.media() && 327 // if this is the first time we're playing the stream or we're
328 !this.player().hasClass('vjs-has-started')) { 328 // ahead of the latest safe playback position, seek to the live
329 // point
330 if (!this.player().hasClass('vjs-has-started') ||
331 this.currentTime() > this.seekable().end(0)) {
329 this.setCurrentTime(this.seekable().end(0)); 332 this.setCurrentTime(this.seekable().end(0));
333
334 } else if (this.currentTime() < this.seekable().start(0)) {
335 // if the viewer has paused and we fell out of the live window,
336 // seek forward to the earliest available position
337 this.setCurrentTime(this.seekable().start(0));
338 }
330 } 339 }
331 340
332 // delegate back to the Flash implementation 341 // delegate back to the Flash implementation
......
...@@ -1686,6 +1686,51 @@ test('live playlist starts with correct currentTime value', function() { ...@@ -1686,6 +1686,51 @@ test('live playlist starts with correct currentTime value', function() {
1686 'currentTime is updated at playback'); 1686 'currentTime is updated at playback');
1687 }); 1687 });
1688 1688
1689 test('resets the time to a seekable position when resuming a live stream ' +
1690 'after a long break', function() {
1691 var seekTarget;
1692 player.src({
1693 src: 'live0.m3u8',
1694 type: 'application/vnd.apple.mpegurl'
1695 });
1696 openMediaSource(player);
1697 requests.shift().respond(200, null,
1698 '#EXTM3U\n' +
1699 '#EXT-X-MEDIA-SEQUENCE:16\n' +
1700 '#EXTINF:10,\n' +
1701 '16.ts\n');
1702 // mock out the player to simulate a live stream that has been
1703 // playing for awhile
1704 player.addClass('vjs-has-started');
1705 player.hls.seekable = function() {
1706 return {
1707 start: function() {
1708 return 160;
1709 },
1710 end: function() {
1711 return 170;
1712 }
1713 };
1714 };
1715 player.hls.currentTime = function() {
1716 return 0;
1717 };
1718 player.hls.setCurrentTime = function(time) {
1719 if (time !== undefined) {
1720 seekTarget = time;
1721 }
1722 };
1723
1724 player.play();
1725 equal(seekTarget, player.seekable().start(0), 'seeked to the start of seekable');
1726
1727 player.hls.currentTime = function() {
1728 return 180;
1729 };
1730 player.play();
1731 equal(seekTarget, player.seekable().end(0), 'seeked to the end of seekable');
1732 });
1733
1689 test('mediaIndex is zero before the first segment loads', function() { 1734 test('mediaIndex is zero before the first segment loads', function() {
1690 window.manifests['first-seg-load'] = 1735 window.manifests['first-seg-load'] =
1691 '#EXTM3U\n' + 1736 '#EXTM3U\n' +
......