Skip to content

Commit

Permalink
fix: Fix buffering due to re-fetch (SegmentIterator) (shaka-project#3419
Browse files Browse the repository at this point in the history
)

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 shaka-project#3354

b/186457868

Change-Id: I2b34ee52dd12b59e1c1237258050b50e3189bee3
  • Loading branch information
caridley authored and joeyparrish committed Jun 16, 2021
1 parent 9dc4664 commit 9e6da5a
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 9 deletions.
20 changes: 14 additions & 6 deletions lib/media/segment_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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--;
}
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 6 additions & 3 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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',
Expand Down

0 comments on commit 9e6da5a

Please sign in to comment.