From 12fafca9d305833a0b5482bcd4c6e8d8fa8ecabc Mon Sep 17 00:00:00 2001 From: dsilhavy Date: Mon, 23 Mar 2020 16:56:04 +0100 Subject: [PATCH] Bugfix live edge calculation (#3201) * Improve live delay calculation * Update settings * Add fragment duration as delay fallback * Update reference client config * r parameter takes precedence over suggestedPresentationDelay * Update unit tests for live delay fragment count and suggested presentation delay * Use four times the minbuffertime instead of two times ofr live edge calculation * Set liveDelayFragmentCount to NaN by default --- .../dash-if-reference-player/dashjs_config.json | 4 ++-- src/core/Settings.js | 8 ++++---- src/mss/parser/MssParser.js | 3 ++- src/streaming/controllers/PlaybackController.js | 17 +++++++++-------- test/unit/streaming.MediaPlayer.js | 8 ++++---- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/samples/dash-if-reference-player/dashjs_config.json b/samples/dash-if-reference-player/dashjs_config.json index 6b1b076977..f9811a8386 100644 --- a/samples/dash-if-reference-player/dashjs_config.json +++ b/samples/dash-if-reference-player/dashjs_config.json @@ -5,7 +5,7 @@ "streaming": { "metricsMaxListDepth": 50, "abandonLoadTimeout": 10000, - "liveDelayFragmentCount": 4, + "liveDelayFragmentCount": null, "liveDelay": null, "scheduleWhilePaused": true, "fastSwitchEnabled": true, @@ -22,7 +22,7 @@ "lowLatencyEnabled": false, "keepProtectionMediaKeys": false, "useManifestDateHeaderTimeSource": true, - "useSuggestedPresentationDelay": false, + "useSuggestedPresentationDelay": true, "manifestUpdateRetryInterval": 100, "liveCatchUpMinDrift": 0.02, "liveCatchUpMaxDrift": 0, diff --git a/src/core/Settings.js b/src/core/Settings.js index 60413673ef..71d0d17a3a 100644 --- a/src/core/Settings.js +++ b/src/core/Settings.js @@ -54,7 +54,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * streaming: { * metricsMaxListDepth: 1000, * abandonLoadTimeout: 10000, - * liveDelayFragmentCount: 4, + * liveDelayFragmentCount: NaN, * liveDelay: null, * scheduleWhilePaused: true, * fastSwitchEnabled: false, @@ -203,7 +203,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * @property {number} [abandonLoadTimeout=10000] * A timeout value in seconds, which during the ABRController will block switch-up events. * This will only take effect after an abandoned fragment event occurs. - * @property {number} [liveDelayFragmentCount=4] + * @property {number} [liveDelayFragmentCount=NaN] * Changing this value will lower or increase live stream latency. The detected segment duration will be multiplied by this value * to define a time in seconds to delay a live stream from the live edge. Lowering this value will lower latency but may decrease * the player's ability to build a stable buffer. @@ -373,7 +373,7 @@ function Settings() { streaming: { metricsMaxListDepth: 1000, abandonLoadTimeout: 10000, - liveDelayFragmentCount: 4, + liveDelayFragmentCount: NaN, liveDelay: null, scheduleWhilePaused: true, fastSwitchEnabled: false, @@ -390,7 +390,7 @@ function Settings() { lowLatencyEnabled: false, keepProtectionMediaKeys: false, useManifestDateHeaderTimeSource: true, - useSuggestedPresentationDelay: false, + useSuggestedPresentationDelay: true, useAppendWindowEnd: true, manifestUpdateRetryInterval: 100, liveCatchUpMinDrift: 0.02, diff --git a/src/mss/parser/MssParser.js b/src/mss/parser/MssParser.js index 83da5c60c2..a03891fdbc 100644 --- a/src/mss/parser/MssParser.js +++ b/src/mss/parser/MssParser.js @@ -715,7 +715,8 @@ function MssParser(config) { if (manifest.type === 'dynamic') { let targetLiveDelay = mediaPlayerModel.getLiveDelay(); if (!targetLiveDelay) { - targetLiveDelay = segmentDuration * settings.get().streaming.liveDelayFragmentCount; + const liveDelayFragmentCount = settings.get().streaming.liveDelayFragmentCount !== null && !isNaN(settings.get().streaming.liveDelayFragmentCount) ? settings.get().streaming.liveDelayFragmentCount : 4; + targetLiveDelay = segmentDuration * liveDelayFragmentCount; } let targetDelayCapping = Math.max(manifest.timeShiftBufferDepth - 10/*END_OF_PLAYLIST_PADDING*/, manifest.timeShiftBufferDepth / 2); let liveDelay = Math.min(targetDelayCapping, targetLiveDelay); diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 8586ce506a..3369d06e46 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -240,19 +240,20 @@ function PlaybackController() { let suggestedPresentationDelay = adapter.getSuggestedPresentationDelay(); - if (settings.get().streaming.useSuggestedPresentationDelay && suggestedPresentationDelay !== null) { - delay = suggestedPresentationDelay; - } else if (settings.get().streaming.lowLatencyEnabled) { + if (settings.get().streaming.lowLatencyEnabled) { delay = 0; } else if (mediaPlayerModel.getLiveDelay()) { delay = mediaPlayerModel.getLiveDelay(); // If set by user, this value takes precedence + } else if (settings.get().streaming.liveDelayFragmentCount !== null && !isNaN(settings.get().streaming.liveDelayFragmentCount) && !isNaN(fragmentDuration)) { + delay = fragmentDuration * settings.get().streaming.liveDelayFragmentCount; } else if (r) { delay = r; - } - else if (!isNaN(fragmentDuration)) { - delay = fragmentDuration * settings.get().streaming.liveDelayFragmentCount; + } else if (settings.get().streaming.useSuggestedPresentationDelay === true && suggestedPresentationDelay !== null && !isNaN(suggestedPresentationDelay) && suggestedPresentationDelay > 0) { + delay = suggestedPresentationDelay; + } else if (!isNaN(fragmentDuration)) { + delay = fragmentDuration * 4; } else { - delay = streamInfo.manifestInfo.minBufferTime * 2; + delay = streamInfo.manifestInfo.minBufferTime * 4; } startTime = adapter.getAvailabilityStartTime(); @@ -758,7 +759,7 @@ function PlaybackController() { const minDelay = 1.2 * e.request.duration; if (minDelay > mediaPlayerModel.getLiveDelay()) { logger.warn('Browser does not support fetch API with StreamReader. Increasing live delay to be 20% higher than segment duration:', minDelay.toFixed(2)); - const s = { streaming: { liveDelay: minDelay } }; + const s = {streaming: {liveDelay: minDelay}}; settings.update(s); } } diff --git a/test/unit/streaming.MediaPlayer.js b/test/unit/streaming.MediaPlayer.js index 142de7ce89..c702b55910 100644 --- a/test/unit/streaming.MediaPlayer.js +++ b/test/unit/streaming.MediaPlayer.js @@ -602,7 +602,7 @@ describe('MediaPlayer', function () { it('should configure LiveDelayFragmentCount', function () { let liveDelayFragmentCount = player.getSettings().streaming.liveDelayFragmentCount; - expect(liveDelayFragmentCount).to.equal(4); + expect(liveDelayFragmentCount).to.be.NaN; // jshint ignore:line player.updateSettings({'streaming': { 'liveDelayFragmentCount': 5 }}); @@ -612,12 +612,12 @@ describe('MediaPlayer', function () { it('should configure useSuggestedPresentationDelay', function () { let useSuggestedPresentationDelay = player.getSettings().streaming.useSuggestedPresentationDelay; - expect(useSuggestedPresentationDelay).to.be.false; // jshint ignore:line + expect(useSuggestedPresentationDelay).to.be.true; // jshint ignore:line - player.updateSettings({'streaming': { 'useSuggestedPresentationDelay': true }}); + player.updateSettings({'streaming': { 'useSuggestedPresentationDelay': false }}); useSuggestedPresentationDelay = player.getSettings().streaming.useSuggestedPresentationDelay; - expect(useSuggestedPresentationDelay).to.be.true; // jshint ignore:line + expect(useSuggestedPresentationDelay).to.be.false; // jshint ignore:line }); it('should configure scheduleWhilePaused', function () {