Skip to content

Commit

Permalink
Feature/cmcd settings from mpd and steering report (#4426)
Browse files Browse the repository at this point in the history
* parsing ClientDataResporting from MDP

* add applyCMCDParameters

* Using the CMCDParameters configuration under ClientDataReporting in the MDP file

* Check if cmcd is enabled by checking mdp and player settings. Using mdp over the player settings but when applyCMCDParameters is false, player settings will be used

* apply serviceLocation filter to data reporting

* Send cmcd data to content steering server

* add adapter set filter

* improve apply filters

* improve apply filters

* delete unnecessary atribute in client data reporting

* add client data reporting model

* refactor client data reporting model

* implemented include in request filter

* add none include request case

* change segment type into filter

* Add test to check if cmcd data from manifest is correct

* delete comments

* Update tests with latest changes for cmcd reporting data

* add test for getQueryParameter

* delete comment in streaming.models.CmcdModel.js

* add test to get correctly cmcd data from getHeadersParameters()

* Adding tests for ClientDataReportingModel

* add test to get correctly cmcd data from getHeadersParameters()

* add funcionality to service description controller mock

* reset serviceDescriptionControllerMock after tests run

* More tests added for ClientDataReportingModel

* Add tests for applyCMCDParameters setting

* Add includeInRequests attribute to player settings

* Send latest video cmcd to content steering server

* fix edge case

* - add logger
- add edge cases to defined if cmcd should be enable or not
- improve whitelist functions based on new changes

* improve edge cases checks

* fix a detail

* fix parsing

* fix parsing keys

* improve error messages

* add support for audio only files

* remove unnecessary spaces

* improve lastMediaTypeRequest logic

* remove unnecessary spaces

* improve _lastMediaTypeRequest behaviour

* Fix tests after merging development into feature/cmcd-settings-from-mpd-and-steering-report

* Added new test cases for ClientDataReportingModel.js

* Fix isIncludedFilters

* Check if element parsed for ContentSteering from mpd is an array or an object

* Update AUTHORS.md

* Update AUTHORS.md

* Refactors from PR review: change applyCMCDParameters name to applyParametersFromMpd, fix typos, change variable names and create a vo model for CMCDParameters

* Fix import

* Move ClientDataReportingModel to controllers folder and change the name to ClientDataReportingController

* Update _canBeEnabled function and create a dedicated private function in HTTPLoader for updating url and headers according to CMCD

* Update includeInRequest default value to segment and update the tests

* Implement schemeIdUri for CMCDParameters using urn:mpeg:dash:cta-5004:2023 scheme

* Remove console.log

* Add sample page for CMCD triggered via the MPD

---------

Co-authored-by: santiagomintegui <105082491+santiagomintegui@users.noreply.github.com>
Co-authored-by: santi <santiagomintegui@gmail.com>
Co-authored-by: Nicolás Caballero <nicolasc@qualabs.com>
Co-authored-by: Nicolás Caballero <nicolascaballero.v@gmail.com>
Co-authored-by: Matias Rodriguez <matias@192.168.1.12>
Co-authored-by: matias@qualabs.com <matias@Matiass-MacBook-Pro.local>
  • Loading branch information
7 people committed Apr 29, 2024
1 parent 0e82824 commit 5117500
Show file tree
Hide file tree
Showing 22 changed files with 2,076 additions and 60 deletions.
3 changes: 3 additions & 0 deletions AUTHORS.md
Expand Up @@ -49,3 +49,6 @@
* @adripanico [Adrian Caballero, Epic Labs]
* @ahfarmer [Andrew Farmer, Rhombus Systems]
* @matvp91 [Matthias Van Parijs]
* @matiasrb97 [Matías Rodriguez, Qualabs]
* @santimintegui [Santiago Mintegui, Qualabs]
* @N1Knight [Nicolás Caballero, Qualabs]
4 changes: 3 additions & 1 deletion index.d.ts
Expand Up @@ -1258,13 +1258,15 @@ declare namespace dashjs {
}
},
cmcd?: {
applyParametersFromMpd?:boolean,
enabled?: boolean,
sid?: string | null,
cid?: string | null,
rtp?: number | null,
rtpSafetyFactor?: number,
mode?: 'query' | 'header',
enabledKeys?: Array<string>
enabledKeys?: Array<string>,
includeInRequests?: Array<string>
},
cmsd?: {
enabled?: boolean,
Expand Down
540 changes: 540 additions & 0 deletions samples/advanced/cmcd-from-manifest.html

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions samples/advanced/mpds/basic-cmcd-config.mpd
@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:mas="urn:marlin:mas:1-0:services:schemas:mpd" xmlns:mspr="urn:microsoft:playready" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" type="static" mediaPresentationDuration="PT10M34.600S" minBufferTime="PT1.980S">
<BaseURL serviceLocation="cdn-a">https://cloudfront.content-steering.com/bbb/</BaseURL>
<BaseURL serviceLocation="cdn-b">https://fastly.content-steering.com/bbb/</BaseURL>
<BaseURL serviceLocation="cdn-c">https://akamai.content-steering.com/bbb/</BaseURL>
<ServiceDescription>
<ContentSteering defaultServiceLocation="cdn-a" queryBeforeStart="true">https://cloudfront.content-steering.com/dash.dcsm?steering_params=eyJjZG5PcmRlciI6WyJjZG4tYSIsImNkbi1iIiwiY2RuLWMiXSwibWluQml0cmF0ZSI6OTE0ODc4LCJwYXRod2F5cyI6W3siaWQiOiJjZG4tYSIsInRocm91Z2hwdXQiOjIwMDAwMDAwfSx7ImlkIjoiY2RuLWIiLCJ0aHJvdWdocHV0IjoyMDAwMDAwMH0seyJpZCI6ImNkbi1jIiwidGhyb3VnaHB1dCI6MjAwMDAwMDB9XX0=</ContentSteering>
<ClientDataReporting>
<CMCDParameters version="1" keys="br sid cid" contentID="content-id-1" sessionID="session-id-1" includeInRequests='segment steering' schemeIdUri="urn:mpeg:dash:cta-5004:2023"/>
</ClientDataReporting>
</ServiceDescription>
<Period>
<AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1" lang="und" group="0">
<SegmentTemplate duration="1984" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4f" startNumber="1" timescale="1000"/>
<Representation audioSamplingRate="48000" bandwidth="131556" codecs="mp4a.40.2" id="audio_128kbps">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
</Representation>
</AdaptationSet>
<AdaptationSet mimeType="video/mp4" scanType="progressive" segmentAlignment="true" startWithSAP="1" group="0">
<SegmentTemplate duration="2000" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4f" startNumber="1" timescale="1000"/>
<Representation bandwidth="4530860" codecs="avc1.640028" frameRate="30" height="1080" id="video_1920x1080_4531kbps" scanType="progressive" width="1920"/>
<Representation bandwidth="2445034" codecs="avc1.4D401F" frameRate="30" height="720" id="video_1280x720_2445kbps" scanType="progressive" width="1280"/>
<Representation bandwidth="1419255" codecs="avc1.4D401F" frameRate="30" height="576" id="video_1024x576_1419kbps" scanType="progressive" width="1024"/>
<Representation bandwidth="783322" codecs="avc1.4D401E" frameRate="30" height="360" id="video_640x360_783kbps" scanType="progressive" width="640"/>
</AdaptationSet>
</Period>
</MPD>
11 changes: 11 additions & 0 deletions samples/samples.json
Expand Up @@ -697,6 +697,17 @@
"Audio"
]
},
{
"title": "CMCD Reporting from manifest",
"description": "This sample shows how to use dash.js in order to enhance requests to the CDN with Common Media Client Data (CMCD - CTA 5005). Configuring it from manifest file.",
"href": "advanced/cmcd-from-manifest.html",
"image": "lib/img/bbb-1.jpg",
"labels": [
"VoD",
"Video",
"Audio"
]
},
{
"title": "Custom Capabilities Filters",
"description": "This sample shows how to filter representations.",
Expand Down
10 changes: 9 additions & 1 deletion src/core/Settings.js
Expand Up @@ -851,6 +851,10 @@ import Events from './events/Events.js';
* If not specified this value defaults to 'query'.
* @property {Array.<string>} [enabledKeys]
* This value is used to specify the desired CMCD parameters. Parameters not included in this list are not reported.
* @property {Array.<string>} [includeInRequests]
* Specifies which HTTP GET requests shall carry parameters.
*
* If not specified this value defaults to ['segment'].
*/

/**
Expand Down Expand Up @@ -895,6 +899,8 @@ import Events from './events/Events.js';
* Set to true if dash.js should use the parameters defined in ProducerReferenceTime elements in combination with ServiceDescription elements.
* @property {boolean} [applyContentSteering=true]
* Set to true if dash.js should apply content steering during playback.
* @property {boolean} [applyParametersFromMpd=true]
* Set to true if dash.js should use the cmcd parameters defined in MDP or js elements.
* @property {number} [eventControllerRefreshDelay=100]
* For multi-period streams, overwrite the manifest mediaPresentationDuration attribute with the sum of period durations if the manifest mediaPresentationDuration is greater than the sum of period durations
* @property {boolean} [enableManifestDurationMismatchFix=true]
Expand Down Expand Up @@ -1272,13 +1278,15 @@ function Settings() {
}
},
cmcd: {
applyParametersFromMpd: true,
enabled: false,
sid: null,
cid: null,
rtp: null,
rtpSafetyFactor: 5,
mode: Constants.CMCD_MODE_QUERY,
enabledKeys: ['br', 'd', 'ot', 'tb', 'bl', 'dl', 'mtp', 'nor', 'nrr', 'su', 'bs', 'rtp', 'cid', 'pr', 'sf', 'sid', 'st', 'v']
enabledKeys: Constants.CMCD_AVAILABLE_KEYS,
includeInRequests: ['segment']
},
cmsd: {
enabled: false,
Expand Down
4 changes: 4 additions & 0 deletions src/dash/constants/DashConstants.js
Expand Up @@ -36,6 +36,7 @@
export default {
ACCESSIBILITY: 'Accessibility',
ADAPTATION_SET: 'AdaptationSet',
ADAPTATION_SETS: 'adaptationSets',
ADAPTATION_SET_SWITCHING_SCHEME_ID_URI: 'urn:mpeg:dash:adaptation-set-switching:2016',
ADD: 'add',
ASSET_IDENTIFIER: 'AssetIdentifier',
Expand All @@ -51,7 +52,9 @@ export default {
BITSTREAM_SWITCHING_MINUS: 'bitstreamSwitching',
BYTE_RANGE: 'byteRange',
CENC_DEFAULT_KID: 'cenc:default_KID',
CLIENT_DATA_REPORTING: 'ClientDataReporting',
CLIENT_REQUIREMENT: 'clientRequirement',
CMCD_PARAMETERS: 'CMCDParameters',
CODECS: 'codecs',
CODEC_PRIVATE_DATA: 'codecPrivateData',
CODING_DEPENDENCY: 'codingDependency',
Expand Down Expand Up @@ -161,6 +164,7 @@ export default {
SERVICE_DESCRIPTION_PLAYBACK_RATE: 'PlaybackRate',
SERVICE_DESCRIPTION_SCOPE: 'Scope',
SERVICE_LOCATION: 'serviceLocation',
SERVICE_LOCATIONS: 'serviceLocations',
SOURCE_URL: 'sourceURL',
START: 'start',
START_NUMBER: 'startNumber',
Expand Down
16 changes: 15 additions & 1 deletion src/dash/controllers/ServiceDescriptionController.js
Expand Up @@ -80,7 +80,8 @@ function ServiceDescriptionController() {
minBitrate: {},
maxBitrate: {},
initialBitrate: {},
contentSteering: null
contentSteering: null,
clientDataReporting: null,
};
prftOffsets = [];
}
Expand Down Expand Up @@ -128,6 +129,10 @@ function ServiceDescriptionController() {
if (sd.contentSteering) {
_applyServiceDescriptionContentSteering(sd);
}

if (sd.clientDataReporting) {
_applyServiceDescriptionClientDataReporting(sd);
}
}

/**
Expand Down Expand Up @@ -293,6 +298,15 @@ function ServiceDescriptionController() {
serviceDescriptionSettings.contentSteering = sd.contentSteering;
}

/**
* Add information about client data reporting element. Handling is up to the CMCDModel
* @param {object} sd
* @private
*/
function _applyServiceDescriptionClientDataReporting(sd) {
serviceDescriptionSettings.clientDataReporting = sd.clientDataReporting;
}

/**
* Returns the current calculated time offsets based on ProducerReferenceTime elements
* @returns {array}
Expand Down
35 changes: 32 additions & 3 deletions src/dash/models/DashManifestModel.js
Expand Up @@ -50,6 +50,8 @@ import Errors from '../../core/errors/Errors.js';
import MpdLocation from '../vo/MpdLocation.js';
import PatchLocation from '../vo/PatchLocation.js';
import ContentProtection from '../vo/ContentProtection.js';
import ClientDataReporting from '../vo/ClientDataReporting.js';
import CMCDParameters from '../vo/CMCDParameters.js';

function DashManifestModel() {
let instance,
Expand Down Expand Up @@ -1255,6 +1257,27 @@ function DashManifestModel() {
return entry;
}

function _createClientDataReportingInstance(element){
const entry = new ClientDataReporting();

if (element.hasOwnProperty(DashConstants.CMCD_PARAMETERS) && element[DashConstants.CMCD_PARAMETERS].schemeIdUri === Constants.CTA_5004_2023_SCHEME) {
entry.cmcdParameters = new CMCDParameters();
entry.cmcdParameters.init(element[DashConstants.CMCD_PARAMETERS]);
}

if (element.hasOwnProperty(DashConstants.SERVICE_LOCATIONS) && element[DashConstants.SERVICE_LOCATIONS] !== ''){
entry.serviceLocations = element[DashConstants.SERVICE_LOCATIONS];
entry.serviceLocationsArray = entry.serviceLocations.toString().split(' ');
}

if (element.hasOwnProperty(DashConstants.ADAPTATION_SETS) && element[DashConstants.ADAPTATION_SETS] !== ''){
entry.adaptationSets = element[DashConstants.ADAPTATION_SETS];
entry.adaptationSetsArray = entry.adaptationSets.toString().split(' ');
}

return entry;
}

function getLocation(manifest) {
if (manifest && manifest.hasOwnProperty(DashConstants.LOCATION)) {
return manifest[DashConstants.LOCATION].map((entry) => {
Expand Down Expand Up @@ -1301,7 +1324,8 @@ function DashManifestModel() {
playbackRate = null,
operatingQuality = null,
operatingBandwidth = null,
contentSteering = null;
contentSteering = null,
clientDataReporting = null;

for (const prop in sd) {
if (sd.hasOwnProperty(prop)) {
Expand Down Expand Up @@ -1338,7 +1362,11 @@ function DashManifestModel() {
target: parseInt(sd[prop].target)
}
} else if (prop === DashConstants.CONTENT_STEERING) {
contentSteering = _createContentSteeringInstance(sd[prop])
let element = sd[prop];
element = Array.isArray(element) ? element.at(element.length - 1) : element;
contentSteering = _createContentSteeringInstance(element);
} else if (prop === DashConstants.CLIENT_DATA_REPORTING) {
clientDataReporting = _createClientDataReportingInstance(sd[prop]);
}
}
}
Expand All @@ -1350,7 +1378,8 @@ function DashManifestModel() {
playbackRate,
operatingQuality,
operatingBandwidth,
contentSteering
contentSteering,
clientDataReporting
});
}
}
Expand Down
64 changes: 64 additions & 0 deletions src/dash/vo/CMCDParameters.js
@@ -0,0 +1,64 @@
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2024, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

import DescriptorType from './DescriptorType.js';

/**
* @class
* @ignore
*/
class CMCDParameters extends DescriptorType {
constructor() {
super();
this.version = null;
this.sessionID = null;
this.contentID = null;
this.mode = null;
this.keys = null;
this.includeInRequests = null;
}

init(data) {
super.init(data);

if (data) {
this.version = data.version;
this.sessionID = data.sessionID;
this.contentID = data.contentID;
this.mode = data.mode ?? 'query';
this.keys = data.keys ? data.keys.split(' ') : null;
this.includeInRequests = data.includeInRequests ? data.includeInRequests.split(' ') : ['segment'];
this.schemeIdUri = data.schemeIdUri;
}
}
}

export default CMCDParameters;
45 changes: 45 additions & 0 deletions src/dash/vo/ClientDataReporting.js
@@ -0,0 +1,45 @@
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2024, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @class
* @ignore
*/
class ClientDataReporting {
constructor() {
this.cmcdParameters = null;
this.serviceLocations = null;
this.serviceLocationsArray = [];
this.adaptationSets = null;
this.adaptationSetsArray = [];
}
}

export default ClientDataReporting;

0 comments on commit 5117500

Please sign in to comment.