From 6defc782f19a06c8b8e26e654c243b7f3436b2d7 Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:08:50 +0100 Subject: [PATCH 1/8] fix: set media source duration when setLiveSeekableRange is not available --- .../controllers/MediaSourceController.js | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index 074d7fa3ce..c0d003a1fb 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -70,13 +70,15 @@ function MediaSourceController() { videoModel.setSource(null); } - function setDuration(value) { + function setDuration(value, log = true) { if (!mediaSource || mediaSource.readyState !== 'open') return; if (value === null && isNaN(value)) return; if (mediaSource.duration === value) return; if (!isBufferUpdating(mediaSource)) { - logger.info('Set MediaSource duration:' + value); + if (log) { + logger.info('Set MediaSource duration:' + value); + } mediaSource.duration = value; } else { setTimeout(setDuration.bind(null, value), 50); @@ -84,11 +86,35 @@ function MediaSourceController() { } function setSeekable(start, end) { - if (mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && + if (Math.random() > 2 && mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && mediaSource.readyState === 'open' && start >= 0 && start < end) { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); + } else { + try { + const bufferedRangeEnd = getBufferedRangeEnd(mediaSource); + const targetMediaSourceDuration = Math.max(end, bufferedRangeEnd); + if (mediaSource.duration < targetMediaSourceDuration) { + setDuration(targetMediaSourceDuration, false); + } + } catch (e) { + logger.error(`Failed to set MediaSource duration! ` + e.toString()); + } + } + } + + function getBufferedRangeEnd(source) { + let max = 0; + const buffers = source.sourceBuffers; + + for (let i = 0; i < buffers.length; i++) { + if (buffers[i].buffered.length > 0) { + const end = buffers[i].buffered.end(buffers[i].buffered.length - 1); + max = Math.max(end, max); + } } + + return max; } function signalEndOfStream(source) { From be101cb2e70c8779c11dc7f84b7ee7af48c799c5 Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:22:10 +0100 Subject: [PATCH 2/8] feat: added config.streaming.buffer.enableLiveSeekableRangeFix --- index.d.ts | 3 ++- src/core/Settings.js | 8 ++++++-- src/streaming/controllers/MediaSourceController.js | 4 ++-- src/streaming/controllers/StreamController.js | 8 ++++++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index daf5be6ecf..2356664090 100644 --- a/index.d.ts +++ b/index.d.ts @@ -193,7 +193,8 @@ declare namespace dashjs { longFormContentDurationThreshold?: number, stallThreshold?: number, useAppendWindow?: boolean, - setStallState?: boolean + setStallState?: boolean, + enableSetLiveSeekableRangeFix?: boolean }, gaps?: { jumpGaps?: boolean, diff --git a/src/core/Settings.js b/src/core/Settings.js index 4953252f99..61ff9753bc 100644 --- a/src/core/Settings.js +++ b/src/core/Settings.js @@ -99,7 +99,8 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * longFormContentDurationThreshold: 600, * stallThreshold: 0.5, * useAppendWindow: true, - * setStallState: false + * setStallState: false, + * enableSetLiveSeekableRangeFix: false * }, * gaps: { * jumpGaps: true, @@ -301,6 +302,8 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest. * @property {boolean} [setStallState=false] * Specifies if we fire manual waiting events once the stall threshold is reached + * @property {boolean} [enableSetLiveSeekableRangeFix=false] + * Sets `mediaSource.duration` when live seekable range changes if `mediaSource.setLiveSeekableRange` is unavailable. */ /** @@ -801,7 +804,8 @@ function Settings() { longFormContentDurationThreshold: 600, stallThreshold: 0.3, useAppendWindow: true, - setStallState: true + setStallState: true, + enableSetLiveSeekableRangeFix: false }, gaps: { jumpGaps: true, diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index c0d003a1fb..ae036864b8 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -85,12 +85,12 @@ function MediaSourceController() { } } - function setSeekable(start, end) { + function setSeekable(start, end, enableSetLiveSeekableRangeFix = false) { if (Math.random() > 2 && mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && mediaSource.readyState === 'open' && start >= 0 && start < end) { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); - } else { + } else if (enableSetLiveSeekableRangeFix) { try { const bufferedRangeEnd = getBufferedRangeEnd(mediaSource); const targetMediaSourceDuration = Math.max(end, bufferedRangeEnd); diff --git a/src/streaming/controllers/StreamController.js b/src/streaming/controllers/StreamController.js index 1ec6cc364c..2ccf114e74 100644 --- a/src/streaming/controllers/StreamController.js +++ b/src/streaming/controllers/StreamController.js @@ -423,7 +423,7 @@ function StreamController() { _setMediaDuration(); const dvrInfo = dashMetrics.getCurrentDVRInfo(); - mediaSourceController.setSeekable(dvrInfo.range.start, dvrInfo.range.end); + mediaSourceController.setSeekable(dvrInfo.range.start, dvrInfo.range.end, _enableLiveSeekableRangeFix()); _activateStream(seekTime, keepBuffers); } @@ -611,6 +611,10 @@ function StreamController() { } } + function _enableLiveSeekableRangeFix() { + return settings.get().streaming.buffer.enableLiveSeekableRangeFix; + } + /** * Initiate the preloading of the next stream * @param {object} nextStream @@ -1487,7 +1491,7 @@ function StreamController() { //Should we normalize and union the two? const targetMediaType = hasAudioTrack() ? Constants.AUDIO : Constants.VIDEO; if (e.mediaType === targetMediaType) { - mediaSourceController.setSeekable(e.value.range.start, e.value.range.end); + mediaSourceController.setSeekable(e.value.range.start, e.value.range.end, _enableLiveSeekableRangeFix()); } } } From 6dd71781df97fbf40d254dcd046466534354c89f Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:28:10 +0100 Subject: [PATCH 3/8] fix: set enableSetLiveSeekableRangeFix to true by default --- src/core/Settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/Settings.js b/src/core/Settings.js index 61ff9753bc..ba2bfce14d 100644 --- a/src/core/Settings.js +++ b/src/core/Settings.js @@ -100,7 +100,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * stallThreshold: 0.5, * useAppendWindow: true, * setStallState: false, - * enableSetLiveSeekableRangeFix: false + * enableSetLiveSeekableRangeFix: true * }, * gaps: { * jumpGaps: true, @@ -302,7 +302,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest. * @property {boolean} [setStallState=false] * Specifies if we fire manual waiting events once the stall threshold is reached - * @property {boolean} [enableSetLiveSeekableRangeFix=false] + * @property {boolean} [enableSetLiveSeekableRangeFix=true] * Sets `mediaSource.duration` when live seekable range changes if `mediaSource.setLiveSeekableRange` is unavailable. */ @@ -805,7 +805,7 @@ function Settings() { stallThreshold: 0.3, useAppendWindow: true, setStallState: true, - enableSetLiveSeekableRangeFix: false + enableSetLiveSeekableRangeFix: true }, gaps: { jumpGaps: true, From 567da01f5d7656d08a7352e83ae6e08eb9265245 Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:28:20 +0100 Subject: [PATCH 4/8] fix: remove debug code --- src/streaming/controllers/MediaSourceController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index ae036864b8..aa2ec2a81a 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -85,8 +85,8 @@ function MediaSourceController() { } } - function setSeekable(start, end, enableSetLiveSeekableRangeFix = false) { - if (Math.random() > 2 && mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && + function setSeekable(start, end, enableSetLiveSeekableRangeFix) { + if (mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && mediaSource.readyState === 'open' && start >= 0 && start < end) { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); From 5dda4007acc1e61c42f88d62cbd93d1d2d6ee798 Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:30:29 +0100 Subject: [PATCH 5/8] refactor: guards --- src/streaming/controllers/MediaSourceController.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index aa2ec2a81a..6b778c5034 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -86,8 +86,10 @@ function MediaSourceController() { } function setSeekable(start, end, enableSetLiveSeekableRangeFix) { - if (mediaSource && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function' && - mediaSource.readyState === 'open' && start >= 0 && start < end) { + if (!mediaSource || mediaSource.readyState !== 'open') return; + if (start < 0 || end <= start) return; + + if (typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function') { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); } else if (enableSetLiveSeekableRangeFix) { From 04188f8cb74a45d3f1fe369eaf722bfa2f4454ef Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:52:10 +0100 Subject: [PATCH 6/8] chore: update setting name --- index.d.ts | 2 +- src/core/Settings.js | 6 +++--- src/streaming/controllers/MediaSourceController.js | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index 2356664090..611591973e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -194,7 +194,7 @@ declare namespace dashjs { stallThreshold?: number, useAppendWindow?: boolean, setStallState?: boolean, - enableSetLiveSeekableRangeFix?: boolean + enableLiveSeekableRangeFix?: boolean }, gaps?: { jumpGaps?: boolean, diff --git a/src/core/Settings.js b/src/core/Settings.js index ba2bfce14d..9fb20c6106 100644 --- a/src/core/Settings.js +++ b/src/core/Settings.js @@ -100,7 +100,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * stallThreshold: 0.5, * useAppendWindow: true, * setStallState: false, - * enableSetLiveSeekableRangeFix: true + * enableLiveSeekableRangeFix: true * }, * gaps: { * jumpGaps: true, @@ -302,7 +302,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; * Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest. * @property {boolean} [setStallState=false] * Specifies if we fire manual waiting events once the stall threshold is reached - * @property {boolean} [enableSetLiveSeekableRangeFix=true] + * @property {boolean} [enableLiveSeekableRangeFix=true] * Sets `mediaSource.duration` when live seekable range changes if `mediaSource.setLiveSeekableRange` is unavailable. */ @@ -805,7 +805,7 @@ function Settings() { stallThreshold: 0.3, useAppendWindow: true, setStallState: true, - enableSetLiveSeekableRangeFix: true + enableLiveSeekableRangeFix: true }, gaps: { jumpGaps: true, diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index 6b778c5034..083b623a31 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -85,18 +85,18 @@ function MediaSourceController() { } } - function setSeekable(start, end, enableSetLiveSeekableRangeFix) { + function setSeekable(start, end, enableLiveSeekableRangeFix) { if (!mediaSource || mediaSource.readyState !== 'open') return; if (start < 0 || end <= start) return; - if (typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function') { + if (Math.random() > 2 && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function') { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); - } else if (enableSetLiveSeekableRangeFix) { + } else if (enableLiveSeekableRangeFix) { try { const bufferedRangeEnd = getBufferedRangeEnd(mediaSource); const targetMediaSourceDuration = Math.max(end, bufferedRangeEnd); - if (mediaSource.duration < targetMediaSourceDuration) { + if (!isFinite(mediaSource.duration) || mediaSource.duration < targetMediaSourceDuration) { setDuration(targetMediaSourceDuration, false); } } catch (e) { From 30480030221ef814c3b5308ec2023af4890a8d8f Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:52:46 +0100 Subject: [PATCH 7/8] chore: remove debug code --- src/streaming/controllers/MediaSourceController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/streaming/controllers/MediaSourceController.js b/src/streaming/controllers/MediaSourceController.js index 083b623a31..6cce7efa99 100644 --- a/src/streaming/controllers/MediaSourceController.js +++ b/src/streaming/controllers/MediaSourceController.js @@ -89,7 +89,7 @@ function MediaSourceController() { if (!mediaSource || mediaSource.readyState !== 'open') return; if (start < 0 || end <= start) return; - if (Math.random() > 2 && typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function') { + if (typeof mediaSource.setLiveSeekableRange === 'function' && typeof mediaSource.clearLiveSeekableRange === 'function') { mediaSource.clearLiveSeekableRange(); mediaSource.setLiveSeekableRange(start, end); } else if (enableLiveSeekableRangeFix) { From 50f2eb3d83a87daef8677f0b63b24d4b1b698779 Mon Sep 17 00:00:00 2001 From: grabofus <34451173+grabofus@users.noreply.github.com> Date: Thu, 30 Jun 2022 14:14:07 +0100 Subject: [PATCH 8/8] 4.3.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 09d7a26b93..d39b9fd71d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dashjs", - "version": "4.3.4", + "version": "4.3.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a8c51f8d38..e456d45866 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dashjs", - "version": "4.3.4", + "version": "4.3.5", "description": "A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.", "author": "Dash Industry Forum", "license": "BSD-3-Clause",