Skip to content

Commit

Permalink
Feature/mpd patching test (#4462)
Browse files Browse the repository at this point in the history
* Add functional test for MPD patching

* Add sample for MPD patching

* Add new function to Typescript file and revert changes in package.json

* Return right type in JSDoc

* Change single teststream

* Run tests on Chrome
  • Loading branch information
dsilhavy committed Apr 17, 2024
1 parent b38ba81 commit 0837a99
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 10 deletions.
4 changes: 3 additions & 1 deletion index.d.ts
Expand Up @@ -1571,6 +1571,8 @@ declare namespace dashjs {

destroy(): void;

getManifest(): object;

}

interface MediaPlayerErrors {
Expand Down Expand Up @@ -3690,7 +3692,7 @@ declare namespace dashjs {
getFonts(): FontInfo[];

getFontsForTrackId(trackId: number): FontInfo[];

reset(): void;
}

Expand Down
116 changes: 116 additions & 0 deletions samples/live-streaming/mpd-patching.html
@@ -0,0 +1,116 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Live stream with MPD Patching</title>

<script src="../../dist/dash.all.debug.js"></script>

<!-- Bootstrap core CSS -->
<link href="../lib/bootstrap/bootstrap.min.css" rel="stylesheet">
<link href="../lib/main.css" rel="stylesheet">

<style>
video {
width: 100%;
}

.clock {
color: #000;
font-size: 60pt
}
</style>

<script class="code">
var outputContainer;

function init() {
var video,
player,
url = 'https://192-46-234-23.ip.linodeusercontent.com/livesim2/segtimeline_1/patch_60/testpic_2s/Manifest.mpd';

video = document.querySelector('video');
player = dashjs.MediaPlayer().create();
player.initialize(video, url, true);
outputContainer = document.getElementById('output-container');
player.on('internalManifestLoaded', showEvent)
}


function showEvent(e) {
outputContainer.innerHTML = "";
for (var name in e) {

if (typeof e[name] != 'object') {
log(' ' + name + ': ' + e[name]);
}
}
for (name in e) {
if (typeof e[name] == 'object') {
log(' ' + name + ':');
for (name2 in e[name]) {
log(' ' + name2 + ': ' + JSON.stringify(e[name][name2]));
}
}
}
}

function log(msg) {
msg = msg.length > 90 ? msg.substring(0, 90) + '...' : msg;
outputContainer.innerHTML += msg + '\n';
outputContainer.scrollTop = outputContainer.scrollHeight;
}
</script>
</head>
<body>

<main>
<div class="container py-4">
<header class="pb-3 mb-4 border-bottom">
<img class=""
src="../lib/img/dashjs-logo.png"
width="200">
</header>
<div class="row">
<div class="col-md-6">
<div class="h-100 p-5 bg-light border rounded-3">
<h3>Live stream with MPD Patching</h3>
<p>Example showing how dash.js handles live streams with updates to the manifest file provided via
MPD patches.</p>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-7">
<video controls="true"></video>
</div>
</div>
<div class="row mt-4">
<div class="col-md-12">
<div class="p-5 border rounded-3 mt-1">
<h4>Last MPD update</h4>
<div id="output-container">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div id="code-output"></div>
</div>
</div>
<footer class="pt-3 mt-4 text-muted border-top">
&copy; DASH-IF
</footer>
</div>
</main>


<script>
document.addEventListener('DOMContentLoaded', function () {
init();
});
</script>
<script src="../highlighter.js"></script>
</body>
</html>
11 changes: 11 additions & 0 deletions samples/samples.json
Expand Up @@ -165,6 +165,17 @@
"Video",
"Audio"
]
},
{
"title": "Live stream with MPD Patching",
"description": "Example showing how dash.js handles live streams with updates to the MPD provided via MPD patching",
"href": "live-streaming/mpd-patching.html",
"image": "lib/img/livesim-1.jpg",
"labels": [
"Live",
"Video",
"Audio"
]
}
]
},
Expand Down
8 changes: 8 additions & 0 deletions src/streaming/MediaPlayer.js
Expand Up @@ -2171,6 +2171,13 @@ function MediaPlayer() {
}
}

/**
* Returns the current manifest
* @returns {object}
*/
function getManifest() {
return manifestModel.getValue();
}

