RepresentationStream
Overview
The RepresentationStream download and push segments linked to a given
Representation.
It constructs a list of segments to download, which depend on the current
playback conditions.
It then download and push them to a linked SegmentBuffer (the media buffer
containing the segments for later decoding).
Multiple RepresentationStream observables can be ran on the same
SegmentBuffer without problems, as long as they are linked to different
Periods of the Manifest.
This allows for example smooth transitions between multiple periods.
Return value
The RepresentationStream returns an Observable which emits multiple
notifications depending on what is happening at its core, like:
-
when segments are scheduled for download
-
when segments are pushed to the associated
SegmentBuffer -
when the Manifest needs to be refreshed to obtain information on possible
-
whether the
RepresentationStreamfinished to load segments until the end of the current Period. This can for example allow the creation of aRepresentationStreamfor the next Period for pre-loading purposes. -
whether there are discontinuities: holes in the stream that won’t be filled by segments and can thus be skipped
Queue Algorithm
The RepresentationStream depends on a central algorithm to make sure that the right segments are scheduled for download at any time.
This algorithm constructs a queue of segments to download at any time, and regularly checks that the segment currently downloaded still corresponds to the currently most needed Segment.
This list of segments is based on a simple calculation between the current
position and the buffer size we want to achieve.
This list goes then through multiple filters to ensure we’re not queueing them
unnecessarly. Such cases would be, for example, if the segment is already
present in the SegmentBuffer at a better quality.
For a clock based on various video events, the strategy is the following:
-
let
segmentQueuebe an empty array. -
On each clock tick, calculate
segmentsNeeded, an Array of needed segments (read: not yet downloaded) from the current time to the buffer size goal.Note that the steps 2 to 5 can run multiple times while waiting for a request - happening in step 5 and 8. If that happens,
segmentQueueshould equal the last value it has been given. -
check if there’s a segment currently downloaded (launched in step 8)
3-1. If there is none, let segmentQueue be equal to
segmentsNeeded3-2. If there is one but for a segment different than the first element in
segmentsNeededor ifsegmentsNeededis empty, abort this request and letsegmentQueuebe equal tosegmentsNeeded.3-3. If there is one and is for the same segment than the first element in
segmentsNeeded, letsegmentQueuebe equal tosegmentsNeededwithout its first element. -
if
segmentQueueis empty, go back to 2. -
check if there’s a pending segment request (happening in step 8):
5-1. if there’s no segment request, continue
5-1. if there’s a pending segment request, go back to 2
-
Let
currentSegmentbe the first segment ofsegmentQueue -
Remove the first segment from
segmentQueue(a.k.a.currentSegment) -
perform a request for
currentSegmentand wait for it to finish. During this time, step 2 to 5 can run in parallel, and as suchSegmentQueuecan be mutated during this process. -
Once the request is finished, run those tasks in parallel:
9-1. Append the segment to the corresponding
SegmentBuffer9-1. go back to step 4.