Skip to content
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
13 changes: 6 additions & 7 deletions samples/advanced/cmcd-v2-network-interceptors.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@
includeInRequests: ['segment', 'mpd'],
targets: [
{
cmcdMode: 'response',
enabled: true,
url: 'http://localhost:3003/response-mode',
enabledKeys: ['ot', 'rc', 'msd'],
url: 'http://localhost:3003/report',
enabledKeys: ['e', 'rc', 'url'],
mode: CMCD_MODE_QUERY,
includeOnRequests: ['mpd', 'segment'],
events: ['rr']
},
]
}
Expand All @@ -97,7 +96,7 @@

/* Callback before report */
player.addRequestInterceptor((request) => {
if (request.customData.request.type == 'CmcdResponse' && request.url.includes('http://localhost:3003/response-mode')) {
if (request.customData.request.type == 'CmcdEvent' && request.url.includes('rr') && request.url.includes('http://localhost:3003/report')) {
let customKey = 'synchronization-leader-sid';
let customKeyValue = '123'
let { cmcd } = request;
Expand All @@ -115,15 +114,15 @@
/* Callback after server response */
player.addResponseInterceptor((response) => {
request = response.request.customData.request;
if (request.type == 'CmcdResponse' && request.url.includes('http://localhost:3003/response-mode')) {
if (request.type == 'CmcdEvent' && request.url.includes('rr') && request.url.includes('http://localhost:3003/report')) {
console.log(request.cmcd);
}
return Promise.resolve(response);
});

const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
if (url.includes('response-mode')) {
if (url.includes('report')) {
const queryString = decodeURIComponent(url.split('CMCD=')[1]);
const data = getKeysForQueryMode(queryString);
var keys = Object.keys(data);
Expand Down
12 changes: 4 additions & 8 deletions samples/advanced/cmcd-v2.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,15 @@
enabledKeys: ['br', 'd', 'ot', 'tb' , 'bl', 'dl', 'mtp', 'nor', 'nrr', 'su' , 'bs', 'rtp' , 'cid', 'pr', 'sf', 'sid', 'st', 'v', 'msd'],
targets: [
{
cmcdMode: 'response',
enabled: true,
url: 'http://localhost:3001/cmcd/response-mode',
enabledKeys: ['ot', 'rc', 'msd'],
url: 'http://localhost:3001/cmcd/response-received',
enabledKeys: ['url', 'rc', 'msd'],
includeOnRequests: ['mpd', 'segment'],
events: ['rr'],
mode: CMCD_MODE_QUERY,
},
{
enabled: true,
cmcdMode: 'event',
url: 'http://localhost:3002/cmcd/event-mode',
timeInterval: 10,
enabledKeys: ['e', 'msd', 'sta'],
Expand All @@ -73,21 +72,18 @@
},
{
enabled: true,
cmcdMode: 'event',
url: 'http://localhost:3003/cmcd/event-mode',
timeInterval: 6,
mode: CMCD_MODE_HEADER,
},
{
enabled: true,
cmcdMode: 'response',
url: 'http://localhost:3004/cmcd/response-body-mode',
url: 'http://localhost:3004/cmcd/event-body-mode',
mode: CMCD_MODE_BODY,
batchSize: 3,
},
{
enabled: true,
cmcdMode: 'event',
url: 'http://localhost:3005/cmcd/event-body-mode',
mode: CMCD_MODE_BODY,
batchTimer: 3,
Expand Down
2 changes: 1 addition & 1 deletion src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ function Settings() {
rtp: null,
rtpSafetyFactor: 5,
mode: Constants.CMCD_MODE_QUERY,
enabledKeys: null,
enabledKeys: Constants.CMCD_KEYS,
includeInRequests: ['segment', 'mpd'],
version: 1,
targets: []
Expand Down
8 changes: 8 additions & 0 deletions src/streaming/constants/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { CmcdEventType } from '@svta/common-media-library/cmcd/CmcdEventType';
import { CMCD_DEFAULT_TIME_INTERVAL } from '@svta/common-media-library/cmcd/CMCD_DEFAULT_TIME_INTERVAL';
import { CMCD_PARAM } from '@svta/common-media-library/cmcd/CMCD_PARAM';
import { CMCD_QUERY } from '@svta/common-media-library/cmcd/CMCD_QUERY';
import { CMCD_KEYS } from '@svta/common-media-library/cmcd/CMCD_KEYS';

/**
* Constants declaration
Expand Down Expand Up @@ -247,6 +248,13 @@ export default {
*/
CMCD_REPORTING_MODE: CmcdReportingMode,

/**
* @constant {string} CMCD_KEYS specifies all the available keys for CMCD.
* @memberof Constants#
* @static
*/
CMCD_KEYS: CMCD_KEYS,

/**
* @constant {string} CMCD_REPORTING_EVENTS specifies all the available events for CMCD event mode.
* @memberof Constants#
Expand Down
7 changes: 1 addition & 6 deletions src/streaming/controllers/CmcdBatchController.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,7 @@ function CmcdBatchController() {
httpRequest.method = HTTPRequest.POST;
httpRequest.body = cmcdData;
httpRequest.headers = Constants.CMCD_CONTENT_TYPE_HEADER

if (target.cmcdMode === Constants.CMCD_REPORTING_MODE.EVENT) {
httpRequest.type = HTTPRequest.CMCD_EVENT;
} else if (target.cmcdMode === Constants.CMCD_REPORTING_MODE.RESPONSE) {
httpRequest.type = HTTPRequest.CMCD_RESPONSE;
}
httpRequest.type = HTTPRequest.CMCD_EVENT;

_sendBatchReport(httpRequest)
.then((response) => {
Expand Down
134 changes: 55 additions & 79 deletions src/streaming/controllers/CmcdController.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ function CmcdController() {

function _initializeEventModeTimeInterval() {
const targets = settings.get().streaming.cmcd.targets;
const eventModeTargets = targets.filter((target) => target.cmcdMode === Constants.CMCD_REPORTING_MODE.EVENT);
eventModeTargets.forEach(({ timeInterval, events }) => {
targets.forEach(({ timeInterval, events }) => {
if (!events || !events.includes(Constants.CMCD_REPORTING_EVENTS.TIME_INTERVAL)) {
return;
}
Expand All @@ -176,9 +175,9 @@ function CmcdController() {
_onEventChange(Constants.CMCD_REPORTING_EVENTS.PLAY_STATE);
}

function _onEventChange(state){
function _onEventChange(state, response){
cmcdModel.onEventChange(state);
triggerCmcdEventMode(state);
triggerCmcdEventMode(state, response);
}

function _onPeriodSwitchComplete() {
Expand Down Expand Up @@ -228,47 +227,54 @@ function CmcdController() {
}
}

function triggerCmcdEventMode(event){
function triggerCmcdEventMode(event, response){
const targets = settings.get().streaming.cmcd.targets;
const eventModeTargets = targets.filter((target) => target.cmcdMode === Constants.CMCD_REPORTING_MODE.EVENT);

if (eventModeTargets.length === 0) {
if (targets.length === 0) {
return;
}

const cmcdData = cmcdModel.triggerCmcdEventMode(event);
let cmcdData = cmcdModel.triggerCmcdEventMode(event);
if (event === Constants.CMCD_REPORTING_EVENTS.RESPONSE_RECEIVED) {
cmcdData = {...cmcdData, ...response.request.cmcd}
cmcdData = _addCmcdResponseReceivedData(response, cmcdData);
}

eventModeTargets.forEach(targetSettings => {
if (targetSettings.enabled) {
targets.forEach(targetSettings => {
if (!isCmcdEnabled(targetSettings)){
return;
}

if (targetSettings.events?.length === 0) {
logger.warn('CMCD Event Mode is enabled, but the "events" setting is empty. No event-specific CMCD data will be sent.');
}
const requestType = response?.request.customData.request.type;
if (requestType && !cmcdModel.isIncludedInRequestFilter(requestType, targetSettings.includeOnRequests)){
return;
}

let events = targetSettings.events ? targetSettings.events : Object.values(Constants.CMCD_REPORTING_EVENTS);
if (targetSettings.events?.length === 0) {
logger.warn('CMCD Event Mode is enabled, but the "events" setting is empty. No event-specific CMCD data will be sent.');
}

if (!events.includes(event)) {
return;
}
let events = targetSettings.events ? targetSettings.events : Object.values(Constants.CMCD_REPORTING_EVENTS);

let httpRequest = new CmcdReportRequest();
if (!events.includes(event)) {
return;
}

httpRequest.url = targetSettings.url;
httpRequest.type = HTTPRequest.CMCD_EVENT;
httpRequest.method = HTTPRequest.GET;
let httpRequest = new CmcdReportRequest();

const sequenceNumber = _getNextSequenceNumber(targetSettings);
let cmcd = {...cmcdData, sn: sequenceNumber}
httpRequest.cmcd = cmcd;
httpRequest.url = targetSettings.url;
httpRequest.type = HTTPRequest.CMCD_EVENT;
httpRequest.method = HTTPRequest.GET;

if (isCmcdEnabled(targetSettings)) {
_updateRequestWithCmcd(httpRequest, cmcd, targetSettings)
if ((targetSettings.batchSize || targetSettings.batchTimer) && httpRequest.body){
cmcdBatchController.addReport(targetSettings, httpRequest.body)
} else {
_sendCmcdDataReport(httpRequest);
}
}
const sequenceNumber = _getNextSequenceNumber(targetSettings);
let cmcd = {...cmcdData, sn: sequenceNumber}
httpRequest.cmcd = cmcd;

_updateRequestWithCmcd(httpRequest, cmcd, targetSettings)
if ((targetSettings.batchSize || targetSettings.batchTimer) && httpRequest.body){
cmcdBatchController.addReport(targetSettings, httpRequest.body)
} else {
_sendCmcdDataReport(httpRequest);
}
});
}
Expand Down Expand Up @@ -299,8 +305,8 @@ function CmcdController() {
if (isIncludedFilters) {
const cmcdParameters = cmcdModel.getCmcdParametersFromManifest();
const cmcdModeSetting = targetSettings ? targetSettings.mode : settings.get().streaming.cmcd.mode;
const cmcdMode = cmcdParameters.mode ? cmcdParameters.mode : cmcdModeSetting;
switch (cmcdMode) {
const mode = cmcdParameters.mode ? cmcdParameters.mode : cmcdModeSetting;
switch (mode) {
case Constants.CMCD_MODE_QUERY:
request.url = Utils.removeQueryParameterFromUrl(request.url, Constants.CMCD_QUERY_KEY);
const additionalQueryParameter = _getAdditionalQueryParameter(request, cmcdData, targetSettings);
Expand All @@ -311,7 +317,7 @@ function CmcdController() {
request.headers = Object.assign(request.headers, getHeaderParameters(request, cmcdData, targetSettings));
break;
case Constants.CMCD_MODE_BODY:
if (request.type === HTTPRequest.CMCD_RESPONSE || request.type === HTTPRequest.CMCD_EVENT) {
if (request.type === HTTPRequest.CMCD_EVENT) {
request.body = getJsonParameters(request, cmcdData, targetSettings);
request.method = HTTPRequest.POST;
request.headers = request.headers || {};
Expand Down Expand Up @@ -480,7 +486,7 @@ function CmcdController() {
(cmcdParametersFromManifest.version ? cmcdParametersFromManifest.keys : settings.get().streaming.cmcd.enabledKeys);

return {
reportingMode: targetSettings?.cmcdMode,
reportingMode: targetSettings ? Constants.CMCD_REPORTING_MODE.EVENT : Constants.CMCD_REPORTING_MODE.REQUEST,
version: settings.get().streaming.cmcd.version ?? Constants.CMCD_DEFAULT_VERSION,
filter: enabledKeys ? (key) => enabledKeys.includes(key) : undefined,
}
Expand Down Expand Up @@ -558,86 +564,56 @@ function CmcdController() {
}

function getCmcdResponseInterceptors(){
return [_cmcdResponseModeInterceptor];
return [_cmcdResponseReceivedInterceptor];
}

function _cmcdResponseModeInterceptor(response){
const requestType = response.request.customData.request.type;

let cmcdData = {
...response.request.cmcd,
};

cmcdData = _addCmcdResponseModeData(response, cmcdData);
const targets = settings.get().streaming.cmcd.targets;
const responseModeTargets = targets.filter((target) => target.cmcdMode === Constants.CMCD_REPORTING_MODE.RESPONSE);
responseModeTargets.forEach(targetSettings => {
if (targetSettings.enabled && cmcdModel.isIncludedInRequestFilter(requestType, targetSettings.includeOnRequests)){
let httpRequest = new CmcdReportRequest();
httpRequest.url = targetSettings.url;
httpRequest.type = HTTPRequest.CMCD_RESPONSE;
httpRequest.method = HTTPRequest.GET;

const sequenceNumber = _getNextSequenceNumber(targetSettings);
let cmcd = {...cmcdData, sn: sequenceNumber}
httpRequest.cmcd = cmcd;

if (isCmcdEnabled(targetSettings)) {
_updateRequestWithCmcd(httpRequest, cmcd, targetSettings)
if ((targetSettings.batchSize || targetSettings.batchTimer) && httpRequest.body){
cmcdBatchController.addReport(targetSettings, httpRequest.body)
} else {
_sendCmcdDataReport(httpRequest);
}
}
}
});

function _cmcdResponseReceivedInterceptor(response){
_onEventChange(Constants.CMCD_REPORTING_EVENTS.RESPONSE_RECEIVED, response)
return response;
}

function _addCmcdResponseModeData(response, cmcdData){
const responseModeData = {};
function _addCmcdResponseReceivedData(response, cmcdData){
const responseData = {};
const request = response.request.customData.request;
const requestType = request.type;

if (requestType === HTTPRequest.MEDIA_SEGMENT_TYPE){
responseModeData.rc = response.status;
responseData.rc = response.status;
}

if (request.startDate && request.firstByteDate){
responseModeData.ttfb = request.firstByteDate - request.startDate;
responseData.ttfb = request.firstByteDate - request.startDate;
}

if (request.endDate && request.startDate){
responseModeData.ttlb = request.endDate - request.startDate
responseData.ttlb = request.endDate - request.startDate
}

if (request.url) {
responseModeData.url = request.url.split('?')[0]
responseData.url = request.url.split('?')[0]
}

if (response.headers){
try {
const cmsdStaticHeader = response.headers['cmsd-static'];
if (cmsdStaticHeader) {
responseModeData.cmsds = btoa(cmsdStaticHeader);
responseData.cmsds = btoa(cmsdStaticHeader);
}

const cmsdDynamicHeader = response.headers['cmsd-dynamic'];
if (cmsdDynamicHeader) {
responseModeData.cmsdd = btoa(cmsdDynamicHeader);
responseData.cmsdd = btoa(cmsdDynamicHeader);
}
} catch (e) {
logger.warn('Failed to base64 encode CMSD headers, ignoring.', e);
}
}

return {...cmcdData, ...responseModeData};
return {...cmcdData, ...responseData};
}

function _getTargetKey(target) {
return `${target.url}_${target.cmcdMode}_${target.mode}`;
return `${target.url}_${target.mode}`;
}

function _getNextSequenceNumber(target) {
Expand Down
1 change: 0 additions & 1 deletion src/streaming/vo/metrics/HTTPRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE = 'FragmentInfoSegment';
HTTPRequest.DVB_REPORTING_TYPE = 'DVBReporting';
HTTPRequest.LICENSE = 'license';
HTTPRequest.CONTENT_STEERING_TYPE = 'ContentSteering';
HTTPRequest.CMCD_RESPONSE = 'CmcdResponse';
HTTPRequest.CMCD_EVENT = 'CmcdEvent';
HTTPRequest.OTHER_TYPE = 'other';

Expand Down
Loading
Loading