Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature enable low latency #3684

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
637768a
Move ESLint check to prod config
dsilhavy Jun 7, 2021
f3f1773
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 8, 2021
1fdabd5
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 8, 2021
0934482
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 9, 2021
468944c
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 11, 2021
fe506cb
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 11, 2021
f99f65f
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 11, 2021
4d464fe
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 14, 2021
2f1d351
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 18, 2021
5f36c4b
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 18, 2021
6a8cbad
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 25, 2021
3fb5591
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 26, 2021
37f8408
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Jun 26, 2021
a6046fe
Enable low latency streaming automatically if availabilityTimeComplet…
dsilhavy Jun 26, 2021
a185b54
Fix linting error
dsilhavy Jun 26, 2021
3daa5f8
Merge branch 'development' of https://github.com/Dash-Industry-Forum/…
dsilhavy Sep 8, 2021
b6a7ee8
Add settings flag to enable/disable low latency activation via MPD pa…
dsilhavy Sep 8, 2021
d173e38
Set maxDrift to 12 seconds
dsilhavy Sep 8, 2021
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
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ declare namespace dashjs {
abandonLoadTimeout?: number,
wallclockTimeUpdateInterval?: number,
lowLatencyEnabled?: boolean,
lowLatencyEnabledByManifest?: boolean,
manifestUpdateRetryInterval?: number,
cacheInitSegments?: boolean,
eventControllerRefreshDelay?: number,
Expand Down
40 changes: 25 additions & 15 deletions samples/dash-if-reference-player/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,8 +682,16 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'

$scope.togglelowLatencyMode = function () {
$scope.player.updateSettings({
'streaming': {
'lowLatencyEnabled': $scope.lowLatencyModeSelected
streaming: {
lowLatencyEnabled: $scope.lowLatencyModeSelected
}
});
};

$scope.toggleLowLatencyByManifestMode = function () {
$scope.player.updateSettings({
streaming: {
lowLatencyEnabledByManifest: $scope.lowLatencyEnabledByManifest
}
});
};
Expand Down Expand Up @@ -776,16 +784,17 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
}

var config = {
'streaming': {
'buffer': {
'stableBufferTime': $scope.defaultStableBufferDelay,
'bufferTimeAtTopQuality': $scope.defaultBufferTimeAtTopQuality,
'bufferTimeAtTopQualityLongForm': $scope.defaultBufferTimeAtTopQualityLongForm,
streaming: {
buffer: {
stableBufferTime: $scope.defaultStableBufferDelay,
bufferTimeAtTopQuality: $scope.defaultBufferTimeAtTopQuality,
bufferTimeAtTopQualityLongForm: $scope.defaultBufferTimeAtTopQualityLongForm,
},
'delay': {
'liveDelay': $scope.defaultLiveDelay
delay: {
liveDelay: $scope.defaultLiveDelay
},
'lowLatencyEnabled': $scope.lowLatencyModeSelected,
lowLatencyEnabled: $scope.lowLatencyModeSelected,
lowLatencyEnabledByManifest: $scope.lowLatencyEnabledByManifest,
abr: {},
cmcd: {}
}
Expand Down Expand Up @@ -1008,7 +1017,7 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
protectionData[input.drmKeySystem]['httpRequestHeaders'] = input.httpRequestHeaders;
}
} else {
alert("Kid and Key must be specified!");
alert('Kid and Key must be specified!');
}

} else {
Expand All @@ -1018,15 +1027,15 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
// Check if DRM-Priorisation is enabled
if (this.prioritiesEnabled) {
protectionData[input.drmKeySystem] = {
"serverURL": input.licenseServerUrl,
"priority": parseInt(input.priority)
'serverURL': input.licenseServerUrl,
'priority': parseInt(input.priority)
}
if (!angular.equals(input.httpRequestHeaders, {}))
protectionData[input.drmKeySystem]['httpRequestHeaders'] = input.httpRequestHeaders;

} else {
protectionData[input.drmKeySystem] = {
"serverURL": input.licenseServerUrl,
'serverURL': input.licenseServerUrl,
}
}

Expand All @@ -1052,7 +1061,7 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
}

} else {
console.log(input.licenseServerUrl, "is not a valid url!")
console.log(input.licenseServerUrl, 'is not a valid url!')
}

}
Expand Down Expand Up @@ -1535,6 +1544,7 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
$scope.defaultBufferTimeAtTopQuality = currentConfig.streaming.buffer.bufferTimeAtTopQuality;
$scope.defaultBufferTimeAtTopQualityLongForm = currentConfig.streaming.buffer.bufferTimeAtTopQualityLongForm;
$scope.lowLatencyModeSelected = currentConfig.streaming.lowLatencyEnabled;
$scope.lowLatencyEnabledByManifest = currentConfig.streaming.lowLatencyEnabledByManifest;
$scope.liveCatchupEnabled = currentConfig.streaming.liveCatchup.enabled;
}

