Skip to content

Commit

Permalink
[WIP] CMCD as HTTP headers (#3554)
Browse files Browse the repository at this point in the history
* Implemented cmcd headers

* Added parameter to settings to specify cmcd mode

* Minor tweaks, updated docs

* Removed mixed mode

* Add CMCD mode selection to reference client

Co-authored-by: dsilhavy <[email protected]>
  • Loading branch information
FritzHeiden and dsilhavy authored Mar 30, 2021
1 parent a41cf42 commit 7567702
Show file tree
Hide file tree
Showing 14 changed files with 497 additions and 15 deletions.
3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ declare namespace dashjs {
sid?: string,
cid?: string,
rtp?: number,
rtpSafetyFactor?: number
rtpSafetyFactor?: number,
mode?: 'query' | 'header'
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions samples/advanced/cmcd.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

<script class="code">
var CMCD_DATA_GENERATED = dashjs.MetricsReporting.events.CMCD_DATA_GENERATED;

/* possible modes of attach cmcd data */
var CMCD_MODE_QUERY = "query"; /* as query parameters */
var CMCD_MODE_HEADER = "header"; /* as HTTP headers */

function init() {
var video,
player,
Expand All @@ -31,6 +36,7 @@
enabled: true, /* enable reporting of cmcd parameters */
sid: 'b248658d-1d1a-4039-91d0-8c08ba597da5', /* session id send with each request */
cid: '21cf726cfe3d937b5f974f72bb5bd06a', /* content id send with each request */
mode: CMCD_MODE_QUERY,
}
}
});
Expand Down
16 changes: 16 additions & 0 deletions samples/dash-if-reference-player/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,22 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
}
};

$scope.setCmcdMode = function () {
var mode = $("input[name='cmcd-mode']:checked").val();
switch (mode) {
case 'query':
$scope.player.updateSettings({ streaming: { cmcd: { mode: 'query' }}});
break;

case 'header':
$scope.player.updateSettings({ streaming: { cmcd: { mode: 'header' }}});
break;

default:
$scope.player.updateSettings({ streaming: { cmcd: { mode: 'query' }}});
}
};

$scope.hasLogo = function (item) {
return (item.hasOwnProperty('logo') && item.logo);
};
Expand Down
13 changes: 13 additions & 0 deletions samples/dash-if-reference-player/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,19 @@
title="This value is used as a factor for the rtp value calculation: rtp = minBandwidth * rtpSafetyFactor. If not specified this value defaults to 5. Note that this value is only used when no static rtp value is defined.">RTP
safety factor:</label>
<input type="text" class="form-control" placeholder="Default 5" ng-model="cmcdRtpSafetyFactor">
<label class="options-label" title="Specifies the CMCD data transition mode">Transition Mode:</label>
<label data-toggle="tooltip" data-placement="right"
title="Send the CMCD metrics via query parameter">
<input type="radio" id="cmcd-query" value="query" checked="checked" autocomplete="off" name="cmcd-mode"
ng-click="setCmcdMode()">
Query
</label>
<label data-toggle="tooltip" data-placement="right"
title="Send the CMCD metrics via custom HTTP header">
<input type="radio" id="cmcd-header" value="header" autocomplete="off" name="cmcd-mode"
ng-click="setCmcdMode()">
Header
</label>
</div>
</div>

Expand Down
10 changes: 8 additions & 2 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* sid: null,
* cid: null,
* rtp: null,
* rtpSafetyFactor: 5
* rtpSafetyFactor: 5,
* mode: Constants.CMCD_MODE_QUERY
* }
* }
* }
Expand Down Expand Up @@ -500,6 +501,10 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* This value is used as a factor for the rtp value calculation: rtp = minBandwidth * rtpSafetyFactor
*
* If not specified this value defaults to 5. Note that this value is only used when no static rtp value is defined.
* @property {number} [mode]
* The method to use to attach cmcd metrics to the requests. 'query' to use query parameters, 'header' to use http headers.
*
* If not specified this value defaults to 'query'.
*/

