Skip to content

Commit 7a9cff6

Browse files
committed
feat: implement CMCD v2 functionality
1 parent 84f5eac commit 7a9cff6

31 files changed

Lines changed: 6502 additions & 2028 deletions

index.d.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,21 +3755,55 @@ export interface BaseURLTreeModel {
37553755
}
37563756

37573757
export interface CmcdModel {
3758+
setup(): void;
3759+
3760+
reset(): void;
3761+
3762+
setConfig(config: object): void;
3763+
37583764
getCmcdData(request: HTTPRequest): object;
37593765

3760-
getCmcdParametersFromManifest(): CMCDParameters;
3766+
onStateChange(state: any): void;
37613767

3762-
getHeaderParameters(request: HTTPRequest): object | null;
3768+
onPeriodSwitchComplete(): void;
37633769

3764-
getQueryParameter(request: HTTPRequest): { key: string, finalPayloadString: string } | null;
3770+
onPlaybackStarted(): void;
37653771

3766-
initialize(): void;
3772+
onPlaybackPlaying(): void;
37673773

3768-
isCmcdEnabled(): boolean;
3774+
onRebufferingStarted(mediaType: string): void;
37693775

3770-
reset(): void;
3776+
onRebufferingCompleted(mediaType: string): void;
37713777

3772-
setConfig(config: object): void;
3778+
onPlayerError(errorData: any): void;
3779+
3780+
onPlaybackSeeking(): void;
3781+
3782+
onPlaybackSeeked(): void;
3783+
3784+
onPlaybackRateChanged(data: any): void;
3785+
3786+
wasPlaying(): boolean;
3787+
3788+
onManifestLoaded(data: any): void;
3789+
3790+
onBufferLevelStateChanged(data: any): void;
3791+
3792+
updateMsdData(mode: string): object;
3793+
3794+
resetInitialSettings(): void;
3795+
3796+
getCmcdParametersFromManifest(): CMCDParameters;
3797+
3798+
triggerCmcdEventMode(event: string): object;
3799+
3800+
getGenericCmcdData(mediaType?: string): object;
3801+
3802+
isIncludedInRequestFilter(type: string, includeInRequests?: any): boolean;
3803+
3804+
getLastMediaTypeRequest(): string;
3805+
3806+
onEventChange(state: any): void;
37733807
}
37743808

