140c0810 by Brandon Bay

Live start time tweaks

Moving live start time calculation earlier in the code flow to
eliminate a race condition, repeating it on first play to create a
smooth experience, and making sure currentTime is updated to match
these changes.
1 parent 4643387e
......@@ -66,7 +66,7 @@
width="600"
controls>
<source
src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8"
src="http://10.1.12.182:9090/event/adaptive-streaming/brightcove/play/event-master.m3u8?init=3"
type="application/x-mpegURL">
</video>
<script>
......
......@@ -164,6 +164,16 @@ videojs.Hls.prototype.src = function(src) {
});
}
// Start live playlists 30 seconds before the current time
// This is done using the old playlist because of a race condition
// where the playlist selected below may not be loaded quickly
// enough to have its segments available for review. When we receive
// a loadedplaylist event, we will call translateMediaIndex and
// maintain our position at the live point.
if (this.duration() === Infinity && this.mediaIndex === 0) {
this.mediaIndex = videojs.Hls.getMediaIndexForLive(oldMediaPlaylist);
}
selectedPlaylist = this.selectPlaylist();
oldBitrate = oldMediaPlaylist.attributes &&
oldMediaPlaylist.attributes.BANDWIDTH || 0;
......@@ -179,11 +189,6 @@ videojs.Hls.prototype.src = function(src) {
segmentDlTime = Infinity;
}
// start live playlists 30 seconds before the current time
if (this.duration() === Infinity && this.mediaIndex === 0 && selectedPlaylist.segments) {
this.mediaIndex = videojs.Hls.setMediaIndexForLive(selectedPlaylist);
}
// this threshold is to account for having a high latency on the manifest
// request which is a somewhat small file.
threshold = 10;
......@@ -239,7 +244,10 @@ videojs.Hls.prototype.src = function(src) {
});
};
videojs.Hls.setMediaIndexForLive = function(selectedPlaylist) {
/* Returns the media index for the live point in the current playlist, and updates
the current time to go along with it.
*/
videojs.Hls.getMediaIndexForLive = function(selectedPlaylist) {
var tailIterator = selectedPlaylist.segments.length,
tailDuration = 0,
targetTail = (selectedPlaylist.targetDuration || 10) * 3;
......@@ -279,6 +287,11 @@ videojs.Hls.prototype.play = function() {
this.mediaIndex = 0;
}
if (this.playlists.media() && !this.el().classList.contains('vjs-has-started')) {
this.mediaIndex = videojs.Hls.getMediaIndexForLive(this.playlists.media());
this.setCurrentTime(this.setCurrentTimeByMediaIndex(this.playlists.media(), this.mediaIndex));
}
// delegate back to the Flash implementation
return videojs.Flash.prototype.play.apply(this, arguments);
};
......@@ -936,7 +949,7 @@ videojs.Hls.translateMediaIndex = function(mediaIndex, original, update) {
if (translatedMediaIndex >= update.segments.length || translatedMediaIndex < 0) {
// recalculate the live point if the streams are too far out of sync
return videojs.Hls.setMediaIndexForLive(update) + 1;
return videojs.Hls.getMediaIndexForLive(update) + 1;
}
// sync on media sequence
......@@ -973,6 +986,20 @@ videojs.Hls.getMediaIndexByTime = function(playlist, time) {
return -1;
};
videojs.Hls.prototype.setCurrentTimeByMediaIndex = function(playlist, mediaIndex) {
var index, time = 0;
if (!playlist.segments || mediaIndex === 0) {
return 0;
}
for (index = 0; index < mediaIndex - 1; index++) {
time += playlist.segments[index].duration;
}
return time;
};
/**
* A comparator function to sort two playlist object by bandwidth.
* @param left {object} a media playlist object
......
......@@ -1249,6 +1249,21 @@ test('live playlist starts 30s before live', function() {
strictEqual(player.hls.mediaIndex, 6, 'mediaIndex is updated after the reload');
});
test('live playlist starts with correct currentTime value', function() {
player.src({
src: 'http://example.com/manifest/liveStart30sBefore.m3u8',
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
standardXHRResponse(requests[0]);
player.hls.playlists.trigger('loadedmetadata');
player.hls.play();
strictEqual(player.currentTime(), 60, 'currentTime is updated at playback');
});
test('mediaIndex is zero before the first segment loads', function() {
window.manifests['first-seg-load'] =
'#EXTM3U\n' +
......