c8da7b50 by marguinbc Committed by Jon-Carlos Rivera

Prevent trimming buffer between segment boundaries (#773)

* add trimBuffer_ helper function to streamline loadSegment
1 parent 47f303d1
...@@ -503,14 +503,16 @@ export default class SegmentLoader extends videojs.EventTarget { ...@@ -503,14 +503,16 @@ export default class SegmentLoader extends videojs.EventTarget {
503 } 503 }
504 504
505 /** 505 /**
506 * load a specific segment from a request into the buffer 506 * trim the back buffer so we only remove content
507 * on segment boundaries
507 * 508 *
508 * @private 509 * @private
510 *
511 * @param {Object} segmentInfo - the current segment
512 * @returns {Number} removeToTime - the end point in time, in seconds
513 * that the the buffer should be trimmed.
509 */ 514 */
510 loadSegment_(segmentInfo) { 515 trimBuffer_(segmentInfo) {
511 let segment;
512 let keyXhr;
513 let segmentXhr;
514 let seekable = this.seekable_(); 516 let seekable = this.seekable_();
515 let currentTime = this.currentTime_(); 517 let currentTime = this.currentTime_();
516 let removeToTime = 0; 518 let removeToTime = 0;
...@@ -531,6 +533,43 @@ export default class SegmentLoader extends videojs.EventTarget { ...@@ -531,6 +533,43 @@ export default class SegmentLoader extends videojs.EventTarget {
531 removeToTime = currentTime - 60; 533 removeToTime = currentTime - 60;
532 } 534 }
533 535
536 // If we are going to remove time from the front of the buffer, make
537 // sure we aren't discarding a partial segment to avoid throwing
538 // PLAYER_ERR_TIMEOUT while trying to read a partially discarded segment
539 for (let i = 0; i <= segmentInfo.playlist.segments.length; i++) {
540 // Loop through the segments and calculate the duration to compare
541 // against the removeToTime
542 let removeDuration = duration(segmentInfo.playlist,
543 segmentInfo.playlist.mediaSequence + i,
544 this.expired_);
545
546 // If we are close to next segment begining, remove to end of previous
547 // segment instead
548 let previousDuration = duration(segmentInfo.playlist,
549 segmentInfo.playlist.mediaSequence + (i - 1),
550 this.expired_);
551
552 if (removeDuration >= removeToTime) {
553 removeToTime = previousDuration;
554 break;
555 }
556 }
557 return removeToTime;
558 }
559
560 /**
561 * load a specific segment from a request into the buffer
562 *
563 * @private
564 */
565 loadSegment_(segmentInfo) {
566 let segment;
567 let keyXhr;
568 let segmentXhr;
569 let removeToTime = 0;
570
571 removeToTime = this.trimBuffer_(segmentInfo);
572
534 if (removeToTime > 0) { 573 if (removeToTime > 0) {
535 this.sourceUpdater_.remove(0, removeToTime); 574 this.sourceUpdater_.remove(0, removeToTime);
536 } 575 }
......
...@@ -2016,7 +2016,9 @@ QUnit.test('cleans up the buffer when loading live segments', function() { ...@@ -2016,7 +2016,9 @@ QUnit.test('cleans up the buffer when loading live segments', function() {
2016 QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8', 2016 QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8',
2017 'master playlist requested'); 2017 'master playlist requested');
2018 QUnit.equal(removes.length, 1, 'remove called'); 2018 QUnit.equal(removes.length, 1, 'remove called');
2019 QUnit.deepEqual(removes[0], [0, seekable.start(0)], 2019 // segment-loader removes up to the segment prior to seekable.start
2020 // to avoid crossing segment-boundaries
2021 QUnit.deepEqual(removes[0], [0, seekable.start(0) - 10],
2020 'remove called with the right range'); 2022 'remove called with the right range');
2021 2023
2022 // verify stats 2024 // verify stats
...@@ -2071,7 +2073,7 @@ QUnit.test('cleans up the buffer based on currentTime when loading a live segmen ...@@ -2071,7 +2073,7 @@ QUnit.test('cleans up the buffer based on currentTime when loading a live segmen
2071 2073
2072 QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8', 'master playlist requested'); 2074 QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8', 'master playlist requested');
2073 QUnit.equal(removes.length, 1, 'remove called'); 2075 QUnit.equal(removes.length, 1, 'remove called');
2074 QUnit.deepEqual(removes[0], [0, 80 - 60], 'remove called with the right range'); 2076 QUnit.deepEqual(removes[0], [0, 80 - 70], 'remove called with the right range');
2075 2077
2076 // verify stats 2078 // verify stats
2077 QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); 2079 QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes');
......