37753809
export interface CmsdModel {
@@ -6012,4 +6046,3 @@ export interface KeySystemInfo {
60126046
export type RequestFilter = (request: LicenseRequest) => Promise<any>;
60136047
export type ResponseFilter = (response: LicenseResponse) => Promise<any>;
60146048

6015-
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>CMCD v2 Callbacks with Network Interceptors</title>
6+
7+
<script src="../../dist/modern/umd/dash.all.debug.js"></script>
8+
9+
<!-- Bootstrap core CSS -->
10+
<link href="../lib/bootstrap/bootstrap.min.css" rel="stylesheet">
11+
<link href="../lib/main.css" rel="stylesheet">
12+
13+
<style>
14+
video {
15+
width: 640px;
16+
height: 360px;
17+
}
18+
19+
#trace {
20+
height: 500px;
21+
margin-top: 20px;
22+
font-size: 10px;
23+
}
24+
</style>
25+
<script>
26+
function getKeysForQueryMode(cmcdString) {
27+
var cmcdData = {};
28+
var cmcdString = cmcdString;
29+
30+
extractKeyValuePairs(cmcdString, cmcdData);
31+
32+
return cmcdData;
33+
}
34+
35+
function extractKeyValuePairs(cmcdString, cmcdData) {
36+
if (cmcdString === '') {
37+
return;
38+
}
39+
var keyValuePairs = cmcdString.split(',');
40+
41+
keyValuePairs.forEach(function (keyValuePair) {
42+
var data = keyValuePair.split('=');
43+
var key = data[0];
44+
var value = data[1];
45+
46+
cmcdData[key] = value;
47+
})
48+
}
49+
50+
function log(msg) {
51+
msg = msg.length > 200 ? msg.substring(0, 200) + '...' : msg; /* to avoid repeated wrapping with large objects */
52+
var tracePanel = document.getElementById('trace');
53+
tracePanel.innerHTML += msg + '\n';
54+
tracePanel.scrollTop = tracePanel.scrollHeight;
55+
}
56+
</script>
57+
<script class="code">
58+
var CMCD_MODE_QUERY = 'query'; /* as query parameters */
59+
var player;
60+
61+
function init() {
62+
var video,
63+
url = 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
64+
version;
65+
66+
player = dashjs.MediaPlayer().create();
67+
video = document.querySelector('video');
68+
player.initialize();
69+
version = player.getVersion();
70+
71+
player.updateSettings({
72+
streaming: {
73+
cmcd: {
74+
version: 2,
75+
enabled: true, /* enable reporting of cmcd parameters */
76+
sid: 'b248658d-1d1a-4039-91d0-8c08ba597da5', /* session id send with each request */
77+
cid: '21cf726cfe3d937b5f974f72bb5bd06a', /* content id send with each request */
78+
mode: CMCD_MODE_QUERY,
79+
enabledKeys: ['cid', 'sid'],
80+
includeInRequests: ['segment', 'mpd'],
81+
targets: [
82+
{
83+
enabled: true,
84+
url: 'http://localhost:3003/report',
85+
enabledKeys: ['e', 'rc', 'url'],
86+
mode: CMCD_MODE_QUERY,
87+
events: ['rr']
88+
},
89+
]
90+
}
91+
}
92+
});
93+
player.setAutoPlay(false);
94+
player.attachView(video);
95+
player.attachSource(url);
96+
97+
/* Callback before report */
98+
player.addRequestInterceptor((request) => {
99+
if (request.customData.request.type == 'CmcdEvent' && request.url.includes('rr') && request.url.includes('http://localhost:3003/report')) {
100+
let customKey = 'synchronization-leader-sid';
101+
let customKeyValue = '123'
102+
let { cmcd } = request;
103+
if (cmcd) {
104+
/* Add custom key to cmcd data */
105+
cmcd[customKey] = customKeyValue;
106+
/* Add custom key to query parameters */
107+
let newParam = encodeURIComponent(`,${customKey}="${customKeyValue}"`);
108+
request.url += newParam;
109+
}
110+
}
111+
return Promise.resolve(request);
112+
});
113+
114+
/* Callback after server response */
115+
player.addResponseInterceptor((response) => {
116+
request = response.request.customData.request;
117+
if (request.type == 'CmcdEvent' && request.url.includes('rr') && request.url.includes('http://localhost:3003/report')) {
118+
console.log(request.cmcd);
119+
}
120+
return Promise.resolve(response);
121+
});
122+
123+
const originalOpen = XMLHttpRequest.prototype.open;
124+
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
125+
if (url.includes('report')) {
126+
const queryString = decodeURIComponent(url.split('CMCD=')[1]);
127+
const data = getKeysForQueryMode(queryString);
128+
var keys = Object.keys(data);
129+
keys = keys.sort();
130+
for (var key of keys) {
131+
log(key.padEnd(4) + ': ' + data[key]);
132+
}
133+
log('');
134+
}
135+
return originalOpen.call(this, method, url, ...rest);
136+
};
137+
}
138+
</script>
139+
</head>
140+
<body>
141+
142+
<main>
143+
<div class="container py-4">
144+
<header class="pb-3 mb-4 border-bottom">
145+
<img class=""
146+
src="../lib/img/dashjs-logo.png"
147+
width="200">
148+
</header>
149+
<div class="row">
150+
<div class="col-md-12">
151+
<div class="h-100 p-5 bg-light border rounded-3">
152+
<h3>CMCD v2 Callbacks with Network Interceptors</h3>
153+
<p>This sample shows how to use Network Interceptors to execute callbacks after server response or pre-request callbacks for Response and Event Mode</p>
154+
</div>
155+
</div>
156+
</div>
157+
<div class="row mt-2">
158+
<div class="col-md-6">
159+
<video controls="true"></video>
160+
</div>
161+
<div class="col-md-6">
162+
<div class="form-floating">
163+
<textarea class="form-control" placeholder="Sent CMCD data will be displayed here"
164+
id="trace"></textarea>
165+
<label for="trace">CMCD Report Data</label>
166+
</div>
167+
</div>
168+
</div>
169+
<div class="row">
170+
<div class="col-md-12">
171+
<div id="code-output"></div>
172+
</div>
173+
</div>
174+
<footer class="pt-3 mt-4 text-muted border-top">
175+
&copy; DASH-IF
176+
</footer>
177+
</div>
178+
</main>
179+
180+
181+
<script>
182+
document.addEventListener('DOMContentLoaded', function () {
183+
init();
184+
});
185+
</script>
186+
<script src="../highlighter.js"></script>
187+
</body>
188+
</html>

0 commit comments

Comments
 (0)