Expand Down
7 changes: 2 additions & 5 deletions samples/dash-if-reference-player/app/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,15 @@
"url": "https://akamaibroadcasteruseast.akamaized.net/cmaf/live/657078/akasource/out.mpd",
"name": "Akamai Low Latency Stream (Single Rate)",
"bufferConfig": {
"lowLatencyMode": true,
"liveDelay": 3
"liveDelay": 3,
"lowLatencyMode": true
},
"provider": "akamai"
},
{
"url": "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd",
"name": "Akamai Low Latency Stream (Multi Rate)",
"bufferConfig": {
"lowLatencyMode": true,
"liveDelay": 3
},
"provider": "akamai"
Expand All @@ -303,7 +302,6 @@
"url": "https://livesim.dashif.org/livesim/chunkdur_1/ato_7/testpic4_8s/Manifest300.mpd",
"name": "Low Latency (Single-Rate) (livesim-chunked)",
"bufferConfig": {
"lowLatencyMode": true,
"liveDelay": 4
},
"provider": "dashif"
Expand All @@ -312,7 +310,6 @@
"url": "https://livesim.dashif.org/livesim/chunkdur_1/ato_7/testpic4_8s/Manifest.mpd",
"name": "Low Latency (Multi-Rate) (livesim-chunked)",
"bufferConfig": {
"lowLatencyMode": true,
"liveDelay": 4
},
"provider": "dashif"
Expand Down
8 changes: 7 additions & 1 deletion samples/dash-if-reference-player/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,13 @@
title="Enable low latency mode">
<input type="checkbox" id="lowLatencyModeCB" ng-model="lowLatencyModeSelected"
ng-change="togglelowLatencyMode()" ng-checked="lowLatencyModeSelected">
Low Latency Mode
Low latency mode
</label>
<label class="topcoat-checkbox" data-toggle="tooltip" data-placement="right"
title="Enable low latency mode by MPD attribute 'availabilityTimeComplete' ">
<input type="checkbox" id="lowLatencyModeEnabledByManifestCB" ng-model="lowLatencyEnabledByManifest"
ng-change="toggleLowLatencyByManifestMode()" ng-checked="lowLatencyEnabledByManifest">
Enable low latency mode by MPD
</label>
<label class="topcoat-checkbox" data-toggle="tooltip" data-placement="right"
title="Enable catchup mode for non low latency streams">
Expand Down
15 changes: 10 additions & 5 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* abandonLoadTimeout: 10000,
* wallclockTimeUpdateInterval: 100,
* lowLatencyEnabled: false,
* lowLatencyEnabledByManifest: true,
* manifestUpdateRetryInterval: 100,
* cacheInitSegments: true,
* eventControllerRefreshDelay: 100,
Expand Down Expand Up @@ -129,7 +130,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* },
* liveCatchup: {
* minDrift: 0.02,
* maxDrift: 0,
* maxDrift: 12,
* playbackRate: 0.5,
* latencyThreshold: 60,
* playbackBufferMin: 0.5,
Expand Down Expand Up @@ -377,6 +378,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* @property {boolean} [useManifestDateHeaderTimeSource=true]
* Allows you to enable the use of the Date Header, if exposed with CORS, as a timing source for live edge detection.
*
* The use of the date header will happen only after the other timing source that take precedence fail or are omitted as described.
* @property {number} [backgroundAttempts=2]
* Number of synchronization attempts to perform in the background after an initial synchronization request has been done. This is used to verify that the derived client-server offset is correct.
*
Expand Down Expand Up @@ -434,7 +436,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* LowLatencyMinDrift should be provided in seconds, and it uses values between 0.0 and 0.5.
*
* Note: Catch-up mechanism is only applied when playing low latency live streams.
* @property {number} [maxDrift=0]
* @property {number} [maxDrift=12]
* Use this method to set the maximum latency deviation allowed before dash.js to do a seeking to live position.
*
* In low latency mode, when the difference between the measured latency and the target one, as an absolute number, is higher than the one sets with this method, then dash.js does a seek to live edge position minus the target live delay.
Expand Down Expand Up @@ -644,9 +646,11 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* @property {number} [wallclockTimeUpdateInterval=50]
* How frequently the wallclockTimeUpdated internal event is triggered (in milliseconds).
* @property {boolean} [lowLatencyEnabled=false]
* Enable or disable low latency mode.
* Manually enable or disable low latency mode.
*
* @property {boolean} [lowLatencyEnabledByManifest=true]
* If this value is set to true we enable the low latency mode based on MPD attributes: Specifically in case "availabilityTimeComplete" of the current representation is set to false.
*
* The use of the date header will happen only after the other timing source that take precedence fail or are omitted as described.
* @property {number} [manifestUpdateRetryInterval=100]
* For live streams, set the interval-frequency in milliseconds at which dash.js will check if the current manifest is still processed before downloading the next manifest once the minimumUpdatePeriod time has.
* @property {boolean} [cacheInitSegments=true]
Expand Down Expand Up @@ -743,6 +747,7 @@ function Settings() {
abandonLoadTimeout: 10000,
wallclockTimeUpdateInterval: 100,
lowLatencyEnabled: false,
lowLatencyEnabledByManifest: true,
manifestUpdateRetryInterval: 100,
cacheInitSegments: false,
eventControllerRefreshDelay: 150,
Expand Down Expand Up @@ -812,7 +817,7 @@ function Settings() {
},
liveCatchup: {
minDrift: 0.02,
maxDrift: 0,
maxDrift: 12,
playbackRate: 0.5,
latencyThreshold: 60,
playbackBufferMin: 0.5,
Expand Down
6 changes: 0 additions & 6 deletions src/dash/SegmentBaseLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ function SegmentBaseLoader() {
boxParser,
requestModifier,
dashMetrics,
settings,
mediaPlayerModel,
urlLoader,
errors,
Expand All @@ -62,7 +61,6 @@ function SegmentBaseLoader() {
dashMetrics: dashMetrics,
mediaPlayerModel: mediaPlayerModel,
requestModifier: requestModifier,
useFetch: settings ? settings.get().streaming.lowLatencyEnabled : null,
boxParser: boxParser,
errors: errors,
urlUtils: urlUtils,
Expand All @@ -88,10 +86,6 @@ function SegmentBaseLoader() {
errHandler = config.errHandler;
}

if (config.settings) {
settings = config.settings;
}

if (config.boxParser) {
boxParser = config.boxParser;
}
Expand Down
3 changes: 0 additions & 3 deletions src/dash/WebmSegmentBaseLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ function WebmSegmentBaseLoader() {
dashMetrics,
mediaPlayerModel,
urlLoader,
settings,
errors,
baseURLController;

Expand Down Expand Up @@ -94,7 +93,6 @@ function WebmSegmentBaseLoader() {
dashMetrics: dashMetrics,
mediaPlayerModel: mediaPlayerModel,
requestModifier: requestModifier,
useFetch: settings ? settings.get().streaming.lowLatencyEnabled : null,
errors: errors
});
}
Expand All @@ -107,7 +105,6 @@ function WebmSegmentBaseLoader() {
dashMetrics = config.dashMetrics;
mediaPlayerModel = config.mediaPlayerModel;
errHandler = config.errHandler;
settings = config.settings;
errors = config.errors;
logger = config.debug.getLogger(instance);
requestModifier = config.requestModifier;
Expand Down
19 changes: 13 additions & 6 deletions src/dash/controllers/RepresentationController.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ function RepresentationController(config) {

voAvailableRepresentations = availableRepresentations;

currentVoRepresentation = getRepresentationForQuality(quality);
const rep = getRepresentationForQuality(quality)
_setCurrentVoRepresentation(rep);
realAdaptation = newRealAdaptation;

if (type !== Constants.VIDEO && type !== Constants.AUDIO && (type !== Constants.TEXT || !isFragmented)) {
Expand Down Expand Up @@ -203,7 +204,7 @@ function RepresentationController(config) {
return representation;
}

function addRepresentationSwitch() {
function _addRepresentationSwitch() {
checkConfig();
const now = new Date();
const currentRepresentation = getCurrentRepresentation();
Expand All @@ -214,9 +215,10 @@ function RepresentationController(config) {

eventBus.trigger(MediaPlayerEvents.REPRESENTATION_SWITCH, {
mediaType: type,
streamId: streamInfo.id,
currentRepresentation,
numberOfRepresentations: voAvailableRepresentations.length
})
}, { streamId: streamInfo.id, mediaType: type })
}

function getRepresentationForQuality(quality) {
Expand Down Expand Up @@ -285,15 +287,20 @@ function RepresentationController(config) {
repSwitch = dashMetrics.getCurrentRepresentationSwitch(getCurrentRepresentation().adaptation.type);

if (!repSwitch) {
addRepresentationSwitch();
_addRepresentationSwitch();
}
endDataUpdate();
}
}

function prepareQualityChange(newQuality) {
currentVoRepresentation = getRepresentationForQuality(newQuality);
addRepresentationSwitch();
const newRep = getRepresentationForQuality(newQuality)
_setCurrentVoRepresentation(newRep);
_addRepresentationSwitch();
}

function _setCurrentVoRepresentation(value) {
currentVoRepresentation = value;
}

function onManifestValidityChanged(e) {
Expand Down
1 change: 0 additions & 1 deletion src/streaming/FragmentLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ function FragmentLoader(config) {
dashMetrics: config.dashMetrics,
mediaPlayerModel: config.mediaPlayerModel,
requestModifier: config.requestModifier,
useFetch: config.settings.get().streaming.lowLatencyEnabled,
urlUtils: urlUtils,
constants: Constants,
boxParser: config.boxParser,
Expand Down
1 change: 0 additions & 1 deletion src/streaming/ManifestLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ function ManifestLoader(config) {
dashMetrics: config.dashMetrics,
mediaPlayerModel: config.mediaPlayerModel,
requestModifier: config.requestModifier,
useFetch: config.settings.get().streaming.lowLatencyEnabled,
urlUtils: urlUtils,
constants: Constants,
dashConstants: DashConstants,
Expand Down
1 change: 0 additions & 1 deletion src/streaming/XlinkLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ function XlinkLoader(config) {
dashMetrics: config.dashMetrics,
mediaPlayerModel: config.mediaPlayerModel,
requestModifier: config.requestModifier,
useFetch: config.settings ? config.settings.get().streaming.lowLatencyEnabled : null,
errors: Errors
});

Expand Down
25 changes: 25 additions & 0 deletions src/streaming/controllers/PlaybackController.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ function PlaybackController() {
eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, this);
eventBus.on(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, this, { priority: EventBus.EVENT_PRIORITY_HIGH });
eventBus.on(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, this);
eventBus.on(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, this);

if (playOnceInitialized) {
playOnceInitialized = false;
Expand Down Expand Up @@ -353,6 +354,7 @@ function PlaybackController() {
eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, this);
eventBus.off(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, this);
eventBus.off(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, this);
eventBus.off(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, this);
videoModel.setPlaybackRate(1.0, true);
stopUpdatingWallclockTime();
removeAllListeners();
Expand Down Expand Up @@ -916,6 +918,29 @@ function PlaybackController() {
_checkEnableLowLatency(e.mediaInfo);
}

/**
* We enable low latency playback if for the current representation availabilityTimeComplete is set to false
* @param e
* @private
*/
function _onRepresentationSwitch(e) {
const activeStreamInfo = streamController.getActiveStreamInfo();
if (!settings.get().streaming.lowLatencyEnabledByManifest || !e || !activeStreamInfo || !e.currentRepresentation || !e.streamId || e.streamId !== activeStreamInfo.id || !e.mediaType || (e.mediaType !== Constants.VIDEO && e.mediaType !== Constants.AUDIO)) {
return;
}

const lowLatencyEnabled = !e.currentRepresentation.availabilityTimeComplete;

if (lowLatencyEnabled) {
settings.update({
streaming: {
lowLatencyEnabled: lowLatencyEnabled
}
});
}
}


function _checkEnableLowLatency(mediaInfo) {
if (mediaInfo && mediaInfo.supplementalProperties &&
mediaInfo.supplementalProperties[Constants.SUPPLEMENTAL_PROPERTY_LL_SCHEME] === 'true') {
Expand Down
Loading