Skip to content

Commit

Permalink
Move Stream's DownloadingQueue into fetchers' SegmentQueue
Browse files Browse the repository at this point in the history
While working on CMCD (#1461), I saw an opportunity for doing a
refactoring that I initially postponed: moving what was called the
`DownloadingQueue` from the `RepresentationStream` to the `fetchers`
code.

The modules involved
--------------------

The `DownloadingQueue` is a class allowing to put the current list of
wanted segments for a given media type (audio, video, text) into a FIFO
queue so they can be requested from the most urgent (usually the one
coming right next in the corresponding media buffer) to the least urgent
(usually the ones consecutive to that segment, in chronological order) -
through a simple interface.

The `DownloadingQueue` does both the queueing (the list of wanted
segments is given to it as input) and the requesting (by relying on an
instanciated `SegmentFetcher` - defined in the `fetchers` code) as well
as some optimizations such as requesting the initialization segment at
the same time than the initially-wanted media segment when possible.

Previously, that `DownloadingQueue` was part of the
`RepresentationStream` (in the `src/core/stream/representation`
directory).

The `RepresentationStream` is documented as the module whose role is to
find the right segments to load, to orchestrate their requests and then
to push them into the right `SegmentSink` (`src/core/segment_sinks`).

In terms of responsibility and readability of the code it can make
sense to put the `DownloadingQueue` in the `RepresentationStream`, but
I always felt that it would be more at its place in the `fetchers` code
for segments instead (in `src/core/fetchers/segment).

The `fetchers` code for segments's role is to actually perform the
segment requests, and do so in a transport-agnostic way (the
transport-specific part being defined in `src/transports` which is
directly used by the `fetchers` code).

What I did here
---------------

Basically, I moved the `DownloadingQueue` file into the
`src/core/fetchers/segment` directory and renamed it `SegmentQueue` as
it made more sense to me to remove the `Downloading` part from the name
now that it is implied from its new location, and add the `Segment`
part, which is sort of a convention in the `fetchers` to separate
manifest-related code to segment-related code.

I then made the `SegmentQueue` one of the main modules to be used by
code external to the `fetchers` (here principally the
`RepresentationStream`) instead of the `PrioritizedSegmentFetcher` like
before.

I also tried to simplify the whole `fetchers` API for segments so it can
be straightforward to use from other modules without having to understand
logic specific to that part.

What's the relation with CMCD
-----------------------------

As written at the start, this was done in relation with my work on CMCD,
because that scheme can optionally provide to the CDN hints about what
segment it is going to load next (with the previous segment's request).

Previously, this would have meant an akward supplementary parameter
somewhere asking for information on the next wanted segment for what's
in the end very specific.

By instead updating the `fetchers` (which is the module directly
exploiting CMCD) so its API is already aware of the current queue of
wanted segments (and not just the most urgent one like before),
implementing "next segment hints" can be done without having to involve
any other module.
  • Loading branch information
peaBerberian committed Jun 21, 2024
1 parent 2b8dcfd commit 7657876
Show file tree
Hide file tree
Showing 18 changed files with 355 additions and 282 deletions.
23 changes: 12 additions & 11 deletions src/core/fetchers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ This directory actually exports two completely isolated type of fetchers:

- The **Manifest fetcher** is used to download and parse the manifest file.

- The **SegmentFetcherCreator** is used to create Segment fetchers, allowing to download
and parse media segments.
- The **SegmentQueueCreator** is used to create `SegmentQueue` objects, allowing
to download and parse media segments.

## The Manifest fetcher

Expand All @@ -32,22 +32,23 @@ parsing of the Manifest file.
It also regularly refreshes the Manifest, based on its attributes and other criteria, like
performances when doing that.

## The SegmentFetcherCreator
## The SegmentQueueCreator

The SegmentFetcherCreator allows to easily perform segment downloads for the rest of the
The SegmentQueueCreator allows to easily perform segment downloads for the rest of the
code. This is the part of the code that interacts with the transport protocols - defined
in `stc/transports` - to load and parse media segments.

To do so, the SegmentFetcherCreator creates "segment fetchers" of different types
(example: a video or audio segment fetcher) when you ask for it. Through those fetchers,
you can then schedule various segment requests with a given priority.
To do so, the SegmentQueueCreator creates `SegmentQueue` classes of different types
(example: a video or audio `SegmentQueue`) when you ask for it. Through those
`SegmentQueue`, you can then schedule various a FIFO queue of segment requests each
with a given priority.

The priority of this request is then corroborated with the priority of all requests
currently pending in the SegmentFetcherCreator (and not only with those on the current
segment fetcher) to know when the request should effectively be done - more prioritary
currently pending in the SegmentQueueCreator (and not only with those on the current
`SegmentQueue`) to know when the request should effectively be done - more prioritary
requests will be done first.

During the lifecycle of the request, the segment fetcher will communicate about data and
During the lifecycle of the request, the `SegmentQueue` will communicate about data and
metrics through several means - documented in the code.

### Priorization
Expand All @@ -64,7 +65,7 @@ If the request has no priorization number, the lowest priorization number (the h
priority) will be set on it: `0`

Basically, any new request will have their priorization number compared to the one of the
current request(s) done by the SegmentFetcherCreator:
current request(s) done by the SegmentQueueCreator:

- if no request is already pending, we perform the request immediately

Expand Down
12 changes: 6 additions & 6 deletions src/core/fetchers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import type {
} from "./manifest";
import ManifestFetcher from "./manifest";
import type {
IPrioritizedSegmentFetcher,
ISegmentFetcherCreatorBackoffOptions,
SegmentQueue,
ISegmentQueueCreatorBackoffOptions,
} from "./segment";
import SegmentFetcherCreator from "./segment";
import SegmentQueueCreator from "./segment";

export type {
IManifestFetcherSettings,
IManifestFetcherEvent,
IManifestRefreshSettings,
IPrioritizedSegmentFetcher,
ISegmentFetcherCreatorBackoffOptions,
ISegmentQueueCreatorBackoffOptions,
SegmentQueue,
};
export { ManifestFetcher, SegmentFetcherCreator };
export { ManifestFetcher, SegmentQueueCreator };
11 changes: 6 additions & 5 deletions src/core/fetchers/segment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* limitations under the License.
*/

import type { IPrioritizedSegmentFetcher } from "./prioritized_segment_fetcher";
import type { ISegmentFetcherCreatorBackoffOptions } from "./segment_fetcher_creator";
import SegmentFetcherCreator from "./segment_fetcher_creator";
import type SegmentQueue from "./segment_queue";
import type { ISegmentQueueContext } from "./segment_queue";
import type { ISegmentQueueCreatorBackoffOptions } from "./segment_queue_creator";
import SegmentQueueCreator from "./segment_queue_creator";

export default SegmentFetcherCreator;
export type { IPrioritizedSegmentFetcher, ISegmentFetcherCreatorBackoffOptions };
export default SegmentQueueCreator;
export type { SegmentQueue, ISegmentQueueCreatorBackoffOptions, ISegmentQueueContext };
Loading

0 comments on commit 7657876

Please sign in to comment.