From 9e6da5a6e96234fa99b96e3931774781d11e2ac8 Mon Sep 17 00:00:00 2001 From: Aidan Ridley Date: Wed, 19 May 2021 14:00:05 -0600 Subject: [PATCH] fix: Fix buffering due to re-fetch (SegmentIterator) (#3419) In multi-period live DASH streams, the SegmentIterator would sometimes get reset to a value pointing to the beginning of the segment references for the period, causing StreamingEngine to re-fetch segments it already had. This fixes SegmentIterator's getIteratorForTime() to return null when a reference can't be found, and fixes StreamingEngine to handle null returns by waiting and checking again. Closes #3354 b/186457868 Change-Id: I2b34ee52dd12b59e1c1237258050b50e3189bee3 --- lib/media/segment_index.js | 20 ++++++++++++++------ lib/media/streaming_engine.js | 9 ++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 9eb828b891..75149dfafa 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -383,22 +383,25 @@ shaka.media.SegmentIndex = class { /** @return {!shaka.media.SegmentIterator} */ [Symbol.iterator]() { - return this.getIteratorForTime(0); + const iter = this.getIteratorForTime(0); + goog.asserts.assert(iter != null, 'Iterator for 0 should never be null!'); + return iter; } /** * Returns a new iterator that initially points to the segment that contains * the given time. Like the normal iterator, next() must be called first to - * get to the first element. + * get to the first element. Returns null if we do not find a segment at the + * requested time. * * @param {number} time - * @return {!shaka.media.SegmentIterator} + * @return {?shaka.media.SegmentIterator} * @export */ getIteratorForTime(time) { let index = this.find(time); if (index == null) { - index = -1; + return null; } else { index--; } @@ -517,8 +520,13 @@ shaka.media.SegmentIterator = class { 'Please use SegmentIndex.getIteratorForTime instead of seek().'); const iter = this.segmentIndex_.getIteratorForTime(time); - this.currentPosition_ = iter.currentPosition_; - this.currentPartialPosition_ = iter.currentPartialPosition_; + if (iter) { + this.currentPosition_ = iter.currentPosition_; + this.currentPartialPosition_ = iter.currentPartialPosition_; + } else { + this.currentPosition_ = Number.MAX_VALUE; + this.currentPartialPosition_ = 0; + } return this.next().value; } diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index d17c74fefa..3d1419bc25 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -1113,7 +1113,8 @@ shaka.media.StreamingEngine = class { mediaState.segmentIterator = mediaState.stream.segmentIndex.getIteratorForTime(time); - const ref = mediaState.segmentIterator.next().value; + const ref = mediaState.segmentIterator && + mediaState.segmentIterator.next().value; if (ref == null) { shaka.log.warning(logPrefix, 'cannot find segment', 'endTime:', time); } @@ -1135,14 +1136,16 @@ shaka.media.StreamingEngine = class { if (inaccurateTolerance) { mediaState.segmentIterator = mediaState.stream.segmentIndex.getIteratorForTime(lookupTime); - ref = mediaState.segmentIterator.next().value; + ref = mediaState.segmentIterator && + mediaState.segmentIterator.next().value; } if (!ref) { // If we can't find a valid segment with the drifted time, look for a // segment with the presentation time. mediaState.segmentIterator = mediaState.stream.segmentIndex.getIteratorForTime(presentationTime); - ref = mediaState.segmentIterator.next().value; + ref = mediaState.segmentIterator && + mediaState.segmentIterator.next().value; } if (ref == null) { shaka.log.warning(logPrefix, 'cannot find segment',