aac49993 by jrivera

Tests for endOfStream and segment.duration tracking behavior in updateEndHandler

1 parent cf295e56
...@@ -298,7 +298,7 @@ videojs.Hls.findSoleUncommonTimeRangesEnd_ = function(original, update) { ...@@ -298,7 +298,7 @@ videojs.Hls.findSoleUncommonTimeRangesEnd_ = function(original, update) {
298 }; 298 };
299 299
300 /** 300 /**
301 * Updates segment with information about it's end-point in time and, optionally, 301 * Updates segment with information about its end-point in time and, optionally,
302 * the segment duration if we have enough information to determine a segment duration 302 * the segment duration if we have enough information to determine a segment duration
303 * accurately. 303 * accurately.
304 * @param playlist {object} a media playlist object 304 * @param playlist {object} a media playlist object
...@@ -322,7 +322,7 @@ videojs.HlsHandler.prototype.updateSegmentMetadata_ = function(playlist, segment ...@@ -322,7 +322,7 @@ videojs.HlsHandler.prototype.updateSegmentMetadata_ = function(playlist, segment
322 322
323 // fix up segment durations based on segment end data 323 // fix up segment durations based on segment end data
324 if (!previousSegment) { 324 if (!previousSegment) {
325 // first segment is always has a start time of 0 making it's duration 325 // first segment is always has a start time of 0 making its duration
326 // equal to the segment end 326 // equal to the segment end
327 segment.duration = segment.end; 327 segment.duration = segment.end;
328 } else if (previousSegment.end) { 328 } else if (previousSegment.end) {
...@@ -337,9 +337,9 @@ videojs.HlsHandler.prototype.updateSegmentMetadata_ = function(playlist, segment ...@@ -337,9 +337,9 @@ videojs.HlsHandler.prototype.updateSegmentMetadata_ = function(playlist, segment
337 * @param playlist {object} a media playlist object 337 * @param playlist {object} a media playlist object
338 * @param segmentIndex {number} the index of segment we last appended 338 * @param segmentIndex {number} the index of segment we last appended
339 * @param currentBuffered {object} the buffered region that currentTime resides in 339 * @param currentBuffered {object} the buffered region that currentTime resides in
340 * @return {boolean} whether or not endOfStream was called on the MediaSource 340 * @return {boolean} whether the calling function should call endOfStream on the MediaSource
341 */ 341 */
342 videojs.HlsHandler.prototype.maybeEndOfStream_ = function(playlist, segmentIndex, currentBuffered) { 342 videojs.HlsHandler.prototype.isEndOfStream_ = function(playlist, segmentIndex, currentBuffered) {
343 var 343 var
344 segments = playlist.segments, 344 segments = playlist.segments,
345 appendedLastSegment, 345 appendedLastSegment,
...@@ -358,14 +358,9 @@ videojs.HlsHandler.prototype.maybeEndOfStream_ = function(playlist, segmentIndex ...@@ -358,14 +358,9 @@ videojs.HlsHandler.prototype.maybeEndOfStream_ = function(playlist, segmentIndex
358 // if we've buffered to the end of the video, we need to call endOfStream 358 // if we've buffered to the end of the video, we need to call endOfStream
359 // so that MediaSources can trigger the `ended` event when it runs out of 359 // so that MediaSources can trigger the `ended` event when it runs out of
360 // buffered data instead of waiting for me 360 // buffered data instead of waiting for me
361 if (playlist.endList && 361 return playlist.endList &&
362 this.mediaSource.readyState === 'open' && 362 this.mediaSource.readyState === 'open' &&
363 (appendedLastSegment || 363 (appendedLastSegment || bufferedToEnd);
364 bufferedToEnd)) {
365 this.mediaSource.endOfStream();
366 return true;
367 }
368 return false;
369 }; 364 };
370 365
371 var parseCodecs = function(codecs) { 366 var parseCodecs = function(codecs) {
...@@ -1310,7 +1305,8 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1310,7 +1305,8 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1310 currentMediaIndex, 1305 currentMediaIndex,
1311 currentBuffered, 1306 currentBuffered,
1312 seekable, 1307 seekable,
1313 timelineUpdate; 1308 timelineUpdate,
1309 isEndOfStream;
1314 1310
1315 // stop here if the update errored or was aborted 1311 // stop here if the update errored or was aborted
1316 if (!segmentInfo) { 1312 if (!segmentInfo) {
...@@ -1330,10 +1326,14 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1330,10 +1326,14 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1330 segments = playlist.segments; 1326 segments = playlist.segments;
1331 currentMediaIndex = segmentInfo.mediaIndex + (segmentInfo.mediaSequence - playlist.mediaSequence); 1327 currentMediaIndex = segmentInfo.mediaIndex + (segmentInfo.mediaSequence - playlist.mediaSequence);
1332 currentBuffered = this.findBufferedRange_(); 1328 currentBuffered = this.findBufferedRange_();
1329 isEndOfStream = this.isEndOfStream_(playlist, currentMediaIndex, currentBuffered);
1333 1330
1334 // if we switched renditions don't try to add segment timeline 1331 // if we switched renditions don't try to add segment timeline
1335 // information to the playlist 1332 // information to the playlist
1336 if (segmentInfo.playlist.uri !== this.playlists.media().uri) { 1333 if (segmentInfo.playlist.uri !== this.playlists.media().uri) {
1334 if (isEndOfStream) {
1335 return this.mediaSource.endOfStream();
1336 }
1337 return this.fillBuffer(); 1337 return this.fillBuffer();
1338 } 1338 }
1339 1339
...@@ -1366,8 +1366,8 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1366,8 +1366,8 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1366 1366
1367 // If we decide to signal the end of stream, then we can return instead 1367 // If we decide to signal the end of stream, then we can return instead
1368 // of trying to fetch more segments 1368 // of trying to fetch more segments
1369 if (this.maybeEndOfStream_(playlist, currentMediaIndex, currentBuffered)) { 1369 if (isEndOfStream) {
1370 return; 1370 return this.mediaSource.endOfStream();
1371 } 1371 }
1372 1372
1373 if (timelineUpdate !== null || 1373 if (timelineUpdate !== null ||
......
...@@ -2144,6 +2144,79 @@ test('tracks segment end times as they are buffered', function() { ...@@ -2144,6 +2144,79 @@ test('tracks segment end times as they are buffered', function() {
2144 equal(player.tech_.hls.mediaSource.duration, 10 + 9.5, 'updated duration'); 2144 equal(player.tech_.hls.mediaSource.duration, 10 + 9.5, 'updated duration');
2145 }); 2145 });
2146 2146
2147 test('updates first segment duration as it is buffered', function() {
2148 var bufferEnd = 0;
2149 player.src({
2150 src: 'media.m3u8',
2151 type: 'application/x-mpegURL'
2152 });
2153 openMediaSource(player);
2154
2155 // as new segments are downloaded, the buffer end is updated
2156 player.tech_.buffered = function() {
2157 return videojs.createTimeRange(0, bufferEnd);
2158 };
2159 requests.shift().respond(200, null,
2160 '#EXTM3U\n' +
2161 '#EXTINF:10,\n' +
2162 '0.ts\n' +
2163 '#EXTINF:10,\n' +
2164 '1.ts\n' +
2165 '#EXT-X-ENDLIST\n');
2166
2167 // 0.ts is shorter than advertised
2168 standardXHRResponse(requests.shift());
2169 equal(player.tech_.hls.mediaSource.duration, 20, 'original duration is from the m3u8');
2170 equal(player.tech_.hls.playlists.media().segments[0].duration, 10,
2171 'segment duration initially based on playlist');
2172
2173 bufferEnd = 9.5;
2174 player.tech_.hls.sourceBuffer.trigger('update');
2175 player.tech_.hls.sourceBuffer.trigger('updateend');
2176 equal(player.tech_.hls.playlists.media().segments[0].duration, 9.5,
2177 'updated segment duration');
2178 });
2179
2180 test('updates segment durations as they are buffered', function() {
2181 var bufferEnd = 0;
2182 player.src({
2183 src: 'media.m3u8',
2184 type: 'application/x-mpegURL'
2185 });
2186 openMediaSource(player);
2187
2188 // as new segments are downloaded, the buffer end is updated
2189 player.tech_.buffered = function() {
2190 return videojs.createTimeRange(0, bufferEnd);
2191 };
2192 requests.shift().respond(200, null,
2193 '#EXTM3U\n' +
2194 '#EXTINF:10,\n' +
2195 '0.ts\n' +
2196 '#EXTINF:10,\n' +
2197 '1.ts\n' +
2198 '#EXT-X-ENDLIST\n');
2199
2200 // 0.ts is shorter than advertised
2201 standardXHRResponse(requests.shift());
2202 equal(player.tech_.hls.mediaSource.duration, 20, 'original duration is from the m3u8');
2203
2204 equal(player.tech_.hls.playlists.media().segments[1].duration, 10,
2205 'segment duration initially based on playlist');
2206
2207 bufferEnd = 9.5;
2208 player.tech_.hls.sourceBuffer.trigger('update');
2209 player.tech_.hls.sourceBuffer.trigger('updateend');
2210 clock.tick(1);
2211 standardXHRResponse(requests.shift());
2212 bufferEnd = 19;
2213 player.tech_.hls.sourceBuffer.trigger('update');
2214 player.tech_.hls.sourceBuffer.trigger('updateend');
2215
2216 equal(player.tech_.hls.playlists.media().segments[1].duration, 9.5,
2217 'updated segment duration');
2218 });
2219
2147 QUnit.skip('seeking does not fail when targeted between segments', function() { 2220 QUnit.skip('seeking does not fail when targeted between segments', function() {
2148 var currentTime, segmentUrl; 2221 var currentTime, segmentUrl;
2149 player.src({ 2222 player.src({
...@@ -2428,7 +2501,7 @@ test('can be disposed before finishing initialization', function() { ...@@ -2428,7 +2501,7 @@ test('can be disposed before finishing initialization', function() {
2428 } 2501 }
2429 }); 2502 });
2430 2503
2431 test('calls ended() on the media source at the end of a playlist', function() { 2504 test('calls endOfStream on the media source after appending the last segment', function() {
2432 var endOfStreams = 0, buffered = [[]]; 2505 var endOfStreams = 0, buffered = [[]];
2433 player.src({ 2506 player.src({
2434 src: 'http://example.com/media.m3u8', 2507 src: 'http://example.com/media.m3u8',
...@@ -2441,11 +2514,15 @@ test('calls ended() on the media source at the end of a playlist', function() { ...@@ -2441,11 +2514,15 @@ test('calls ended() on the media source at the end of a playlist', function() {
2441 player.tech_.hls.mediaSource.endOfStream = function() { 2514 player.tech_.hls.mediaSource.endOfStream = function() {
2442 endOfStreams++; 2515 endOfStreams++;
2443 }; 2516 };
2517 player.currentTime(20);
2518 clock.tick(1);
2444 // playlist response 2519 // playlist response
2445 requests.shift().respond(200, null, 2520 requests.shift().respond(200, null,
2446 '#EXTM3U\n' + 2521 '#EXTM3U\n' +
2447 '#EXTINF:10,\n' + 2522 '#EXTINF:10,\n' +
2448 '0.ts\n' + 2523 '0.ts\n' +
2524 '#EXTINF:10,\n' +
2525 '1.ts\n' +
2449 '#EXT-X-ENDLIST\n'); 2526 '#EXT-X-ENDLIST\n');
2450 // segment response 2527 // segment response
2451 requests[0].response = new ArrayBuffer(17); 2528 requests[0].response = new ArrayBuffer(17);
...@@ -2454,7 +2531,50 @@ test('calls ended() on the media source at the end of a playlist', function() { ...@@ -2454,7 +2531,50 @@ test('calls ended() on the media source at the end of a playlist', function() {
2454 2531
2455 buffered =[[0, 10]]; 2532 buffered =[[0, 10]];
2456 player.tech_.hls.sourceBuffer.trigger('updateend'); 2533 player.tech_.hls.sourceBuffer.trigger('updateend');
2457 strictEqual(endOfStreams, 1, 'ended media source'); 2534 strictEqual(endOfStreams, 1, 'called endOfStream on the media source');
2535 });
2536
2537 test('calls endOfStream on the media source when the current buffer ends at duration', function() {
2538 var endOfStreams = 0, buffered = [[]];
2539 player.src({
2540 src: 'http://example.com/media.m3u8',
2541 type: 'application/vnd.apple.mpegurl'
2542 });
2543 openMediaSource(player);
2544 player.tech_.buffered = function() {
2545 return videojs.createTimeRanges(buffered);
2546 };
2547 player.tech_.hls.mediaSource.endOfStream = function() {
2548 endOfStreams++;
2549 };
2550 player.currentTime(19);
2551 clock.tick(1);
2552 // playlist response
2553 requests.shift().respond(200, null,
2554 '#EXTM3U\n' +
2555 '#EXTINF:10,\n' +
2556 '0.ts\n' +
2557 '#EXTINF:10,\n' +
2558 '1.ts\n' +
2559 '#EXT-X-ENDLIST\n');
2560 // segment response
2561 requests[0].response = new ArrayBuffer(17);
2562 requests.shift().respond(200, null, '');
2563 strictEqual(endOfStreams, 0, 'waits for the buffer update to finish');
2564
2565 buffered =[[10, 20]];
2566 player.tech_.hls.sourceBuffer.trigger('updateend');
2567
2568 player.currentTime(5);
2569 clock.tick(1);
2570 // segment response
2571 requests[0].response = new ArrayBuffer(17);
2572 requests.shift().respond(200, null, '');
2573
2574 buffered =[[0, 20]];
2575 player.tech_.hls.sourceBuffer.trigger('updateend');
2576
2577 strictEqual(endOfStreams, 2, 'called endOfStream on the media source twice');
2458 }); 2578 });
2459 2579
2460 test('calling play() at the end of a video replays', function() { 2580 test('calling play() at the end of a video replays', function() {
......