/**
Expand Down Expand Up @@ -712,7 +717,8 @@ function Settings() {
sid: null,
cid: null,
rtp: null,
rtpSafetyFactor: 5
rtpSafetyFactor: 5,
mode: Constants.CMCD_MODE_QUERY
}
}
};
Expand Down
3 changes: 2 additions & 1 deletion src/streaming/MediaPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,8 @@ function MediaPlayer() {
events: Events,
BASE64: BASE64,
constants: Constants,
cmcdModel: cmcdModel
cmcdModel: cmcdModel,
settings: settings
});
if (protectionController) {
protectionController.setLicenseRequestFilters(licenseRequestFilters);
Expand Down
15 changes: 15 additions & 0 deletions src/streaming/constants/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,21 @@ class Constants {
*/
this.TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange';

/**
* @constant {string} CMCD_MODE_QUERY specifies to attach CMCD metrics as query parameters.
* @memberof Constants#
* @static
*/
this.CMCD_MODE_QUERY = 'query';

/**
* @constant {string} CMCD_MODE_HEADER specifies to attach CMCD metrics as HTTP headers.
* @memberof Constants#
* @static
*/
this.CMCD_MODE_HEADER = 'header';


this.LOCATION = 'Location';
this.INITIALIZE = 'initialize';
this.TEXT_SHOWING = 'showing';
Expand Down
40 changes: 40 additions & 0 deletions src/streaming/models/CmcdModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,45 @@ function CmcdModel() {
}
}

function _copyParameters(data, parameterNames) {
const copiedData = {};
for (let name of parameterNames) {
if (data[name]) {
copiedData[name] = data[name];
}
}
return copiedData;
}

function getHeaderParameters(request) {
try {
if (settings.get().streaming.cmcd && settings.get().streaming.cmcd.enabled) {
const cmcdData = _getCmcdData(request);
const cmcdObjectHeader = _copyParameters(cmcdData, ['br', 'd', 'ot', 'tb']);
const cmcdRequestHeader = _copyParameters(cmcdData, ['bl', 'dl', 'mtp', 'nor', 'nrr', 'su']);
const cmcdStatusHeader = _copyParameters(cmcdData, ['bs', 'rtp']);
const cmcdSessionHeader = _copyParameters(cmcdData, ['cid', 'pr', 'sf', 'sid', 'st', 'v']);
const headers = {
'CMCD-Object': _buildFinalString(cmcdObjectHeader),
'CMCD-Request': _buildFinalString(cmcdRequestHeader),
'CMCD-Status': _buildFinalString(cmcdStatusHeader),
'CMCD-Session': _buildFinalString(cmcdSessionHeader)
};

eventBus.trigger(MetricsReportingEvents.CMCD_DATA_GENERATED, {
url: request.url,
mediaType: request.mediaType,
cmcdData
});
return headers;
}

return null;
} catch (e) {
return null;
}
}

