RepresentationBuffer
Overview
The RepresentationBuffer download and push segments linked to a given Representation.
It constructs a list of segments to download, which depend on the current timing values and parameters. It then download and push them to a linked SourceBuffer.
Multiple RepresentationBuffer observables can be ran on the same SourceBuffer without problems. This allows for example smooth transitions between multiple periods.
Return value
The RepresentationBuffer returns an Observable which emits multiple notifications depending on what is happening at its core.
Such events tells us when:
-
Segments are being scheduled for download
-
The RepresentationBuffer has no segment left for download
-
The RepresentationBuffer appended a new Segment to the SourceBuffer
-
The Manifest should be refreshed to allow the RepresentationBuffer to download future-needed segments.
-
A discontinuity is currently encountered in the Stream (TODO this might not be the job of the RepresentationBuffer)
Queue Algorithm
The RepresentationBuffer 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 calculus 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 SourceBuffer at a better quality.
For a clock based on various video events, the strategy is the following:
-
let
segmentQueue
be 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,
segmentQueue
should 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
segmentsNeeded
3-2. If there is one but for a segment different than the first element in
segmentsNeeded
or ifsegmentsNeeded
is empty, abort this request and letsegmentQueue
be equal tosegmentsNeeded
.3-3. If there is one and is for the same segment than the first element in
segmentsNeeded
, letsegmentQueue
be equal tosegmentsNeeded
without its first element. -
if
segmentQueue
is 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
currentSegment
be the first segment ofsegmentQueue
-
Remove the first segment from
segmentQueue
(a.k.a.currentSegment
) -
perform a request for
currentSegment
and wait for it to finish. During this time, step 2 to 5 can run in parallel, and as suchSegmentQueue
can be mutated during this process. -
Once the request is finished, run those tasks in parallel:
9-1. Append the segment to the corresponding SourceBuffer
9-1. go back to step 4.