cta-wave / common-media-client-data

A repository to collect discussion and feedback on the Common Media Client Data proposal.
30 stars 0 forks source link

Request for Comments: CMCD v2 Javascript API for dash.js #138

Open nicolaslevy opened 2 months ago

nicolaslevy commented 2 months ago

Currently, at Qualabs, we are implementing some functionalities of CMCD v2 in order to provide implementation feedback to the group that is developing the CMCD v2 specification.

In this issue, the goal is to gather comments, recommendations, and viewpoints to help define a JavaScript API that encompasses both CMCD v1 and CMCD v2.

As a reminder, below is the JavaScript API for the CMCD v1 implementation of dash.js (and most players).

cmcd: {
    enabled: true, /* enable or disable */
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5", /* session id send with each request */
    cid: "21cf726cfe3d937b5f974f72bb5bd06a", /* content id send with each request */
    mode: CMCD_MODE_QUERY,  /* Query or Headers */
    enabledKeys: ["br",  "sf", "sid", "st", "v"], /*Keys to include in the CMCD report*/
}

This JavaScript API proposal for CMCD v2 in dash.js aims to be as backward compatible as possible with the API for version 1, where it's only necessary to change the version field and add the minimum amount of configuration applicable to each report mode. On the other hand, the "request-mode" is the default mode enabled, and the other two new modes can be added through configuration.

cmcd: {
    enabled: true, /* global enable or disable */
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5", /* session id send with each request */
    cid: "21cf726cfe3d937b5f974f72bb5bd06a", /* content id send with each request */
    mode: CMCD_MODE_QUERY,  /* gobal mode if not specified in each mode */
    enabledKeys: ["br",  "sf", "sid", "st", "v", ], /* optional, gobal keys if not specified in each mode. Note that any mandatory keys for each mode will be automatically added and do not need to be provisioned */
    reporting: {
        requestMode: {
            version: 1 /* version 1 by default for backward compatibility */
            enabled: true, /*by default is always true for this mode for backward compatibility*/
            mode: CMCD_MODE_QUERY /*overrides mode in upper level*/
            enabledKeys: ["br",  "sf", "sid", "st", "v"], /*optional, overrides global keys. Note that any mandatory keys for each mode will be automatically added and do not need to be provisioned */
        },
        responseMode: {
            enabled: false, /*by default is always FALSE for this mode*/
            mode: CMCD_MODE_HEADER /*optional, overrides mode in upper level*/
            requestMethod: "GET", /*optional, GET by defautl*/
            reportingUrl: "http://<url>/endpoint" /*mandatory, URL to send report*/
            enabledKeys: ["br",  "sf", "sid", "st", "v"], /*optional, overrides global keys. Note that any mandatory keys for each mode will be automatically added and do not need to be provisioned*/
        },
        stateIntervalMode: {
            enabled: false, /*by default is always FALSE for this mode*/
            mode: CMCD_MODE_JSON /*optional, overrides mode in upper level*/
            requestMethod: "POST", /*optional, POST by defautl*/
            interval: 30, /*optional, default is 30 seconds*/ 
            reportingUrl: "http://<url>/endpoint" /* mandatory, URL to send report*/
            enabledKeys: ["br",  "sf", "sid", "st", "v"], /*optional, overrides global keys. Note that any mandatory keys for each mode will be automatically added and do not need to be provisioned*/
        },
    }
}

Examples using this proposal:

CMCD v1 configuration (backward compatibility):

cmcd: {
    enabled: true,
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5",
    cid: "21cf726cfe3d937b5f974f72bb5bd06a", 
    mode: CMCD_MODE_QUERY,  
    enabledKeys: ["br",  "sf", "sid", "st", "v"]
}

Only request mode with CMCD v2:

cmcd: {
    enabled: true,
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5",
    cid: "21cf726cfe3d937b5f974f72bb5bd06a",
    mode: CMCD_MODE_QUERY, 
    enabledKeys: ["br",  "sf", "sid", "st", "v"], 
    reporting: {
        requestMode: {
            version: 2 
        },
    }
}

Only response-mode:

cmcd: {
    enabled: true,
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5",
    cid: "21cf726cfe3d937b5f974f72bb5bd06a",
    mode: CMCD_MODE_QUERY, 
    enabledKeys: ["br",  "sf", "sid", "st", "v"],
    reporting: {
        requestMode: {
            enabled: false,
        },
        responseMode: {
            enabled: true, 
            reportingUrl: "http://some.com/endpoint"
        },
    }
}

In particular, it was mentioned during the 8/22 meeting that it might be confusing to have both a global list of keys (enabledKeys) and a separate one in each reporting mode that can override the global one, especially considering that not all keys defined in CMCD v2 can be sent in all modes. For example, the ttfb (Time To First Byte) key only makes sense in the Response Mode.

It was also mentioned that the word "mode" might be confusing when used to refer to both the new modes (request, response, state-interval) and the place and format of data transmission (query, headers, JSON).

dsilhavy commented 2 months ago

Thanks, some comments based on your description:

slhck commented 2 months ago

I have some comments more from an outside perspective (we parse CMCD and sometimes consult in adding support for it for various players):

Mode Naming

