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.
Showing
3 changed files
with
50 additions
and
8 deletions
... | @@ -66,7 +66,7 @@ | ... | @@ -66,7 +66,7 @@ |
66 | width="600" | 66 | width="600" |
67 | controls> | 67 | controls> |
68 | <source | 68 | <source |
69 | src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8" | 69 | src="http://10.1.12.182:9090/event/adaptive-streaming/brightcove/play/event-master.m3u8?init=3" |
70 | type="application/x-mpegURL"> | 70 | type="application/x-mpegURL"> |
71 | </video> | 71 | </video> |
72 | <script> | 72 | <script> | ... | ... |
... | @@ -164,6 +164,16 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -164,6 +164,16 @@ videojs.Hls.prototype.src = function(src) { |
164 | }); | 164 | }); |
165 | } | 165 | } |
166 | 166 | ||
167 | // Start live playlists 30 seconds before the current time | ||
168 | // This is done using the old playlist because of a race condition | ||
169 | // where the playlist selected below may not be loaded quickly | ||
170 | // enough to have its segments available for review. When we receive | ||
171 | // a loadedplaylist event, we will call translateMediaIndex and | ||
172 | // maintain our position at the live point. | ||
173 | if (this.duration() === Infinity && this.mediaIndex === 0) { | ||
174 | this.mediaIndex = videojs.Hls.getMediaIndexForLive(oldMediaPlaylist); | ||
175 | } | ||
176 | |||
167 | selectedPlaylist = this.selectPlaylist(); | 177 | selectedPlaylist = this.selectPlaylist(); |
168 | oldBitrate = oldMediaPlaylist.attributes && | 178 | oldBitrate = oldMediaPlaylist.attributes && |
169 | oldMediaPlaylist.attributes.BANDWIDTH || 0; | 179 | oldMediaPlaylist.attributes.BANDWIDTH || 0; |
... | @@ -179,11 +189,6 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -179,11 +189,6 @@ videojs.Hls.prototype.src = function(src) { |
179 | segmentDlTime = Infinity; | 189 | segmentDlTime = Infinity; |
180 | } | 190 | } |
181 | 191 | ||
182 | // start live playlists 30 seconds before the current time | ||
183 | if (this.duration() === Infinity && this.mediaIndex === 0 && selectedPlaylist.segments) { | ||
184 | this.mediaIndex = videojs.Hls.setMediaIndexForLive(selectedPlaylist); | ||
185 | } | ||
186 | |||
187 | // this threshold is to account for having a high latency on the manifest | 192 | // this threshold is to account for having a high latency on the manifest |
188 | // request which is a somewhat small file. | 193 | // request which is a somewhat small file. |
189 | threshold = 10; | 194 | threshold = 10; |
... | @@ -239,7 +244,10 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -239,7 +244,10 @@ videojs.Hls.prototype.src = function(src) { |
239 | }); | 244 | }); |
240 | }; | 245 | }; |
241 | 246 | ||
242 | videojs.Hls.setMediaIndexForLive = function(selectedPlaylist) { | 247 | /* Returns the media index for the live point in the current playlist, and updates |
248 | the current time to go along with it. | ||
249 | */ | ||
250 | videojs.Hls.getMediaIndexForLive = function(selectedPlaylist) { | ||
243 | var tailIterator = selectedPlaylist.segments.length, | 251 | var tailIterator = selectedPlaylist.segments.length, |
244 | tailDuration = 0, | 252 | tailDuration = 0, |
245 | targetTail = (selectedPlaylist.targetDuration || 10) * 3; | 253 | targetTail = (selectedPlaylist.targetDuration || 10) * 3; |
... | @@ -279,6 +287,11 @@ videojs.Hls.prototype.play = function() { | ... | @@ -279,6 +287,11 @@ videojs.Hls.prototype.play = function() { |
279 | this.mediaIndex = 0; | 287 | this.mediaIndex = 0; |
280 | } | 288 | } |
281 | 289 | ||
290 | if (this.playlists.media() && !this.el().classList.contains('vjs-has-started')) { | ||
291 | this.mediaIndex = videojs.Hls.getMediaIndexForLive(this.playlists.media()); | ||
292 | this.setCurrentTime(this.setCurrentTimeByMediaIndex(this.playlists.media(), this.mediaIndex)); | ||
293 | } | ||
294 | |||
282 | // delegate back to the Flash implementation | 295 | // delegate back to the Flash implementation |
283 | return videojs.Flash.prototype.play.apply(this, arguments); | 296 | return videojs.Flash.prototype.play.apply(this, arguments); |
284 | }; | 297 | }; |
... | @@ -936,7 +949,7 @@ videojs.Hls.translateMediaIndex = function(mediaIndex, original, update) { | ... | @@ -936,7 +949,7 @@ videojs.Hls.translateMediaIndex = function(mediaIndex, original, update) { |
936 | 949 | ||
937 | if (translatedMediaIndex >= update.segments.length || translatedMediaIndex < 0) { | 950 | if (translatedMediaIndex >= update.segments.length || translatedMediaIndex < 0) { |
938 | // recalculate the live point if the streams are too far out of sync | 951 | // recalculate the live point if the streams are too far out of sync |
939 | return videojs.Hls.setMediaIndexForLive(update) + 1; | 952 | return videojs.Hls.getMediaIndexForLive(update) + 1; |
940 | } | 953 | } |
941 | 954 | ||
942 | // sync on media sequence | 955 | // sync on media sequence |
... | @@ -973,6 +986,20 @@ videojs.Hls.getMediaIndexByTime = function(playlist, time) { | ... | @@ -973,6 +986,20 @@ videojs.Hls.getMediaIndexByTime = function(playlist, time) { |
973 | return -1; | 986 | return -1; |
974 | }; | 987 | }; |
975 | 988 | ||
989 | videojs.Hls.prototype.setCurrentTimeByMediaIndex = function(playlist, mediaIndex) { | ||
990 | var index, time = 0; | ||
991 | |||
992 | if (!playlist.segments || mediaIndex === 0) { | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | for (index = 0; index < mediaIndex - 1; index++) { | ||
997 | time += playlist.segments[index].duration; | ||
998 | } | ||
999 | |||
1000 | return time; | ||
1001 | }; | ||
1002 | |||
976 | /** | 1003 | /** |
977 | * A comparator function to sort two playlist object by bandwidth. | 1004 | * A comparator function to sort two playlist object by bandwidth. |
978 | * @param left {object} a media playlist object | 1005 | * @param left {object} a media playlist object | ... | ... |
... | @@ -1249,6 +1249,21 @@ test('live playlist starts 30s before live', function() { | ... | @@ -1249,6 +1249,21 @@ test('live playlist starts 30s before live', function() { |
1249 | strictEqual(player.hls.mediaIndex, 6, 'mediaIndex is updated after the reload'); | 1249 | strictEqual(player.hls.mediaIndex, 6, 'mediaIndex is updated after the reload'); |
1250 | }); | 1250 | }); |
1251 | 1251 | ||
1252 | test('live playlist starts with correct currentTime value', function() { | ||
1253 | player.src({ | ||
1254 | src: 'http://example.com/manifest/liveStart30sBefore.m3u8', | ||
1255 | type: 'application/vnd.apple.mpegurl' | ||
1256 | }); | ||
1257 | openMediaSource(player); | ||
1258 | |||
1259 | standardXHRResponse(requests[0]); | ||
1260 | |||
1261 | player.hls.playlists.trigger('loadedmetadata'); | ||
1262 | player.hls.play(); | ||
1263 | |||
1264 | strictEqual(player.currentTime(), 60, 'currentTime is updated at playback'); | ||
1265 | }); | ||
1266 | |||
1252 | test('mediaIndex is zero before the first segment loads', function() { | 1267 | test('mediaIndex is zero before the first segment loads', function() { |
1253 | window.manifests['first-seg-load'] = | 1268 | window.manifests['first-seg-load'] = |
1254 | '#EXTM3U\n' + | 1269 | '#EXTM3U\n' + | ... | ... |
-
Please register or sign in to post a comment