/**
* Returns all BaseURLs that are available including synthesized elements (e.g by content steering)
Expand Down Expand Up @@ -2642,6 +2649,7 @@ function MediaPlayer() {
getPlaybackRate,
getProtectionController,
getCurrentRepresentationForType,
getManifest,
getRepresentationsByType,
getSettings,
getSource,
Expand Down
25 changes: 25 additions & 0 deletions test/functional/adapter/DashJsAdapter.js
Expand Up @@ -192,6 +192,10 @@ class DashJsAdapter {
return this.player.getTargetLiveDelay();
}

getManifest() {
return this.player.getManifest();
}

seek(value) {
this.player.seek(value);
}
Expand Down Expand Up @@ -478,6 +482,27 @@ class DashJsAdapter {
})
}

async waitForEventAndGetPayload(timeoutValue, event) {
return new Promise((resolve) => {
let timeout = null;

const _onComplete = (res) => {
clearTimeout(timeout);
timeout = null;
this.player.off(event, _onEvent);
resolve(res);
}
const _onTimeout = () => {
_onComplete(null);
}
const _onEvent = (e) => {
_onComplete(e);
}
timeout = setTimeout(_onTimeout, timeoutValue);
this.player.on(event, _onEvent);
})
}

async waitForMediaSegmentDownload(timeoutValue) {
return new Promise((resolve) => {
let timeout = null;
Expand Down
2 changes: 1 addition & 1 deletion test/functional/config/karma.functional.conf.cjs
Expand Up @@ -125,7 +125,7 @@ module.exports = function (config) {
autoWatch: false,

browserNoActivityTimeout: 180000,
browserDisconnectTimeout: 10000,
browserDisconnectTimeout: 20000,
browserDisconnectTolerance: 3,

// start these browsers
Expand Down
22 changes: 22 additions & 0 deletions test/functional/config/test-configurations/streams/all.json
Expand Up @@ -419,6 +419,28 @@
}
]
}
},
{
"name": "MPD Patching with $time",
"url": "https://192-46-234-23.ip.linodeusercontent.com/livesim2/segtimeline_1/patch_60/testpic_2s/Manifest.mpd",
"type": "live",
"testdata": {
"mpdPatching": true
},
"includedTestfiles": [
"feature-support/mpd-patching"
]
},
{
"name": "MPD Patching with $number",
"url": "https://192-46-234-23.ip.linodeusercontent.com/livesim2/segtimelinenr_1/patch_60/testpic_2s/Manifest.mpd",
"type": "live",
"testdata": {
"mpdPatching": true
},
"includedTestfiles": [
"feature-support/mpd-patching"
]
}
]
}
Expand Up @@ -9,11 +9,11 @@
},
"testvectors": [
{
"name": "AWS Single Period $number$",
"url": "https://d10gktn8v7end7.cloudfront.net/out/v1/6ee19df3afa24fe190a8ae16c2c88560/index.mpd",
"type": "live",
"name": "Segment Base",
"type": "vod",
"url": "https://dash.akamaized.net/dash264/TestCases/1a/sony/SNE_DASH_SD_CASE1A_REVISED.mpd",
"includedTestfiles": [
"playback-advanced/cmcd"
"playback/*"
]
}
]
Expand Down
13 changes: 12 additions & 1 deletion test/functional/config/test-configurations/streams/smoke.json
Expand Up @@ -74,7 +74,7 @@
"playback/play",
"playback/pause",
"playback/seek",
"playback-advanced/cmcd",
"feature-support/cmcd",
"playback-advanced/preload"
]
},
Expand Down Expand Up @@ -152,6 +152,17 @@
"includedTestfiles": [
"playback/*"
]
},
{
"name": "MPD Patching with $time",
"url": "https://192-46-234-23.ip.linodeusercontent.com/livesim2/segtimeline_1/patch_60/testpic_2s/Manifest.mpd",
"type": "live",
"testdata": {
"mpdPatching": true
},
"includedTestfiles": [
"feature-support/mpd-patching"
]
}
]
}
3 changes: 2 additions & 1 deletion test/functional/src/Constants.js
Expand Up @@ -136,6 +136,8 @@ TESTCASES.BUFFER.INITIAL_TARGET = TESTCASES.CATEGORIES.BUFFER + 'initial-buffer-
TESTCASES.BUFFER.TARGET = TESTCASES.CATEGORIES.BUFFER + 'buffer-target';

TESTCASES.FEATURE_SUPPORT.EMSG_TRIGGERED = TESTCASES.CATEGORIES.FEATURE_SUPPORT + 'emsg-triggered';
TESTCASES.FEATURE_SUPPORT.MPD_PATCHING = TESTCASES.CATEGORIES.FEATURE_SUPPORT + 'mpd-patching';
TESTCASES.FEATURE_SUPPORT.CMCD = TESTCASES.CATEGORIES.FEATURE_SUPPORT + 'cmcd';

TESTCASES.LIVE.CATCHUP = TESTCASES.CATEGORIES.LIVE + 'latency-catchup';
TESTCASES.LIVE.DELAY = TESTCASES.CATEGORIES.LIVE + 'live-delay';
Expand All @@ -150,7 +152,6 @@ TESTCASES.PLAYBACK_ADVANCED.ATTACH_AT_NON_ZERO = TESTCASES.CATEGORIES.PLAYBACK_A
TESTCASES.PLAYBACK_ADVANCED.ATTACH_WITH_POSIX = TESTCASES.CATEGORIES.PLAYBACK_ADVANCED + 'attach-with-posix';
TESTCASES.PLAYBACK_ADVANCED.MPD_ANCHOR = TESTCASES.CATEGORIES.PLAYBACK_ADVANCED + 'mpd-anchor';
TESTCASES.PLAYBACK_ADVANCED.MULTIPERIOD_PLAYBACK = TESTCASES.CATEGORIES.PLAYBACK_ADVANCED + 'multiperiod-playback';
TESTCASES.PLAYBACK_ADVANCED.CMCD = TESTCASES.CATEGORIES.PLAYBACK_ADVANCED + 'cmcd';
TESTCASES.PLAYBACK_ADVANCED.PRELOAD = TESTCASES.CATEGORIES.PLAYBACK_ADVANCED + 'preload';

TESTCASES.TEXT.INITIAL = TESTCASES.CATEGORIES.TEXT + 'initial-text';
Expand Down
Expand Up @@ -9,7 +9,7 @@ import {
} from '../common/common.js';
import {expect} from 'chai';

const TESTCASE = Constants.TESTCASES.PLAYBACK_ADVANCED.CMCD;
const TESTCASE = Constants.TESTCASES.FEATURE_SUPPORT.CMCD;

Utils.getTestvectorsForTestcase(TESTCASE).forEach((item) => {
const mpd = item.url;
Expand Down
1 change: 0 additions & 1 deletion test/functional/test/feature-support/emsg-triggered.js
@@ -1,4 +1,3 @@
import DashJsAdapter from '../../adapter/DashJsAdapter.js';
import Constants from '../../src/Constants.js';
import Utils from '../../src/Utils.js';
import {expect} from 'chai'
Expand Down
55 changes: 55 additions & 0 deletions test/functional/test/feature-support/mpd-patching.js
@@ -0,0 +1,55 @@
import Constants from '../../src/Constants.js';
import Utils from '../../src/Utils.js';
import {expect} from 'chai'
import {checkIsPlaying, checkIsProgressing, checkNoCriticalErrors, initializeDashJsAdapter} from '../common/common.js';

const TESTCASE = Constants.TESTCASES.FEATURE_SUPPORT.MPD_PATCHING;

Utils.getTestvectorsForTestcase(TESTCASE).forEach((item) => {
const mpd = item.url;

describe(`${TESTCASE} - ${item.name} - ${mpd}`, function () {

let playerAdapter

before(function () {
if (item.type === Constants.CONTENT_TYPES.VOD || !item.testdata || !item.testdata.mpdPatching) {
this.skip();
}
playerAdapter = initializeDashJsAdapter(item, mpd);
})

after(() => {
if (playerAdapter) {
playerAdapter.destroy();
}
})

it(`Checking playing state`, async () => {
await checkIsPlaying(playerAdapter, true);
})

it(`Checking progressing state`, async () => {
await checkIsProgressing(playerAdapter);
});

it(`Two consecutive manifest updates shall be of type Patch`, async () => {
const manifest = playerAdapter.getManifest();
const minimumUpdatePeriodInMs = parseInt(manifest.minimumUpdatePeriod) * 1000;

let manifestUpdateEvent = await playerAdapter.waitForEventAndGetPayload(minimumUpdatePeriodInMs * 2, 'internalManifestLoaded')
expect(manifestUpdateEvent.manifest.tagName).to.be.equal('Patch')
manifestUpdateEvent = await playerAdapter.waitForEventAndGetPayload(minimumUpdatePeriodInMs * 2, 'internalManifestLoaded')
expect(manifestUpdateEvent.manifest.tagName).to.be.equal('Patch')
});

it(`Should still be progressing`, async () => {
await checkIsProgressing(playerAdapter);
});

it(`Expect no critical errors to be thrown`, () => {
checkNoCriticalErrors(playerAdapter);
})

})
})

0 comments on commit 0837a99

Please sign in to comment.