From ba15dd43900692262bd6296d7acfc5642fb09dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Tue, 4 Jul 2023 12:41:20 +0200 Subject: [PATCH 1/9] feat: Parse ServiceDescription information from MPD --- lib/dash/dash_parser.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index aff6e43444..baa9df732c 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -497,6 +497,29 @@ shaka.dash.DashParser = class { this.updatePeriod_ = this.minTotalAvailabilityTimeOffset_; } + const serviceDescriptionNode = XmlUtils.findChild(mpd, + 'ServiceDescription'); + const serviceDescription = {}; + + const latencyNode = XmlUtils.findChild(serviceDescriptionNode, 'Latency'); + if (latencyNode) { + serviceDescription.latency = { + target: parseInt(latencyNode.getAttribute('target'), 10) / 1000, + max: parseInt(latencyNode.getAttribute('max'), 10) / 1000, + min: parseInt(latencyNode.getAttribute('min'), 10) / 1000, + referenceId: parseInt(latencyNode.getAttribute('referenceId'), 10), + }; + } + + const playbackRateNode = XmlUtils.findChild(serviceDescriptionNode, + 'PlaybackRate'); + if (playbackRateNode) { + serviceDescription.playbackRate = { + max: parseFloat(playbackRateNode.getAttribute('max'), 10), + min: parseFloat(playbackRateNode.getAttribute('min'), 10), + }; + } + // These steps are not done on manifest update. if (!this.manifest_) { this.manifest_ = { @@ -509,6 +532,7 @@ shaka.dash.DashParser = class { sequenceMode: this.config_.dash.sequenceMode, ignoreManifestTimestampsInSegmentsMode: false, type: shaka.media.ManifestParser.DASH, + serviceDescription: serviceDescription, }; // We only need to do clock sync when we're using presentation start From a5ae250d7d4e7bad35e372848e13b6b68c997ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Tue, 4 Jul 2023 12:41:45 +0200 Subject: [PATCH 2/9] feat: Use serviceDescription to sync live stream --- lib/player.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/player.js b/lib/player.js index 82a09f3b2f..85afcab8d1 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2278,7 +2278,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { 'arbitrary language initially'); } - if (this.isLive() && this.config_.streaming.liveSync) { + if (this.isLive() && (this.config_.streaming.liveSync || + this.manifest_.serviceDescription)) { const onTimeUpdate = () => this.onTimeUpdate_(); this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate); } @@ -5728,8 +5729,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // Bad stream? return; } - const liveSyncMaxLatency = this.config_.streaming.liveSyncMaxLatency; - const liveSyncPlaybackRate = this.config_.streaming.liveSyncPlaybackRate; + + // Should use serviceDescription if they exist. + const liveSyncMaxLatency = this.manifest_.serviceDescription.latency ? + this.manifest_.serviceDescription.latency.max : + this.config_.streaming.liveSyncMaxLatency; + const liveSyncPlaybackRate = + this.manifest_.serviceDescription.playbackRate ? + this.manifest_.serviceDescription.playbackRate.max : + this.config_.streaming.liveSyncPlaybackRate; const playbackRate = this.video_.playbackRate; const latency = seekRange.end - this.video_.currentTime; let offset = 0; @@ -5747,6 +5755,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if ((latency - offset) > liveSyncMaxLatency) { if (playbackRate != liveSyncPlaybackRate) { + shaka.log.debug('Latency (' + latency + + 's) is greater than liveSyncMaxLatency. ' + + 'Updating playbackRate to ' + liveSyncPlaybackRate); this.trickPlay(liveSyncPlaybackRate); } } else if (playbackRate !== 1 && playbackRate !== 0) { From 5480e421a213e77a7d7163c04501de1e62f939b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 09:35:09 +0200 Subject: [PATCH 3/9] feat: Remove unused service description properties --- lib/player.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/player.js b/lib/player.js index 85afcab8d1..5642b61d83 100644 --- a/lib/player.js +++ b/lib/player.js @@ -5731,12 +5731,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } // Should use serviceDescription if they exist. - const liveSyncMaxLatency = this.manifest_.serviceDescription.latency ? - this.manifest_.serviceDescription.latency.max : - this.config_.streaming.liveSyncMaxLatency; + const liveSyncMaxLatency = + this.manifest_ && this.manifest_.serviceDescription.maxLatency ? + this.manifest_.serviceDescription.maxLatency : + this.config_.streaming.liveSyncMaxLatency; const liveSyncPlaybackRate = - this.manifest_.serviceDescription.playbackRate ? - this.manifest_.serviceDescription.playbackRate.max : + this.manifest_ && this.manifest_.serviceDescription.maxPlaybackRate ? + this.manifest_.serviceDescription.maxPlaybackRate : this.config_.streaming.liveSyncPlaybackRate; const playbackRate = this.video_.playbackRate; const latency = seekRange.end - this.video_.currentTime; @@ -5755,8 +5756,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if ((latency - offset) > liveSyncMaxLatency) { if (playbackRate != liveSyncPlaybackRate) { - shaka.log.debug('Latency (' + latency + - 's) is greater than liveSyncMaxLatency. ' + + shaka.log.debug('Latency (' + latency + 's) ' + + 'is greater than liveSyncMaxLatency (' + liveSyncMaxLatency + 's).' + 'Updating playbackRate to ' + liveSyncPlaybackRate); this.trickPlay(liveSyncPlaybackRate); } From fa87ceaa77285a0ce2d6ffd04d8d039b212db5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 09:35:28 +0200 Subject: [PATCH 4/9] feat: Create function to parse service description --- lib/dash/dash_parser.js | 55 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index baa9df732c..e4b3439188 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -497,29 +497,6 @@ shaka.dash.DashParser = class { this.updatePeriod_ = this.minTotalAvailabilityTimeOffset_; } - const serviceDescriptionNode = XmlUtils.findChild(mpd, - 'ServiceDescription'); - const serviceDescription = {}; - - const latencyNode = XmlUtils.findChild(serviceDescriptionNode, 'Latency'); - if (latencyNode) { - serviceDescription.latency = { - target: parseInt(latencyNode.getAttribute('target'), 10) / 1000, - max: parseInt(latencyNode.getAttribute('max'), 10) / 1000, - min: parseInt(latencyNode.getAttribute('min'), 10) / 1000, - referenceId: parseInt(latencyNode.getAttribute('referenceId'), 10), - }; - } - - const playbackRateNode = XmlUtils.findChild(serviceDescriptionNode, - 'PlaybackRate'); - if (playbackRateNode) { - serviceDescription.playbackRate = { - max: parseFloat(playbackRateNode.getAttribute('max'), 10), - min: parseFloat(playbackRateNode.getAttribute('min'), 10), - }; - } - // These steps are not done on manifest update. if (!this.manifest_) { this.manifest_ = { @@ -532,7 +509,7 @@ shaka.dash.DashParser = class { sequenceMode: this.config_.dash.sequenceMode, ignoreManifestTimestampsInSegmentsMode: false, type: shaka.media.ManifestParser.DASH, - serviceDescription: serviceDescription, + serviceDescription: this.parseServiceDescription_(mpd), }; // We only need to do clock sync when we're using presentation start @@ -571,6 +548,36 @@ shaka.dash.DashParser = class { this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_); } + /** + * Reads and parses service description properties. + * + * @param {!Element} mpd + * @return {!shaka.extern.ServiceDescription} + * @private + */ + parseServiceDescription_(mpd) { + const XmlUtils = shaka.util.XmlUtils; + const serviceDescription = {}; + const elem = XmlUtils.findChild(mpd, 'ServiceDescription'); + + if (elem) { + const latencyNode = XmlUtils.findChild(elem, 'Latency'); + if (latencyNode) { + serviceDescription.maxLatency = parseInt( + latencyNode.getAttribute('max'), 10) / 1000; + } + + const playbackRateNode = XmlUtils.findChild(elem, + 'PlaybackRate'); + if (playbackRateNode) { + serviceDescription.maxPlaybackRate = parseFloat( + playbackRateNode.getAttribute('max')); + } + } + + return serviceDescription; + } + /** * Reads and parses the periods from the manifest. This first does some * partial parsing so the start and duration is available when parsing From 0aea1479b61915e0aec1ee8ac7bbdd388a70b059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 09:35:44 +0200 Subject: [PATCH 5/9] feat: Update documentation --- externs/shaka/manifest.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/externs/shaka/manifest.js b/externs/shaka/manifest.js index 9615f308bc..76c507c204 100644 --- a/externs/shaka/manifest.js +++ b/externs/shaka/manifest.js @@ -20,7 +20,8 @@ * minBufferTime: number, * sequenceMode: boolean, * ignoreManifestTimestampsInSegmentsMode: boolean, - * type: string + * type: string, + * serviceDescription: !shaka.extern.ServiceDescription * }} * * @description @@ -89,6 +90,10 @@ * @property {string} type * Indicates the type of the manifest. It can be 'HLS' or * 'DASH'. + * @property {!shaka.extern.ServiceDescription} serviceDescription + * Defaults to {}.
+ * The service description for the manifest. Used to adapt playbackRate to + * decrease latency. * * @exportDoc */ @@ -118,6 +123,26 @@ shaka.extern.Manifest; */ shaka.extern.InitDataOverride; +/** + * @typedef {{ + * maxLatency: ?number, + * maxPlaybackRate: ?number + * }} + * + * @description + * Maximum latency and playback rate for a manifest. When max latency is reached + * playbackrate is updated to maxPlaybackRate to decrease latency. + * More information {@link https://dashif.org/docs/CR-Low-Latency-Live-r8.pdf here}. + * + * @property {?number} maxLatency + * Maximum latency in seconds. + * @property {?number} maxPlaybackRate + * Maximum playback rate. + * + * @exportDoc + */ +shaka.extern.ServiceDescription; + /** * @typedef {{ From 77ab035b5e209849a6d3d413580009e8bb6e821d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 09:36:01 +0200 Subject: [PATCH 6/9] feat: Fix lint and test problems --- lib/hls/hls_parser.js | 4 ++++ lib/mss/mss_parser.js | 4 ++++ lib/offline/manifest_converter.js | 4 ++++ test/media/playhead_unit.js | 4 ++++ test/media/streaming_engine_integration.js | 4 ++++ test/test/util/manifest_generator.js | 6 ++++++ test/test/util/streaming_engine_util.js | 4 ++++ 7 files changed, 30 insertions(+) diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 869bcd0456..d17aa6d86c 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -801,6 +801,10 @@ shaka.hls.HlsParser = class { ignoreManifestTimestampsInSegmentsMode: this.config_.hls.ignoreManifestTimestampsInSegmentsMode, type: shaka.media.ManifestParser.HLS, + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, }; this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_); } diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index 0f3260d740..23306dc138 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -376,6 +376,10 @@ shaka.mss.MssParser = class { sequenceMode: this.config_.mss.sequenceMode, ignoreManifestTimestampsInSegmentsMode: false, type: shaka.media.ManifestParser.MSS, + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, }; // This is the first point where we have a meaningful presentation start diff --git a/lib/offline/manifest_converter.js b/lib/offline/manifest_converter.js index b85122c67c..88bf292e62 100644 --- a/lib/offline/manifest_converter.js +++ b/lib/offline/manifest_converter.js @@ -91,6 +91,10 @@ shaka.offline.ManifestConverter = class { sequenceMode: manifestDB.sequenceMode || false, ignoreManifestTimestampsInSegmentsMode: false, type: manifestDB.type || shaka.media.ManifestParser.UNKNOWN, + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, }; } diff --git a/test/media/playhead_unit.js b/test/media/playhead_unit.js index e09ddf3713..f0d3abd675 100644 --- a/test/media/playhead_unit.js +++ b/test/media/playhead_unit.js @@ -136,6 +136,10 @@ describe('Playhead', () => { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, }; config = shaka.util.PlayerConfiguration.createDefault().streaming; diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index 40982e8e20..56bed7ebf4 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -597,6 +597,10 @@ describe('StreamingEngine', () => { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, variants: [{ id: 1, video: { diff --git a/test/test/util/manifest_generator.js b/test/test/util/manifest_generator.js index d766732823..b0cd4d7e75 100644 --- a/test/test/util/manifest_generator.js +++ b/test/test/util/manifest_generator.js @@ -101,6 +101,12 @@ shaka.test.ManifestGenerator.Manifest = class { this.ignoreManifestTimestampsInSegmentsMode = false; /** @type {string} */ this.type = 'UNKNOWN'; + /** @type {!shaka.extern.ServiceDescription} */ + this.serviceDescription = { + maxLatency: null, + maxPlaybackRate: null, + }; + /** @type {shaka.extern.Manifest} */ const foo = this; diff --git a/test/test/util/streaming_engine_util.js b/test/test/util/streaming_engine_util.js index 353565ab90..3c2b8a97fb 100644 --- a/test/test/util/streaming_engine_util.js +++ b/test/test/util/streaming_engine_util.js @@ -286,6 +286,10 @@ shaka.test.StreamingEngineUtil = class { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', + serviceDescription: { + maxLatency: null, + maxPlaybackRate: null, + }, }; /** @type {shaka.extern.Variant} */ From 4dda13bdda5b9cff541b218c0dce10460e3400ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 10:46:12 +0200 Subject: [PATCH 7/9] feat: Add unit testing --- test/dash/dash_parser_manifest_unit.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 9da853692d..9d635cf7d3 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -2556,4 +2556,26 @@ describe('DashParser Manifest', () => { expect(segments[0][1].startTime).toBe(15); expect(segments[1][1].startTime).toBe(15); }); + + describe('Parses ServiceDescription', () => { + it('with PlaybackRate and Latency', async () => { + const source = [ + '', + ' ', + ' ', + ' ', + ' ', + '', + ].join('\n'); + + fakeNetEngine.setResponseText('dummy://foo', source); + + /** @type {shaka.extern.Manifest} */ + const manifest = await parser.start('dummy://foo', playerInterface); + + expect(manifest.serviceDescription.maxLatency).toBe(2); + expect(manifest.serviceDescription.maxPlaybackRate).toBe(1.1); + }); + }); }); From a56418b211b10de3c08b61b32ed07010fef830bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 14:05:02 +0200 Subject: [PATCH 8/9] feat: Set serviceDescription optional --- externs/shaka/manifest.js | 5 ++-- lib/dash/dash_parser.js | 35 ++++++++++++---------- lib/hls/hls_parser.js | 5 +--- lib/mss/mss_parser.js | 5 +--- lib/offline/manifest_converter.js | 5 +--- test/media/playhead_unit.js | 5 +--- test/media/streaming_engine_integration.js | 5 +--- test/test/util/manifest_generator.js | 7 ++--- test/test/util/streaming_engine_util.js | 5 +--- 9 files changed, 29 insertions(+), 48 deletions(-) diff --git a/externs/shaka/manifest.js b/externs/shaka/manifest.js index 76c507c204..67ebeb9965 100644 --- a/externs/shaka/manifest.js +++ b/externs/shaka/manifest.js @@ -21,7 +21,7 @@ * sequenceMode: boolean, * ignoreManifestTimestampsInSegmentsMode: boolean, * type: string, - * serviceDescription: !shaka.extern.ServiceDescription + * serviceDescription: ?shaka.extern.ServiceDescription * }} * * @description @@ -90,8 +90,7 @@ * @property {string} type * Indicates the type of the manifest. It can be 'HLS' or * 'DASH'. - * @property {!shaka.extern.ServiceDescription} serviceDescription - * Defaults to {}.
+ * @property {?shaka.extern.ServiceDescription} serviceDescription * The service description for the manifest. Used to adapt playbackRate to * decrease latency. * diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index e4b3439188..8454130134 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -549,33 +549,36 @@ shaka.dash.DashParser = class { } /** - * Reads and parses service description properties. + * Reads maxLatency and maxPlaybackRate properties from service + * description element. * * @param {!Element} mpd - * @return {!shaka.extern.ServiceDescription} + * @return {?shaka.extern.ServiceDescription} * @private */ parseServiceDescription_(mpd) { const XmlUtils = shaka.util.XmlUtils; - const serviceDescription = {}; const elem = XmlUtils.findChild(mpd, 'ServiceDescription'); - if (elem) { - const latencyNode = XmlUtils.findChild(elem, 'Latency'); - if (latencyNode) { - serviceDescription.maxLatency = parseInt( - latencyNode.getAttribute('max'), 10) / 1000; - } + if (!elem ) { + return null; + } - const playbackRateNode = XmlUtils.findChild(elem, - 'PlaybackRate'); - if (playbackRateNode) { - serviceDescription.maxPlaybackRate = parseFloat( - playbackRateNode.getAttribute('max')); - } + const latencyNode = XmlUtils.findChild(elem, 'Latency'); + const playbackRateNode = XmlUtils.findChild(elem, 'PlaybackRate'); + + if ((latencyNode && latencyNode.getAttribute('max')) || playbackRateNode) { + const maxLatency = latencyNode && latencyNode.getAttribute('max') ? + parseInt(latencyNode.getAttribute('max'), 10) / 1000 : + null; + const maxPlaybackRate = playbackRateNode ? + parseFloat(playbackRateNode.getAttribute('max')) : + null; + + return {maxLatency, maxPlaybackRate}; } - return serviceDescription; + return null; } /** diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index d17aa6d86c..167a755c4c 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -801,10 +801,7 @@ shaka.hls.HlsParser = class { ignoreManifestTimestampsInSegmentsMode: this.config_.hls.ignoreManifestTimestampsInSegmentsMode, type: shaka.media.ManifestParser.HLS, - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, }; this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_); } diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index 23306dc138..6b99a056b2 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -376,10 +376,7 @@ shaka.mss.MssParser = class { sequenceMode: this.config_.mss.sequenceMode, ignoreManifestTimestampsInSegmentsMode: false, type: shaka.media.ManifestParser.MSS, - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, }; // This is the first point where we have a meaningful presentation start diff --git a/lib/offline/manifest_converter.js b/lib/offline/manifest_converter.js index 88bf292e62..3e56dab90e 100644 --- a/lib/offline/manifest_converter.js +++ b/lib/offline/manifest_converter.js @@ -91,10 +91,7 @@ shaka.offline.ManifestConverter = class { sequenceMode: manifestDB.sequenceMode || false, ignoreManifestTimestampsInSegmentsMode: false, type: manifestDB.type || shaka.media.ManifestParser.UNKNOWN, - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, }; } diff --git a/test/media/playhead_unit.js b/test/media/playhead_unit.js index f0d3abd675..0b7cca091b 100644 --- a/test/media/playhead_unit.js +++ b/test/media/playhead_unit.js @@ -136,10 +136,7 @@ describe('Playhead', () => { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, }; config = shaka.util.PlayerConfiguration.createDefault().streaming; diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index 56bed7ebf4..d19e1c47c0 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -597,10 +597,7 @@ describe('StreamingEngine', () => { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, variants: [{ id: 1, video: { diff --git a/test/test/util/manifest_generator.js b/test/test/util/manifest_generator.js index b0cd4d7e75..ec750ef018 100644 --- a/test/test/util/manifest_generator.js +++ b/test/test/util/manifest_generator.js @@ -101,11 +101,8 @@ shaka.test.ManifestGenerator.Manifest = class { this.ignoreManifestTimestampsInSegmentsMode = false; /** @type {string} */ this.type = 'UNKNOWN'; - /** @type {!shaka.extern.ServiceDescription} */ - this.serviceDescription = { - maxLatency: null, - maxPlaybackRate: null, - }; + /** @type {?shaka.extern.ServiceDescription} */ + this.serviceDescription = null; /** @type {shaka.extern.Manifest} */ diff --git a/test/test/util/streaming_engine_util.js b/test/test/util/streaming_engine_util.js index 3c2b8a97fb..9620c90523 100644 --- a/test/test/util/streaming_engine_util.js +++ b/test/test/util/streaming_engine_util.js @@ -286,10 +286,7 @@ shaka.test.StreamingEngineUtil = class { sequenceMode: false, ignoreManifestTimestampsInSegmentsMode: false, type: 'UNKNOWN', - serviceDescription: { - maxLatency: null, - maxPlaybackRate: null, - }, + serviceDescription: null, }; /** @type {shaka.extern.Variant} */ From 7535498e10091edb1ce9a877cd794f91695e0fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20G=C3=B3mez=20Llorente?= Date: Wed, 5 Jul 2023 14:05:32 +0200 Subject: [PATCH 9/9] feat: Update maxLatency and maxPlaybackRate conditions --- lib/player.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/player.js b/lib/player.js index 5642b61d83..d7ecc9f9e9 100644 --- a/lib/player.js +++ b/lib/player.js @@ -5730,15 +5730,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return; } - // Should use serviceDescription if they exist. - const liveSyncMaxLatency = - this.manifest_ && this.manifest_.serviceDescription.maxLatency ? - this.manifest_.serviceDescription.maxLatency : - this.config_.streaming.liveSyncMaxLatency; - const liveSyncPlaybackRate = - this.manifest_ && this.manifest_.serviceDescription.maxPlaybackRate ? - this.manifest_.serviceDescription.maxPlaybackRate : - this.config_.streaming.liveSyncPlaybackRate; + let liveSyncMaxLatency; + let liveSyncPlaybackRate; + if (this.config_.streaming.liveSync) { + liveSyncMaxLatency = this.config_.streaming.liveSyncMaxLatency; + liveSyncPlaybackRate = this.config_.streaming.liveSyncPlaybackRate; + } else { + // serviceDescription must override if it is defined in the MPD and + // liveSync configuration is not set. + if (this.manifest_ && this.manifest_.serviceDescription) { + liveSyncMaxLatency = this.manifest_.serviceDescription.maxLatency || + this.config_.streaming.liveSyncMaxLatency; + liveSyncPlaybackRate = + this.manifest_.serviceDescription.maxPlaybackRate || + this.config_.streaming.liveSyncPlaybackRate; + } + } + const playbackRate = this.video_.playbackRate; const latency = seekRange.end - this.video_.currentTime; let offset = 0; @@ -5754,10 +5762,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - if ((latency - offset) > liveSyncMaxLatency) { + if (liveSyncMaxLatency && liveSyncPlaybackRate && + (latency - offset) > liveSyncMaxLatency) { if (playbackRate != liveSyncPlaybackRate) { shaka.log.debug('Latency (' + latency + 's) ' + - 'is greater than liveSyncMaxLatency (' + liveSyncMaxLatency + 's).' + + 'is greater than liveSyncMaxLatency (' + liveSyncMaxLatency + 's). ' + 'Updating playbackRate to ' + liveSyncPlaybackRate); this.trickPlay(liveSyncPlaybackRate); }