e266db29 by jrivera

Add/fix tests related to segment annotation and fetching

1 parent 6ea1ad65
...@@ -450,7 +450,7 @@ ...@@ -450,7 +450,7 @@
450 break; 450 break;
451 } else { 451 } else {
452 knownStart = segment.end; 452 knownStart = segment.end;
453 startIndex = i; 453 startIndex = i + 1;
454 } 454 }
455 } 455 }
456 } 456 }
...@@ -494,8 +494,13 @@ ...@@ -494,8 +494,13 @@
494 return i; 494 return i;
495 } 495 }
496 } 496 }
497 // We haven't found a segment so load the first one 497
498 return 0; 498 // We haven't found a segment so load the first one if time is zero
499 if (time === 0) {
500 return 0;
501 } else {
502 return -1;
503 }
499 } else { 504 } else {
500 // We known nothing so walk from the front of the playlist, 505 // We known nothing so walk from the front of the playlist,
501 // subtracting durations until we find a segment that contains 506 // subtracting durations until we find a segment that contains
......
...@@ -10,8 +10,8 @@ var ...@@ -10,8 +10,8 @@ var
10 // A fudge factor to apply to advertised playlist bitrates to account for 10 // A fudge factor to apply to advertised playlist bitrates to account for
11 // temporary flucations in client bandwidth 11 // temporary flucations in client bandwidth
12 bandwidthVariance = 1.2, 12 bandwidthVariance = 1.2,
13 blacklistDuration = 5 * 60 * 1000, // 2 minute blacklist 13 blacklistDuration = 5 * 60 * 1000, // 5 minute blacklist
14 TIME_FUDGE_FACTOR = 1 / 60, // Fudge factor to account for TimeRanges rounding 14 TIME_FUDGE_FACTOR = 1 / 30, // Fudge factor to account for TimeRanges rounding
15 Component = videojs.getComponent('Component'), 15 Component = videojs.getComponent('Component'),
16 16
17 // The amount of time to wait between checking the state of the buffer 17 // The amount of time to wait between checking the state of the buffer
...@@ -242,32 +242,52 @@ videojs.HlsHandler.prototype.handleSourceOpen = function() { ...@@ -242,32 +242,52 @@ videojs.HlsHandler.prototype.handleSourceOpen = function() {
242 } 242 }
243 }; 243 };
244 244
245 // Search for any end-points in `update` that do not also exist 245 // Search for a likely end time for the segment that was just appened
246 // in `original`. 246 // based on the state of the `buffered` property before and after the
247 // append.
247 // If we found only one such uncommon end-point return it. 248 // If we found only one such uncommon end-point return it.
248 videojs.Hls.findSoleUncommonTimeRangesEnd_ = function(original, update) { 249 videojs.Hls.findSoleUncommonTimeRangesEnd_ = function(original, update) {
249 var result = [], originalEnds = []; 250 var
251 i, start, end,
252 result = [],
253 edges = [],
254 // In order to qualify as a possible candidate, the end point must:
255 // 1) Not have already existed in the `original` ranges
256 // 2) Not result from the shrinking of a range that already existed
257 // in the `original` ranges
258 // 3) Not be contained inside of a range that existed in `original`
259 checkEdges = function(span) {
260 return (span[0] <= end && span[1] > end) || span[1] === end;
261 };
250 262
251 // if original or update are falsey, return an empty list of 263 if (original) {
252 // additions 264 // Save all the edges in the `original` TimeRanges object
253 if (!original || !update) { 265 for (i = 0; i < original.length; i++) {
254 return result; 266 start = original.start(i);
255 } 267 end = original.end(i);
256 268
257 // Save all the end-points in the `original` TimeRanges object 269 edges.push([start, end]);
258 for (i = 0; i < original.length; i++) { 270 }
259 originalEnds.push(original.end(i));
260 } 271 }
261 272
262 // Save any end-points in `update` that are not in the `original` 273 if (update) {
263 // TimeRanges object 274 // Save any end-points in `update` that are not in the `original`
264 for (i = 0; i < update.length; i++) { 275 // TimeRanges object
265 if (originalEnds.indexOf(update.end(i)) === -1) { 276 for (i = 0; i < update.length; i++) {
266 result.push(update.end(i)); 277 start = update.start(i);
278 end = update.end(i);
279
280 if (edges.some(checkEdges)) {
281 continue;
282 }
283
284 // at this point it must be a unique non-shrinking end edge
285 result.push(end);
267 } 286 }
268 } 287 }
269 288
270 // Return null if didn't find exactly one differing end-point 289 // we err on the side of caution and return null if didn't find
290 // exactly *one* differing end edge in the search above
271 if (result.length !== 1) { 291 if (result.length !== 1) {
272 return null; 292 return null;
273 } else { 293 } else {
...@@ -719,10 +739,6 @@ videojs.HlsHandler.prototype.checkBuffer_ = function() { ...@@ -719,10 +739,6 @@ videojs.HlsHandler.prototype.checkBuffer_ = function() {
719 * append bytes into the SourceBuffer. 739 * append bytes into the SourceBuffer.
720 */ 740 */
721 videojs.HlsHandler.prototype.startCheckingBuffer_ = function() { 741 videojs.HlsHandler.prototype.startCheckingBuffer_ = function() {
722 // if the player ever stalls, check if there is video data available
723 // to append immediately
724 this.tech_.on('waiting', (this.drainBuffer).bind(this));
725
726 this.checkBuffer_(); 742 this.checkBuffer_();
727 }; 743 };
728 744
...@@ -735,7 +751,6 @@ videojs.HlsHandler.prototype.stopCheckingBuffer_ = function() { ...@@ -735,7 +751,6 @@ videojs.HlsHandler.prototype.stopCheckingBuffer_ = function() {
735 window.clearTimeout(this.checkBufferTimeout_); 751 window.clearTimeout(this.checkBufferTimeout_);
736 this.checkBufferTimeout_ = null; 752 this.checkBufferTimeout_ = null;
737 } 753 }
738 this.tech_.off('waiting', this.drainBuffer);
739 }; 754 };
740 755
741 var filterBufferedRanges = function(predicate) { 756 var filterBufferedRanges = function(predicate) {
......
...@@ -811,7 +811,7 @@ ...@@ -811,7 +811,7 @@
811 '1001.ts\n' + 811 '1001.ts\n' +
812 '#EXTINF:5,\n' + 812 '#EXTINF:5,\n' +
813 '1002.ts\n'); 813 '1002.ts\n');
814 loader.media().segments[0].start = 150; 814 loader.media().segments[0].end = 154;
815 815
816 equal(loader.getMediaIndexForTime_(0), -1, 'the lowest returned value is negative one'); 816 equal(loader.getMediaIndexForTime_(0), -1, 'the lowest returned value is negative one');
817 equal(loader.getMediaIndexForTime_(45), -1, 'expired content returns negative one'); 817 equal(loader.getMediaIndexForTime_(45), -1, 'expired content returns negative one');
...@@ -819,6 +819,7 @@ ...@@ -819,6 +819,7 @@
819 equal(loader.getMediaIndexForTime_(50 + 100), 0, 'calculates the earliest available position'); 819 equal(loader.getMediaIndexForTime_(50 + 100), 0, 'calculates the earliest available position');
820 equal(loader.getMediaIndexForTime_(50 + 100 + 2), 0, 'calculates within the first segment'); 820 equal(loader.getMediaIndexForTime_(50 + 100 + 2), 0, 'calculates within the first segment');
821 equal(loader.getMediaIndexForTime_(50 + 100 + 2), 0, 'calculates within the first segment'); 821 equal(loader.getMediaIndexForTime_(50 + 100 + 2), 0, 'calculates within the first segment');
822 equal(loader.getMediaIndexForTime_(50 + 100 + 4), 1, 'calculates within the second segment');
822 equal(loader.getMediaIndexForTime_(50 + 100 + 4.5), 1, 'calculates within the second segment'); 823 equal(loader.getMediaIndexForTime_(50 + 100 + 4.5), 1, 'calculates within the second segment');
823 equal(loader.getMediaIndexForTime_(50 + 100 + 6), 1, 'calculates within the second segment'); 824 equal(loader.getMediaIndexForTime_(50 + 100 + 6), 1, 'calculates within the second segment');
824 }); 825 });
...@@ -837,9 +838,9 @@ ...@@ -837,9 +838,9 @@
837 loader.expired_ = 160; 838 loader.expired_ = 160;
838 // annotate the first segment with a start time 839 // annotate the first segment with a start time
839 // this number would be coming from the Source Buffer in practice 840 // this number would be coming from the Source Buffer in practice
840 loader.media().segments[0].start = 150; 841 loader.media().segments[0].end = 150;
841 842
842 equal(loader.getMediaIndexForTime_(151), 0, 'prefers the value on the first segment'); 843 equal(loader.getMediaIndexForTime_(149), 0, 'prefers the value on the first segment');
843 844
844 clock.tick(10 * 1000); // trigger a playlist refresh 845 clock.tick(10 * 1000); // trigger a playlist refresh
845 requests.shift().respond(200, null, 846 requests.shift().respond(200, null,
......
...@@ -2745,47 +2745,72 @@ test('does not download segments if preload option set to none', function() { ...@@ -2745,47 +2745,72 @@ test('does not download segments if preload option set to none', function() {
2745 2745
2746 module('Buffer Inspection'); 2746 module('Buffer Inspection');
2747 2747
2748 test('detects time range edges added by updates', function() { 2748 test('detects time range end-point changed by updates', function() {
2749 var edges; 2749 var edge;
2750 2750
2751 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([[0, 10]]), 2751 // Single-range changes
2752 videojs.createTimeRange([[0, 11]])); 2752 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10]]),
2753 deepEqual(edges, [{ end: 11 }], 'detected a forward addition'); 2753 videojs.createTimeRange([[0, 11]]));
2754 2754 strictEqual(edge, 11, 'detected a forward addition');
2755 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([[5, 10]]), 2755
2756 videojs.createTimeRange([[0, 10]])); 2756 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[5, 10]]),
2757 deepEqual(edges, [{ start: 0 }], 'detected a backward addition'); 2757 videojs.createTimeRange([[0, 10]]));
2758 2758 strictEqual(edge, null, 'ignores backward addition');
2759 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([[5, 10]]), 2759
2760 videojs.createTimeRange([[0, 11]])); 2760 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[5, 10]]),
2761 deepEqual(edges, [ 2761 videojs.createTimeRange([[0, 11]]));
2762 { start: 0 }, { end: 11 } 2762 strictEqual(edge, 11, 'detected a forward addition & ignores a backward addition');
2763 ], 'detected forward and backward additions'); 2763
2764 2764 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10]]),
2765 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([[0, 10]]), 2765 videojs.createTimeRange([[0, 9]]));
2766 videojs.createTimeRange([[0, 10]])); 2766 strictEqual(edge, null, 'ignores a backwards addition resulting from a shrinking range');
2767 deepEqual(edges, [], 'detected no addition'); 2767
2768 2768 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10]]),
2769 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([]), 2769 videojs.createTimeRange([[2, 7]]));
2770 videojs.createTimeRange([[0, 10]])); 2770 strictEqual(edge, null, 'ignores a forward & backwards addition resulting from a shrinking range');
2771 deepEqual(edges, [ 2771
2772 { start: 0 }, 2772 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[2, 10]]),
2773 { end: 10 } 2773 videojs.createTimeRange([[0, 7]]));
2774 ], 'detected an initial addition'); 2774 strictEqual(edge, null, 'ignores a forward & backwards addition resulting from a range shifted backward');
2775 2775
2776 edges = videojs.Hls.bufferedAdditions_(videojs.createTimeRange([[0, 10]]), 2776 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[2, 10]]),
2777 videojs.createTimeRange([[0, 10], [20, 30]])); 2777 videojs.createTimeRange([[5, 15]]));
2778 deepEqual(edges, [ 2778 strictEqual(edge, 15, 'detected a forwards addition resulting from a range shifted foward');
2779 { start: 20 }, 2779
2780 { end: 30} 2780 // Multiple-range changes
2781 ], 'detected a non-contiguous addition'); 2781 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10]]),
2782 }); 2782 videojs.createTimeRange([[0, 11], [12, 15]]));
2783 2783 strictEqual(edge, null, 'ignores multiple new forward additions');
2784 test('treats null buffered ranges as no addition', function() { 2784
2785 var edges = videojs.Hls.bufferedAdditions_(null, 2785 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10], [20, 40]]),
2786 videojs.createTimeRange([[0, 11]])); 2786 videojs.createTimeRange([[20, 50]]));
2787 2787 strictEqual(edge, 50, 'detected a forward addition & ignores range removal');
2788 equal(edges.length, 0, 'no additions'); 2788
2789 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10], [20, 40]]),
2790 videojs.createTimeRange([[0, 50]]));
2791 strictEqual(edge, 50, 'detected a forward addition & ignores merges');
2792
2793 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 10], [20, 40]]),
2794 videojs.createTimeRange([[0, 40]]));
2795 strictEqual(edge, null, 'ignores merges');
2796
2797 // Empty input
2798 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange(),
2799 videojs.createTimeRange([[0, 11]]));
2800 strictEqual(edge, 11, 'handle an empty original TimeRanges object');
2801
2802 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 11]]),
2803 videojs.createTimeRange());
2804 strictEqual(edge, null, 'handle an empty update TimeRanges object');
2805
2806 // Null input
2807 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(null,
2808 videojs.createTimeRange([[0, 11]]));
2809 strictEqual(edge, 11, 'treat null original buffer as an empty TimeRanges object');
2810
2811 edge = videojs.Hls.findSoleUncommonTimeRangesEnd_(videojs.createTimeRange([[0, 11]]),
2812 null);
2813 strictEqual(edge, null, 'treat null update buffer as an empty TimeRanges object');
2789 }); 2814 });
2790 2815
2791 })(window, window.videojs); 2816 })(window, window.videojs);
......