function _getCmcdData(request) {
try {
let cmcdData = null;
Expand Down Expand Up @@ -537,6 +576,7 @@ function CmcdModel() {

instance = {
getQueryParameter,
getHeaderParameters,
setConfig,
reset,
initialize
Expand Down
9 changes: 9 additions & 0 deletions src/streaming/net/FetchLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ function FetchLoader(cfg) {
headers.append('Range', 'bytes=' + request.range);
}

if (httpRequest.headers) {
for (let header in httpRequest.headers) {
let value = httpRequest.headers[header];
if (value) {
headers.append(header, value);
}
}
}

if (!request.requestStartDate) {
request.requestStartDate = requestStartTime;
}
Expand Down
17 changes: 14 additions & 3 deletions src/streaming/net/HTTPLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import Debug from '../../core/Debug';
import EventBus from '../../core/EventBus';
import Events from '../../core/events/Events';
import Settings from '../../core/Settings';
import Constants from '../constants/Constants';

/**
* @module HTTPLoader
Expand Down Expand Up @@ -254,9 +255,18 @@ function HTTPLoader(cfg) {
});
}

let headers = null;
let modifiedUrl = requestModifier.modifyRequestURL(request.url);
const additionalQueryParameter = _getAdditionalQueryParameter(request);
modifiedUrl = Utils.addAditionalQueryParameterToUrl(modifiedUrl, additionalQueryParameter);
if (settings.get().streaming.cmcd && settings.get().streaming.cmcd.enabled) {
const cmcdMode = settings.get().streaming.cmcd.mode;
if (cmcdMode === Constants.CMCD_MODE_QUERY) {
const additionalQueryParameter = _getAdditionalQueryParameter(request);
modifiedUrl = Utils.addAditionalQueryParameterToUrl(modifiedUrl, additionalQueryParameter);
}
else if (cmcdMode === Constants.CMCD_MODE_HEADER) {
headers = cmcdModel.getHeaderParameters(request);
}
}
const verb = request.checkExistenceOnly ? HTTPRequest.HEAD : HTTPRequest.GET;
const withCredentials = mediaPlayerModel.getXHRWithCredentialsForType(request.type);

Expand All @@ -273,7 +283,8 @@ function HTTPLoader(cfg) {
onabort: onabort,
ontimeout: ontimeout,
loader: loader,
timeout: requestTimeout
timeout: requestTimeout,
headers: headers
};

// Adds the ability to delay single fragment loading time to control buffer.
Expand Down
9 changes: 9 additions & 0 deletions src/streaming/net/XHRLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ function XHRLoader(cfg) {
xhr = requestModifier.modifyRequestHeader(xhr);
}

if (httpRequest.headers) {
for (let header in httpRequest.headers) {
let value = httpRequest.headers[header];
if (value) {
xhr.setRequestHeader(header, value);
}
}
}

xhr.withCredentials = httpRequest.withCredentials;

xhr.onload = httpRequest.onload;
Expand Down
3 changes: 2 additions & 1 deletion src/streaming/protection/Protection.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ function Protection() {
events: config.events,
BASE64: config.BASE64,
constants: config.constants,
cmcdModel: config.cmcdModel
cmcdModel: config.cmcdModel,
settings: config.settings
});
config.capabilities.setEncryptedMediaSupported(true);
}
Expand Down
38 changes: 32 additions & 6 deletions src/streaming/protection/controllers/ProtectionController.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import LicenseRequest from '../vo/LicenseRequest';
import LicenseResponse from '../vo/LicenseResponse';
import { HTTPRequest } from '../../vo/metrics/HTTPRequest';
import Utils from '../../../core/Utils';
import Constants from '../../constants/Constants';

const NEEDKEY_BEFORE_INITIALIZE_RETRIES = 5;
const NEEDKEY_BEFORE_INITIALIZE_TIMEOUT = 500;
Expand Down Expand Up @@ -72,6 +73,7 @@ function ProtectionController(config) {
const constants = config.constants;
let needkeyRetries = [];
const cmcdModel = config.cmcdModel;
const settings = config.settings;

let instance,
logger,
Expand Down Expand Up @@ -789,13 +791,18 @@ function ProtectionController(config) {
function doLicenseRequest(request, retriesCount, timeout, onLoad, onAbort, onError) {
const xhr = new XMLHttpRequest();

const cmcdParams = cmcdModel.getQueryParameter({
url: request.url,
type: HTTPRequest.LICENSE
});
if (settings.get().streaming.cmcd && settings.get().streaming.cmcd.enabled) {
const cmcdMode = settings.get().streaming.cmcd.mode;
if (cmcdMode === Constants.CMCD_MODE_QUERY) {
const cmcdParams = cmcdModel.getQueryParameter({
url: request.url,
type: HTTPRequest.LICENSE
});

if (cmcdParams) {
request.url = Utils.addAditionalQueryParameterToUrl(request.url, [cmcdParams]);
if (cmcdParams) {
request.url = Utils.addAditionalQueryParameterToUrl(request.url, [cmcdParams]);
}
}
}

xhr.open(request.method, request.url, true);
Expand All @@ -808,6 +815,25 @@ function ProtectionController(config) {
xhr.setRequestHeader(key, request.headers[key]);
}

if (settings.get().streaming.cmcd && settings.get().streaming.cmcd.enabled) {
const cmcdMode = settings.get().streaming.cmcd.mode;
if (cmcdMode === Constants.CMCD_MODE_HEADER) {
const cmcdHeaders = cmcdModel.getHeaderParameters({
url: request.url,
type: HTTPRequest.LICENSE
});

if (cmcdHeaders) {
for (const header in cmcdHeaders) {
let value = cmcdHeaders[header];
if (value) {
xhr.setRequestHeader(header, value);
}
}
}
}
}

const retryRequest = function () {
// fail silently and retry
retriesCount--;
Expand Down
Loading

0 comments on commit 7567702

Please sign in to comment.