Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Common Media Client Data (CMCD) implementation #1461

Merged
merged 5 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions demo/full/scripts/components/Options/RequestConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import Checkbox from "../CheckBox";
import DEFAULT_VALUES from "../../lib/defaultOptionsValues";
import PlayerOptionNumberInput from "./PlayerOptionNumberInput";
import Select from "../Select";

const { Fragment, useCallback, useEffect, useState } = React;

Expand All @@ -19,19 +20,23 @@ const DEFAULT_MANIFEST_REQUEST_TIMEOUT =
function RequestConfig({
manifestRequestTimeout,
manifestRetry,
cmcdCommunicationMethod,
onManifestRequestTimeoutChange,
onManifestRetryChange,
onSegmentRequestTimeoutChange,
onSegmentRetryChange,
onCmcdChange,
segmentRequestTimeout,
segmentRetry,
}: {
manifestRequestTimeout: number;
manifestRetry: number;
cmcdCommunicationMethod: string;
onManifestRequestTimeoutChange: (val: number) => void;
onManifestRetryChange: (val: number) => void;
onSegmentRequestTimeoutChange: (val: number) => void;
onSegmentRetryChange: (val: number) => void;
onCmcdChange: (val: string) => void;
segmentRequestTimeout: number;
segmentRetry: number;
}): JSX.Element {
Expand Down Expand Up @@ -76,6 +81,27 @@ function RequestConfig({
manifestRequestTimeout !== -1,
);

let cmcdDescMsg;
switch (cmcdCommunicationMethod) {
case "disabled":
cmcdDescMsg = "Not relying on CMCD with the CDN";
break;
case "query":
cmcdDescMsg = "Communicate CMCD payload through URL's query strings";
break;
case "headers":
cmcdDescMsg = "Communicate CMCD payload through HTTP(S) headers";
break;
default:
cmcdDescMsg = "Unknown value";
break;
}

const onCmcdSelection = React.useCallback(
({ value }: { value: string }) => onCmcdChange(value),
[onCmcdChange],
);

// Update manifestRequestTimeout when its linked text change
useEffect(() => {
// Note that this unnecessarily also run on first render - there seem to be
Expand Down Expand Up @@ -275,6 +301,21 @@ function RequestConfig({
: `Stop manifest requests after ${manifestRequestTimeout} millisecond(s)`}
</span>
</li>

<li className="featureWrapperWithSelectMode">
<Select
ariaLabel="Selecting the CMCD communication method"
disabled={false}
className="playerOptionInput"
name="cmcd"
onChange={onCmcdSelection}
selected={{ value: cmcdCommunicationMethod, index: undefined }}
options={["disabled", "query", "headers"]}
>
CMCD (Common Media Client Data) communication type
</Select>
<span className="option-desc">{cmcdDescMsg}</span>
</li>
</Fragment>
);
}
Expand Down
34 changes: 33 additions & 1 deletion demo/full/scripts/controllers/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import type {
IConstructorSettings,
ILoadVideoSettings,
} from "../lib/defaultOptionsValues";
import {
import type {
IAudioRepresentationsSwitchingMode,
ICmcdOptions,
IVideoRepresentationsSwitchingMode,
} from "../../../../src/public_types";

Expand Down Expand Up @@ -61,11 +62,13 @@ function Settings({
} = playerOptions;
const {
autoPlay,
cmcd,
defaultAudioTrackSwitchingMode,
enableFastSwitching,
requestConfig,
onCodecSwitch,
} = loadVideoOptions;
const cmcdCommunicationMethod = cmcd?.communicationType ?? "disabled";
const { manifest: manifestRequestConfig, segment: segmentRequestConfig } =
requestConfig;
const { maxRetry: segmentRetry, timeout: segmentRequestTimeout } = segmentRequestConfig;
Expand All @@ -91,6 +94,33 @@ function Settings({
[updateTryRelyOnWorker],
);

const onCmcdChange = useCallback(
(value: string) => {
updateLoadVideoOptions((prevOptions) => {
let newCmcdType: ICmcdOptions["communicationType"] | undefined;
if (value === "query") {
newCmcdType = "query";
} else if (value === "headers") {
newCmcdType = "headers";
} else {
newCmcdType = undefined;
}
if (newCmcdType === prevOptions.cmcd?.communicationType) {
return prevOptions;
}
return Object.assign({}, prevOptions, {
cmcd:
newCmcdType === undefined
? undefined
: {
communicationType: newCmcdType,
},
});
});
},
[updateLoadVideoOptions],
);

const onVideoResolutionLimitChange = useCallback(
(videoResolutionLimitArg: { value: string }) => {
updatePlayerOptions((prevOptions) => {
Expand Down Expand Up @@ -346,10 +376,12 @@ function Settings({
segmentRetry={segmentRetry}
segmentRequestTimeout={segmentRequestTimeout}
manifestRetry={manifestRetry}
cmcdCommunicationMethod={cmcdCommunicationMethod}
onSegmentRetryChange={onSegmentRetryChange}
onSegmentRequestTimeoutChange={onSegmentRequestTimeoutChange}
onManifestRetryChange={onManifestRetryChange}
onManifestRequestTimeoutChange={onManifestRequestTimeoutChange}
onCmcdChange={onCmcdChange}
/>
</Option>
<Option title="Track Switch Mode">
Expand Down
2 changes: 2 additions & 0 deletions demo/full/scripts/lib/defaultOptionsValues.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
ICmcdOptions,
IConstructorOptions,
ILoadVideoOptions,
} from "../../../../src/public_types";
Expand All @@ -14,6 +15,7 @@ const defaultOptionsValues = {
},
loadVideo: {
autoPlay: true,
cmcd: undefined as ICmcdOptions | undefined,
defaultAudioTrackSwitchingMode: "reload",
enableFastSwitching: true,
requestConfig: {
Expand Down
35 changes: 35 additions & 0 deletions doc/api/Loading_a_Content.md
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,41 @@ If not set or set to `"auto"`, you can see which mode is effective by calling th
If the `useWorker` property is set to `false`, you're running in `"main"` mode, if set to
`true`, you're running in `"multithread"` mode.

### cmcd

_type_: `Object|undefined`

_defaults_: `"undefined"`

<div class="warning">
This option has no effect in <i>DirectFile</i> mode (see <a href="#transport">
transport option</a>)
</div>

When set to an object, it enables "Common Media Client Data" (CMCD) so the RxPlayer is
able to report playback conditions to the CDN.

If set to `undefined` or not defined, CMCD will be disabled.

When set to an Object, it can have the following properties:

- `contentId` (`string|undefined`): Content ID delivered by CMCD metadata for that
content. If not specified, a default one will be generated.

It is heavily recommended that you provide your own content identifier here.

- `sessionId` (`string|undefined`): Session ID delivered by CMCD metadata. If not
specified, a default one will be generated.

- `communicationType` (`string|undefined`): Way in which the CMCD metadata is
Florent-Bouisset marked this conversation as resolved.
Show resolved Hide resolved
communicated.

Can be set to `"query"` for communicating it through query strings or `"headers"` for
communicating it through headers (which may lead to supplementary complexities linked to
CORS policies such as preflight request, blocking etc.).

If not set, the RxPlayer will automatically select the most appropriate way instead.
Florent-Bouisset marked this conversation as resolved.
Show resolved Hide resolved

### checkMediaSegmentIntegrity

_type_: `Function|undefined`
Expand Down
36 changes: 36 additions & 0 deletions doc/api/Miscellaneous/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ As you can see, this function takes two arguments:
- _trackType_ (`string`): The concerned type of track. Can be `"video"`, `"audio"`,
`"text"` (for subtitles)

- _cmcdPayload_ (`Object|undefined`): Optional object that describes the "Common Media
Client Data" (CMCD) that may be provided alongside the resource for this request.

When set, takes the form of an object with two fields: `type` (a `string`) and value,
whose format will depend on the value of `type`.

When `type` is set to `"query"`, then `value` represents a CMCD payload formatted to
be inserted in a query string. It is in this case an array of 2-tuples with the first
value being a field's name as a string and the second element being either that
field's value if set to a string or indicating that the field has no value. For
example a `value` set to
`[["first", "val"], ["second", null], ["third", "something"]]` could be translated
into the query string `?first=val&second&third=something`.

When `type` is set to `"headers"`, then `value` represents a CMCD payload formatted
to be inserted as headers. It is in this case an object where keys are header names
and values are the corresponding header values.

2. **callbacks**: An object containing multiple callbacks to allow this `segmentLoader` to
communicate various events to the RxPlayer.

Expand Down Expand Up @@ -288,6 +306,24 @@ As you can see, this function takes three arguments:
This property is mainly indicative, you may or may not want to exploit this
information depending on your use cases.

- _cmcdPayload_ (`Object|undefined`): Optional object that describes the "Common Media
Client Data" (CMCD) that may be provided alongside the resource for this request.

When set, takes the form of an object with two fields: `type` (a `string`) and value,
whose format will depend on the value of `type`.

When `type` is set to `"query"`, then `value` represents a CMCD payload formatted to
be inserted in a query string. It is in this case an array of 2-tuples with the first
value being a field's name as a string and the second element being either that
field's value if set to a string or indicating that the field has no value. For
example a `value` set to
`[["first", "val"], ["second", null], ["third", "something"]]` could be translated
into the query string `?first=val&second&third=something`.

When `type` is set to `"headers"`, then `value` represents a CMCD payload formatted
to be inserted as headers. It is in this case an object where keys are header names
and values are the corresponding header values.

2. **callbacks**: An object containing multiple callbacks to allow this `manifestLoader`
to communicate the loaded Manifest or an encountered error to the RxPlayer.

Expand Down
43 changes: 23 additions & 20 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ it:
| |
+---------------------------------------------+
|
| call RxPlayer API
| call the RxPlayer API
|
-------------------------|- RxPlayer Main Thread ---------------------------
|
Expand All @@ -52,29 +52,32 @@ it:
|(./main_thread/init)| creates | Text Displayer |
| | --------------------------->|(./main_thread/te |
+--------------------+ |xt_displayer) |
| ^ +------------------+
| | Message exchanges ^
| | |
--------|--|------ RxPlayer Core (May run in a WebWorker) --------------|---
v | |
| ^ +------------------+
| | Message exchanges ^
| | |
---|--|----------- RxPlayer Core (May run in a WebWorker) ---------|---
| | |
| | (*Only if running in a WebWorker)
| | Exchange messages with the main
V | thread and process them.
+---------------------------+ +----------------------------+ |
| | creates | | |
| Worker Main* |-------->| Manifest Fetcher | |
| (./core/main/worker) | | (./core/fetchers/manifest) | |
| | | | |
+---------------------------+ +----------------------------+ |
(*Only if running in a | Load and | |
WebWorker) | refresh the | Ask to load |
Exchange messages with | Manifest | and parse the |
the main thread and | | Manifest |
process them. | v |
| +--------------------+ | ` Internet
| | | request | ` ,,,,,
| | transport |--------------+---`-->( CDN )
creates | | (./core/transport) | | ` `````
| | |<---+ | `
| +--------------------+ \ |
| Abstract the streaming \ |
| Creates | Load and | |
V | refresh the | Ask to load |
+-------------------+ | Manifest | and parse the |
| | | creates | Manifest |
| CMCD data builder | | v |
| (./core/cmcd) | | +--------------------+ | ` Internet
| | | | | request | ` ,,,,,
+-------------------+ | | transport |--------------+---`-->( CDN )
Perform data collection | | (./transport) | | ` `````
for the "Common Media | | |<---+ | `
Client Data" (CMCD) | +--------------------+ \ |
scheme. | Abstract the streaming \ |
| protocol (e.g. DASH) \ |
| \ |
Stream (./core/stream) | \ |
Expand Down Expand Up @@ -248,10 +251,10 @@ The previous schema mostly illustrated the most complex code path of the three (
`DirectfileContentInitializer` is called by the API to start-up such contents and a
specialized `MediaElementTracksStore` is handling tracks specifically for directfile
contents (as they are handled differently than for other code paths, here trough API
exposed by the browser)have .
exposed by the browser).

2. A second code path, we may call the "monothreaded code path" apply for non-directfile
contents (so, contents which rely on MSE API instead) loaded in monothreaded mode,
contents (so, contents which rely on the MSE API instead) loaded in monothreaded mode,
which is the default.

It is much closer to the schema of the previous chapter:
Expand Down
5 changes: 5 additions & 0 deletions src/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ Those modules are:
Link the `transports` module with the rest of the code, to download segments,
download/refresh the manifest and collect data (such as the user's bandwidth) for the
other modules.

- **the `CmcdDataBuilder` (./cmcd)**

Perform data collection and retrieval for the "Common Media Client Data" scheme, which
is a specification allowing to communicate about playback conditions with a CDN.
Loading
Loading