6ad09e5d by Jon-Carlos Rivera

Merge pull request #463 from videojs/simplify-stuff

Simplify stuff
2 parents d702ed19 b7b5d4d1
...@@ -422,7 +422,6 @@ ...@@ -422,7 +422,6 @@
422 i, 422 i,
423 segment, 423 segment,
424 originalTime = time, 424 originalTime = time,
425 targetDuration = this.media_.targetDuration || 10,
426 numSegments = this.media_.segments.length, 425 numSegments = this.media_.segments.length,
427 lastSegment = numSegments - 1, 426 lastSegment = numSegments - 1,
428 startIndex, 427 startIndex,
...@@ -442,70 +441,36 @@ ...@@ -442,70 +441,36 @@
442 441
443 // find segments with known timing information that bound the 442 // find segments with known timing information that bound the
444 // target time 443 // target time
445
446 // Walk backward until we find the first segment with timeline
447 // information that is earlier than `time`
448 for (i = lastSegment; i >= 0; i--) {
449 segment = this.media_.segments[i];
450 if (segment.end !== undefined && segment.end <= time) {
451 startIndex = i + 1;
452 knownStart = segment.end;
453 if (startIndex >= numSegments) {
454 // The last segment claims to end *before* the time we are
455 // searching for so just return it
456 return numSegments;
457 }
458 break;
459 }
460 if (segment.start !== undefined && segment.start <= time) {
461 if (segment.end !== undefined && segment.end > time) {
462 // we've found the target segment exactly
463 return i;
464 }
465 startIndex = i;
466 knownStart = segment.start;
467 break;
468 }
469 }
470
471 // Walk forward until we find the first segment with timeline
472 // information that is greater than `time`
473 for (i = 0; i < numSegments; i++) { 444 for (i = 0; i < numSegments; i++) {
474 segment = this.media_.segments[i]; 445 segment = this.media_.segments[i];
475 if (segment.start !== undefined && segment.start > time) { 446 if (segment.end) {
476 endIndex = i - 1; 447 if (segment.end > time) {
477 knownEnd = segment.start; 448 knownEnd = segment.end;
478 if (endIndex < 0) { 449 endIndex = i;
479 // The first segment claims to start *after* the time we are 450 break;
480 // searching for so the target segment must no longer be 451 } else {
481 // available 452 knownStart = segment.end;
482 return -1; 453 startIndex = i + 1;
483 } 454 }
484 break;
485 }
486 if (segment.end !== undefined && segment.end > time) {
487 endIndex = i;
488 knownEnd = segment.end;
489 break;
490 } 455 }
491 } 456 }
492 457
493 // use the bounds we just found and playlist information to 458 // use the bounds we just found and playlist information to
494 // estimate the segment that contains the time we are looking for 459 // estimate the segment that contains the time we are looking for
495
496 if (startIndex !== undefined) { 460 if (startIndex !== undefined) {
497 // We have a known-start point that is before our desired time so 461 // We have a known-start point that is before our desired time so
498 // walk from that point forwards 462 // walk from that point forwards
499 time = time - knownStart; 463 time = time - knownStart;
500 for (i = startIndex; i < (endIndex || numSegments); i++) { 464 for (i = startIndex; i < (endIndex || numSegments); i++) {
501 segment = this.media_.segments[i]; 465 segment = this.media_.segments[i];
502 time -= segment.duration || targetDuration; 466 time -= segment.duration;
467
503 if (time < 0) { 468 if (time < 0) {
504 return i; 469 return i;
505 } 470 }
506 } 471 }
507 472
508 if (i === endIndex) { 473 if (i >= endIndex) {
509 // We haven't found a segment but we did hit a known end point 474 // We haven't found a segment but we did hit a known end point
510 // so fallback to interpolating between the segment index 475 // so fallback to interpolating between the segment index
511 // based on the known span of the timeline we are dealing with 476 // based on the known span of the timeline we are dealing with
...@@ -523,24 +488,32 @@ ...@@ -523,24 +488,32 @@
523 time = knownEnd - time; 488 time = knownEnd - time;
524 for (i = endIndex; i >= 0; i--) { 489 for (i = endIndex; i >= 0; i--) {
525 segment = this.media_.segments[i]; 490 segment = this.media_.segments[i];
526 time -= segment.duration || targetDuration; 491 time -= segment.duration;
492
527 if (time < 0) { 493 if (time < 0) {
528 return i; 494 return i;
529 } 495 }
530 } 496 }
531 // We haven't found a segment so load the first one 497
532 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 }
533 } else { 504 } else {
534 // We known nothing so walk from the front of the playlist, 505 // We known nothing so walk from the front of the playlist,
535 // subtracting durations until we find a segment that contains 506 // subtracting durations until we find a segment that contains
536 // time and return it 507 // time and return it
537 time = time - this.expired_; 508 time = time - this.expired_;
509
538 if (time < 0) { 510 if (time < 0) {
539 return -1; 511 return -1;
540 } 512 }
513
541 for (i = 0; i < numSegments; i++) { 514 for (i = 0; i < numSegments; i++) {
542 segment = this.media_.segments[i]; 515 segment = this.media_.segments[i];
543 time -= segment.duration || targetDuration; 516 time -= segment.duration;
544 if (time < 0) { 517 if (time < 0) {
545 return i; 518 return i;
546 } 519 }
......
...@@ -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,61 +242,57 @@ videojs.HlsHandler.prototype.handleSourceOpen = function() { ...@@ -242,61 +242,57 @@ videojs.HlsHandler.prototype.handleSourceOpen = function() {
242 } 242 }
243 }; 243 };
244 244
245 // Returns the array of time range edge objects that were additively 245 // Search for a likely end time for the segment that was just appened
246 // modified between two TimeRanges. 246 // based on the state of the `buffered` property before and after the
247 videojs.Hls.bufferedAdditions_ = function(original, update) { 247 // append.
248 var result = [], edges = [], 248 // If we found only one such uncommon end-point return it.
249 i, inOriginalRanges; 249 videojs.Hls.findSoleUncommonTimeRangesEnd_ = function(original, update) {
250 250 var
251 // if original or update are falsey, return an empty list of 251 i, start, end,
252 // additions 252 result = [],
253 if (!original || !update) { 253 edges = [],
254 return result; 254 // In order to qualify as a possible candidate, the end point must:
255 } 255 // 1) Not have already existed in the `original` ranges
256 256 // 2) Not result from the shrinking of a range that already existed
257 // create a sorted array of time range start and end times 257 // in the `original` ranges
258 for (i = 0; i < original.length; i++) { 258 // 3) Not be contained inside of a range that existed in `original`
259 edges.push({ original: true, start: original.start(i) }); 259 overlapsCurrentEnd = function(span) {
260 edges.push({ original: true, end: original.end(i) }); 260 return (span[0] <= end && span[1] >= end);
261 } 261 };
262 for (i = 0; i < update.length; i++) {
263 edges.push({ start: update.start(i) });
264 edges.push({ end: update.end(i) });
265 }
266 edges.sort(function(left, right) {
267 var leftTime, rightTime;
268 leftTime = left.start !== undefined ? left.start : left.end;
269 rightTime = right.start !== undefined ? right.start : right.end;
270
271 // when two times are equal, ensure the original edge covers the
272 // update
273 if (leftTime === rightTime) {
274 if (left.original) {
275 return left.start !== undefined ? -1 : 1;
276 }
277 return right.start !== undefined ? -1 : 1;
278 }
279 return leftTime - rightTime;
280 });
281 262
282 // filter out all time range edges that occur during a period that 263 if (original) {
283 // was already covered by `original` 264 // Save all the edges in the `original` TimeRanges object
284 inOriginalRanges = false; 265 for (i = 0; i < original.length; i++) {
285 for (i = 0; i < edges.length; i++) { 266 start = original.start(i);
286 // if this is a transition point for `original`, track whether 267 end = original.end(i);
287 // subsequent edges are additions 268
288 if (edges[i].original) { 269 edges.push([start, end]);
289 inOriginalRanges = edges[i].start !== undefined;
290 continue;
291 } 270 }
292 // if we're in a time range that was in `original`, ignore this edge 271 }
293 if (inOriginalRanges) { 272
294 continue; 273 if (update) {
274 // Save any end-points in `update` that are not in the `original`
275 // TimeRanges object
276 for (i = 0; i < update.length; i++) {
277 start = update.start(i);
278 end = update.end(i);
279
280 if (edges.some(overlapsCurrentEnd)) {
281 continue;
282 }
283
284 // at this point it must be a unique non-shrinking end edge
285 result.push(end);
295 } 286 }
296 // this edge occurred outside the range of `original`
297 result.push(edges[i]);
298 } 287 }
299 return result; 288
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
291 if (result.length !== 1) {
292 return null;
293 }
294
295 return result[0];
300 }; 296 };
301 297
302 var parseCodecs = function(codecs) { 298 var parseCodecs = function(codecs) {
...@@ -743,10 +739,6 @@ videojs.HlsHandler.prototype.checkBuffer_ = function() { ...@@ -743,10 +739,6 @@ videojs.HlsHandler.prototype.checkBuffer_ = function() {
743 * append bytes into the SourceBuffer. 739 * append bytes into the SourceBuffer.
744 */ 740 */
745 videojs.HlsHandler.prototype.startCheckingBuffer_ = function() { 741 videojs.HlsHandler.prototype.startCheckingBuffer_ = function() {
746 // if the player ever stalls, check if there is video data available
747 // to append immediately
748 this.tech_.on('waiting', (this.drainBuffer).bind(this));
749
750 this.checkBuffer_(); 742 this.checkBuffer_();
751 }; 743 };
752 744
...@@ -759,7 +751,6 @@ videojs.HlsHandler.prototype.stopCheckingBuffer_ = function() { ...@@ -759,7 +751,6 @@ videojs.HlsHandler.prototype.stopCheckingBuffer_ = function() {
759 window.clearTimeout(this.checkBufferTimeout_); 751 window.clearTimeout(this.checkBufferTimeout_);
760 this.checkBufferTimeout_ = null; 752 this.checkBufferTimeout_ = null;
761 } 753 }
762 this.tech_.off('waiting', this.drainBuffer);
763 }; 754 };
764 755
765 var filterBufferedRanges = function(predicate) { 756 var filterBufferedRanges = function(predicate) {
...@@ -1008,6 +999,12 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { ...@@ -1008,6 +999,12 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
1008 // decrease in network performance or a server issue. 999 // decrease in network performance or a server issue.
1009 timeout: (segment.duration * 1.5) * 1000 1000 timeout: (segment.duration * 1.5) * 1000
1010 }, function(error, request) { 1001 }, function(error, request) {
1002 // This is a timeout of a previously aborted segment request
1003 // so simply ignore it
1004 if (!self.segmentXhr_ || request !== self.segmentXhr_) {
1005 return;
1006 }
1007
1011 // the segment request is no longer outstanding 1008 // the segment request is no longer outstanding
1012 self.segmentXhr_ = null; 1009 self.segmentXhr_ = null;
1013 1010
...@@ -1019,7 +1016,6 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { ...@@ -1019,7 +1016,6 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
1019 1016
1020 // otherwise, trigger a network error 1017 // otherwise, trigger a network error
1021 if (!request.aborted && error) { 1018 if (!request.aborted && error) {
1022 self.pendingSegment_ = null;
1023 return self.blacklistCurrentPlaylist_({ 1019 return self.blacklistCurrentPlaylist_({
1024 status: request.status, 1020 status: request.status,
1025 message: 'HLS segment request error at URL: ' + segmentInfo.uri, 1021 message: 'HLS segment request error at URL: ' + segmentInfo.uri,
...@@ -1040,7 +1036,9 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { ...@@ -1040,7 +1036,9 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
1040 } else { 1036 } else {
1041 segmentInfo.bytes = new Uint8Array(request.response); 1037 segmentInfo.bytes = new Uint8Array(request.response);
1042 } 1038 }
1039
1043 self.pendingSegment_ = segmentInfo; 1040 self.pendingSegment_ = segmentInfo;
1041
1044 self.tech_.trigger('progress'); 1042 self.tech_.trigger('progress');
1045 self.drainBuffer(); 1043 self.drainBuffer();
1046 1044
...@@ -1048,6 +1046,7 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { ...@@ -1048,6 +1046,7 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) {
1048 // with the updated bandwidth information 1046 // with the updated bandwidth information
1049 self.playlists.media(self.selectPlaylist()); 1047 self.playlists.media(self.selectPlaylist());
1050 }); 1048 });
1049
1051 }; 1050 };
1052 1051
1053 videojs.HlsHandler.prototype.drainBuffer = function(event) { 1052 videojs.HlsHandler.prototype.drainBuffer = function(event) {
...@@ -1170,7 +1169,7 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1170,7 +1169,7 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1170 currentMediaIndex, 1169 currentMediaIndex,
1171 currentBuffered, 1170 currentBuffered,
1172 seekable, 1171 seekable,
1173 timelineUpdates; 1172 timelineUpdate;
1174 1173
1175 this.pendingSegment_ = null; 1174 this.pendingSegment_ = null;
1176 1175
...@@ -1211,15 +1210,13 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1211,15 +1210,13 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1211 } 1210 }
1212 } 1211 }
1213 1212
1214 timelineUpdates = videojs.Hls.bufferedAdditions_(segmentInfo.buffered, 1213
1215 this.tech_.buffered()); 1214 timelineUpdate = videojs.Hls.findSoleUncommonTimeRangesEnd_(segmentInfo.buffered,
1216 timelineUpdates.forEach(function (update) { 1215 this.tech_.buffered());
1217 if (segment) { 1216
1218 if (update.end !== undefined) { 1217 if (timelineUpdate && segment) {
1219 segment.end = update.end; 1218 segment.end = timelineUpdate;
1220 } 1219 }
1221 }
1222 });
1223 1220
1224 // if we've buffered to the end of the video, let the MediaSource know 1221 // if we've buffered to the end of the video, let the MediaSource know
1225 if (this.playlists.media().endList && 1222 if (this.playlists.media().endList &&
...@@ -1230,7 +1227,7 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () { ...@@ -1230,7 +1227,7 @@ videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1230 return; 1227 return;
1231 } 1228 }
1232 1229
1233 if (timelineUpdates.length || 1230 if (timelineUpdate !== null ||
1234 segmentInfo.buffered.length !== this.tech_.buffered().length) { 1231 segmentInfo.buffered.length !== this.tech_.buffered().length) {
1235 this.updateDuration(playlist); 1232 this.updateDuration(playlist);
1236 // check if it's time to download the next segment 1233 // check if it's time to download the next segment
......
...@@ -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);
......