If you are going to change the type definitions of the configuration object anyway, you might as well change the mode key to dataTransmissionMode or transmissionMode to distinguish it from the reporting. The mode key could be aliased to dataTransmissionMode and become deprecated for some time before being removed evenutally.

My thinking is that if developers update dependencies and choose to use CMCDv2, they might as well change the configuration because you're going to touch the system anyway.

Version

You might add a global version key to the configuration object so that it's clear which version is targeted with the particular set of options, allowing for easier type definitions and more obvious transition to newer versions, should there be any:

// version 1
cmcd: {
    enabled: true,
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5",
    cid: "21cf726cfe3d937b5f974f72bb5bd06a", 
    mode: CMCD_MODE_QUERY,  
    enabledKeys: ["br",  "sf", "sid", "st", "v"]
}

Only request mode with CMCD v2:

cmcd: {
    version: 2, // --> enables proper parsing of options with V2 semantics
    enabled: true,
    sid: "b248658d-1d1a-4039-91d0-8c08ba597da5",
    cid: "21cf726cfe3d937b5f974f72bb5bd06a",
    mode: CMCD_MODE_QUERY, 
    enabledKeys: ["br",  "sf", "sid", "st", "v"], 
    reporting: {
        requestMode: {
            // version: 2 --> no longer needed
        },
    }
}

Enabled Keys:

Is there a use case where one wants to enable more keys globally but exclude them for particular modes? In that case, having an ignoredKeys property could be added, so you don't have to completely override the enabled keys for a particular reporting mode (and thereby specify some keys twice), thus the final set of keys would be enabledKeys - ignoredKeys - irrelevant keys for that mode.

littlespex commented 1 month ago

With the introduction of the two new "external URL" modes, in theory you could send CMCD v2 data to multiple external targets, for the same reporting mode. Do we foresee anyone needing/wanting to do that? Would there be any other benefit from expressing the external configs as a list of targets instead of a singular mode mapping?:

const config = {
  cmcd: {
    sid: 'b248658d-1d1a-4039-91d0-8c08ba597da5',
    cid: '21cf726cfe3d937b5f974f72bb5bd06a',
    targets: [
      {
        reportingMode: 'state-interval',
        dataTransmissionMode: 'json',
        method: 'POST',
        interval: 30,
        url: 'http://<url>/endpoint',
        enabledKeys: ['br', 'sf', 'sid', 'st'],
      }, {
        reportingMode: 'response',
        dataTransmissionMode: 'header',
        method: 'POST',
        url: 'http://<url>/endpoint',
        enabledKeys: ['su', 'bs'],
      }, {
        reportingMode: 'response',
        dataTransmissionMode: 'query',
        method: 'GET',
        url: 'http://<url>/endpoint',
        enabledKeys: ['bl', 'tbl'],
      },
    ],
  },
}
nicolaslevy commented 1 month ago

@littlespex I realy like the idea of multiple targets for the same mode.

Regarding the verrsion @slhck , I think it should be inside each "target" description as @littlespex suggested to (1) enable backwards compatibility for those who needs to send CMCD v1 in Request mode and what to send CMCD v2 using other modes, and (2) be future proof for CMCD v3,4,5... with this we will be able to send multiple endpoints with different CMCD versions.

Now... We sould solve that there is only one request mode to be enabled.... but... whjat happens if CDN A only supports CMCD v2 and CDN B supports CMCD v2? we cloud also consider to add some kind of mapping CDN <-> CMCD configuration

@dsilhavy Agree, we can add the IncludeInRequests for mode response and request.

const config = {
  cmcd: {
    sid: 'b248658d-1d1a-4039-91d0-8c08ba597da5',
    cid: '21cf726cfe3d937b5f974f72bb5bd06a',
    targets: [
      {
        reportingMode: 'state-interval',
        version: 2,
        dataTransmissionMode: 'json',
        method: 'POST',
        interval: 30,
        url: 'http://<url>/endpoint',
        enabledKeys: ['br', 'sf', 'sid', 'st'],
      }, {
        reportingMode: 'response',
        version: 2,
        dataTransmissionMode: 'header',
        IncludeInRequests: 'segments',
        method: 'POST',
        url: 'http://<url>/endpoint',
        enabledKeys: ['su', 'bs'],
      }, {
        reportingMode: 'response',
        version: 2
        dataTransmissionMode: 'query',
        method: 'GET',
        IncludeInRequests: 'segments',
        url: 'http://<url>/endpoint',
        enabledKeys: ['bl', 'tbl'],
      }, {
        reportingMode: 'request',
        dataTransmissionMode: 'query',
        method: 'GET',
        IncludeInRequests: 'segments mpd',
        version: 1,
        cdn: 'CDN-A'.
        enabledKeys: ['bl', 'tbl'],
      }, {
        reportingMode: 'request',
        dataTransmissionMode: 'query',
        method: 'GET',
        IncludeInRequests: 'segments mpd',
        version: 2,
        cdn: 'CDN-B'.
        enabledKeys: ['bl', 'tbl'],
      },
    ],
  },
}

I like that this is very powerful, you can get a lot of flexibility, but it's too complex... I don't expect all players to have this behavior but it could be a reference or suggestion to get the most from CMCD :)

littlespex commented 1 month ago

To keep things simple my vote would be to:

https://gist.github.com/littlespex/ae1d44e346e9fea5a68a8ba114541e06