From 7882e95989649ec2d96996e9b48b8a7ef1f415cc Mon Sep 17 00:00:00 2001 From: vincentvalot Date: Tue, 27 Nov 2018 10:53:25 +0100 Subject: [PATCH 01/18] feat capability to match lang regex for initial settings --- src/streaming/MediaPlayer.js | 5 +- src/streaming/controllers/MediaController.js | 2 +- .../streaming.controllers.MediaController.js | 67 ++++++++++++++++++- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/streaming/MediaPlayer.js b/src/streaming/MediaPlayer.js index 2ad01126d9..da445e3454 100644 --- a/src/streaming/MediaPlayer.js +++ b/src/streaming/MediaPlayer.js @@ -2301,14 +2301,13 @@ function MediaPlayer() { /** * This method allows to set media settings that will be used to pick the initial track. Format of the settings - * is following: - * {lang: langValue, + * is following:
+ * {lang: langValue (can be either a string or a regex to match), * viewpoint: viewpointValue, * audioChannelConfiguration: audioChannelConfigurationValue, * accessibility: accessibilityValue, * role: roleValue} * - * * @param {string} type * @param {Object} value * @memberof module:MediaPlayer diff --git a/src/streaming/controllers/MediaController.js b/src/streaming/controllers/MediaController.js index 1574737869..6d80529705 100644 --- a/src/streaming/controllers/MediaController.js +++ b/src/streaming/controllers/MediaController.js @@ -359,7 +359,7 @@ function MediaController() { } function matchSettings(settings, track) { - const matchLang = !settings.lang || (settings.lang === track.lang); + const matchLang = !settings.lang || (track.lang.match(settings.lang)); const matchViewPoint = !settings.viewpoint || (settings.viewpoint === track.viewpoint); const matchRole = !settings.role || !!track.roles.filter(function (item) { return item === settings.role; diff --git a/test/unit/streaming.controllers.MediaController.js b/test/unit/streaming.controllers.MediaController.js index 825daca662..863d7ba869 100644 --- a/test/unit/streaming.controllers.MediaController.js +++ b/test/unit/streaming.controllers.MediaController.js @@ -397,9 +397,7 @@ describe('MediaController', function () { }); describe('Initial Track Management', function () { - it('should check initial media settings to choose initial track', function () { - let trackType = 'audio'; let streamInfo = { id: 'id' @@ -435,6 +433,71 @@ describe('MediaController', function () { }); + it('should check initial media settings to choose initial track with a string/regex lang', function () { + const trackType = 'audio'; + const streamInfo = { + id: 'id' + }; + const track = { + type: trackType, + streamInfo: streamInfo, + lang: 'fr', + viewpoint: 'viewpoint', + roles: 1, + accessibility: 1, + audioChannelConfiguration: 1 + }; + + mediaController.addTrack(track); + + // call to checkInitialMediaSettingsForType + mediaController.setInitialSettings(trackType, { + lang: 'fr|en|qtz', + viewpoint: 'viewpoint' + }); + mediaController.checkInitialMediaSettingsForType(trackType, streamInfo); + + const currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + expect(objectUtils.areEqual(currentTrack, track)).to.be.true; // jshint ignore:line + }); + + it('should check initial media settings to choose initial track with a regex lang', function () { + const trackType = 'audio'; + const streamInfo = { + id: 'id' + }; + const frTrack = { + type: trackType, + streamInfo: streamInfo, + lang: 'fr', + viewpoint: 'viewpoint', + roles: 1, + accessibility: 1, + audioChannelConfiguration: 1 + }; + const qtzTrack = { + type: trackType, + streamInfo: streamInfo, + lang: 'qtz', + viewpoint: 'viewpoint', + roles: 1, + accessibility: 1, + audioChannelConfiguration: 1 + }; + + mediaController.addTrack(frTrack); + mediaController.addTrack(qtzTrack); + + // call to checkInitialMediaSettingsForType + mediaController.setInitialSettings(trackType, { + lang: /qtz|mis/, + viewpoint: 'viewpoint' + }); + mediaController.checkInitialMediaSettingsForType(trackType, streamInfo); + + const currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + expect(objectUtils.areEqual(currentTrack, qtzTrack)).to.be.true; // jshint ignore:line + }); }); }); From 2cd945a4dc2ccff4ac830c3a5d5f3f9be169247d Mon Sep 17 00:00:00 2001 From: Jerry Chen Date: Tue, 10 Dec 2019 10:58:50 +0800 Subject: [PATCH 02/18] As 'getTimeBasedSegment' returns null if isSegmentAvailable is false, segments' length could be smalled than fragments' length, then exception occurs here. This issue could be tested with video source 'https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd' --- src/dash/DashHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dash/DashHandler.js b/src/dash/DashHandler.js index cd3ab3126c..7ef2850c31 100644 --- a/src/dash/DashHandler.js +++ b/src/dash/DashHandler.js @@ -388,7 +388,7 @@ function DashHandler(config) { } if (segments.length > 0) { - representation.segmentAvailabilityRange = {start: segments[0].presentationStartTime, end: segments[len - 1].presentationStartTime}; + representation.segmentAvailabilityRange = {start: segments[0].presentationStartTime, end: segments[segments.length - 1].presentationStartTime}; representation.availableSegmentsNumber = segments.length; representation.segments = segments; From 9cb19f2586ea6faec0db6737e105a608818693d7 Mon Sep 17 00:00:00 2001 From: Bertrand Berthelot Date: Tue, 10 Dec 2019 17:31:38 +0100 Subject: [PATCH 03/18] PlaybackController: in getActualPresentationTime(), ignore DVRWindow if live stream not yet started (currentTime = 0) --- src/streaming/controllers/PlaybackController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 007587c63c..1b79d21d40 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -405,7 +405,7 @@ function PlaybackController() { if (!DVRWindow) return NaN; if (currentTime > DVRWindow.end) { actualTime = Math.max(DVRWindow.end - streamInfo.manifestInfo.minBufferTime * 2, DVRWindow.start); - } else if (currentTime + 0.250 < DVRWindow.start && DVRWindow.start - currentTime > DVRWindow.start - 315360000) { + } else if (currentTime > 0 && currentTime + 0.250 < DVRWindow.start && DVRWindow.start - currentTime > DVRWindow.start - 315360000) { // Checking currentTime plus 250ms as the 'timeupdate' is fired with a frequency between 4Hz and 66Hz // https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate // http://w3c.github.io/html/single-page.html#offsets-into-the-media-resource From 853e538bbf77b4af5afc6bcb864a99eef8360ee3 Mon Sep 17 00:00:00 2001 From: nicosang Date: Mon, 16 Dec 2019 15:21:22 +0100 Subject: [PATCH 04/18] if r is defined in url stream, we have to use it to compute livedelay --- src/streaming/controllers/PlaybackController.js | 6 +++++- test/unit/mocks/URIFragmentModelMock.js | 7 ++++++- test/unit/streaming.controllers.PlaybackControllers.js | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 007587c63c..6b522c4b44 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -229,6 +229,7 @@ function PlaybackController() { let delay, ret, startTime; + let startTimeParameters = getStartTimeFromUriParameters(); const END_OF_PLAYLIST_PADDING = 10; let suggestedPresentationDelay = adapter.getSuggestedPresentationDelay(); @@ -239,7 +240,10 @@ function PlaybackController() { delay = 0; } else if (mediaPlayerModel.getLiveDelay()) { delay = mediaPlayerModel.getLiveDelay(); // If set by user, this value takes precedence - } else if (!isNaN(fragmentDuration)) { + } else if (startTimeParameters && startTimeParameters.fragT) { + delay = startTimeParameters.fragT; + } + else if (!isNaN(fragmentDuration)) { delay = fragmentDuration * settings.get().streaming.liveDelayFragmentCount; } else { delay = streamInfo.manifestInfo.minBufferTime * 2; diff --git a/test/unit/mocks/URIFragmentModelMock.js b/test/unit/mocks/URIFragmentModelMock.js index f97d966011..dffd1e74a5 100644 --- a/test/unit/mocks/URIFragmentModelMock.js +++ b/test/unit/mocks/URIFragmentModelMock.js @@ -1,9 +1,14 @@ class URIFragmentModelMock { constructor() { + this.uriFragmentData = null; } getURIFragmentData() { - return {t: 18.2}; + return this.uriFragmentData; + } + + setURIFragmentData(uri) { + this.uriFragmentData = uri; } } diff --git a/test/unit/streaming.controllers.PlaybackControllers.js b/test/unit/streaming.controllers.PlaybackControllers.js index b3849b6899..c74ed0cdbf 100644 --- a/test/unit/streaming.controllers.PlaybackControllers.js +++ b/test/unit/streaming.controllers.PlaybackControllers.js @@ -165,6 +165,7 @@ describe('PlaybackController', function () { }); it('getStartTimeFromUriParameters should return the expected value', function () { + uriFragmentModelMock.setURIFragmentData({t: 18.2}); const uriParameters = playbackController.getStartTimeFromUriParameters(); expect(uriParameters.fragT).to.exist; // jshint ignore:line expect(uriParameters.fragT).to.equal(18.2); From ac0d432432e1b31792cc78a9283ab7f73dbe14c5 Mon Sep 17 00:00:00 2001 From: nicosang Date: Wed, 18 Dec 2019 09:22:04 +0100 Subject: [PATCH 05/18] in OnBytesAppended, take into account uri parameters in order to not start behind this value. --- src/streaming/controllers/PlaybackController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 6b522c4b44..c548ddbb12 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -705,7 +705,7 @@ function PlaybackController() { const hasVideoTrack = streamController.isTrackTypePresent(Constants.VIDEO); const hasAudioTrack = streamController.isTrackTypePresent(Constants.AUDIO); - initialStartTime = getStreamStartTime(true); + initialStartTime = getStreamStartTime(false); if (hasAudioTrack && hasVideoTrack) { //current stream has audio and video contents if (!isNaN(commonEarliestTime[streamInfo.id].audio) && !isNaN(commonEarliestTime[streamInfo.id].video)) { From ff355c1dc605526711b79fa4dfffbeccb94aa085 Mon Sep 17 00:00:00 2001 From: nicosang Date: Fri, 20 Dec 2019 14:17:51 +0100 Subject: [PATCH 06/18] each time buffer level or buffer state is uspdated, metrics have to be also updated --- src/streaming/controllers/BufferController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/streaming/controllers/BufferController.js b/src/streaming/controllers/BufferController.js index ef2b430cba..cff7ec6d75 100644 --- a/src/streaming/controllers/BufferController.js +++ b/src/streaming/controllers/BufferController.js @@ -735,6 +735,7 @@ function BufferController(config) { if (!bufferResetInProgress) { logger.debug('onRemoved : call updateBufferLevel'); updateBufferLevel(); + addBufferMetrics(); } else { bufferResetInProgress = false; if (mediaChunk) { From 9adb6f8017a6768550f539352947e8b278e43b90 Mon Sep 17 00:00:00 2001 From: nicosang Date: Wed, 8 Jan 2020 14:43:06 +0100 Subject: [PATCH 07/18] update commonEarliestTime value in onBufferCleared callback in order to not reset value when the buffer range is not deleted --- .../controllers/PlaybackController.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 007587c63c..92e82f8e95 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -90,6 +90,7 @@ function PlaybackController() { eventBus.on(Events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this); eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); + eventBus.on(Events.BUFFER_CLEARED, onBufferCleared, this); eventBus.on(Events.LOADING_PROGRESS, onFragmentLoadProgress, this); eventBus.on(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.on(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this); @@ -150,15 +151,11 @@ function PlaybackController() { // Internal seek = seek video model only (disable 'seeking' listener), // buffer(s) are already appended at given time (see onBytesAppended()) videoModel.removeEventListener('seeking', onPlaybackSeeking); - logger.info('Requesting seek to time: ' + time); + logger.info('Requesting internal seek to time: ' + time); videoModel.setCurrentTime(time, stickToBuffered); } } else { eventBus.trigger(Events.PLAYBACK_SEEK_ASKED); - if (streamInfo) { - delete bufferedRange[streamInfo.id]; - delete commonEarliestTime[streamInfo.id]; - } logger.info('Requesting seek to time: ' + time); videoModel.setCurrentTime(time, stickToBuffered); } @@ -298,6 +295,7 @@ function PlaybackController() { eventBus.off(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); eventBus.off(Events.PLAYBACK_ENDED, onPlaybackEnded, this); eventBus.off(Events.STREAM_INITIALIZING, onStreamInitializing, this); + eventBus.off(Events.BUFFER_CLEARED, onBufferCleared, this); stopUpdatingWallclockTime(); removeAllListeners(); } @@ -671,6 +669,19 @@ function PlaybackController() { } } + function onBufferCleared(e) { + const type = e.sender.getType(); + + if (streamInfo && commonEarliestTime[streamInfo.id] && (commonEarliestTime[streamInfo.id][type] >= e.from && commonEarliestTime[streamInfo.id][type] <= e.to)) { + logger.info('Reset commonEarliestTime and bufferedRange for ' + type); + bufferedRange[streamInfo.id][type] = undefined; + commonEarliestTime[streamInfo.id][type] = undefined; + commonEarliestTime[streamInfo.id].started = false; + } else { + logger.info('No need to reset commonEarliestTime and bufferedRange for ' + type); + } + } + function onBytesAppended(e) { let earliestTime, initialStartTime; From 5aeb17aff743fc9eb4f146f0aa90d0b2ccf239e1 Mon Sep 17 00:00:00 2001 From: Jeremie COLLET Date: Mon, 13 Jan 2020 17:18:46 +0100 Subject: [PATCH 08/18] Fix Issue #3083 for live streams with multiperiod. --- src/dash/utils/SegmentsUtils.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dash/utils/SegmentsUtils.js b/src/dash/utils/SegmentsUtils.js index 05b070b32a..b521503e1b 100644 --- a/src/dash/utils/SegmentsUtils.js +++ b/src/dash/utils/SegmentsUtils.js @@ -149,7 +149,15 @@ function isSegmentAvailable(timelineConverter, representation, segment, isDynami const segmentTime = timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, segment.presentationStartTime); if (segmentTime >= periodRelativeEnd) { - return false; + if (isDynamic) { + // segment is not available in current period, but it may be segment available in another period that current one (in DVR window) + // if not (time > segmentAvailabilityRange.end), then return false + if ( representation.segmentAvailabilityRange && segment.presentationStartTime >= representation.segmentAvailabilityRange.end) { + return false; + } + } else { + return false; + } } return true; From a1bdc988689f4503aaf19f73354a82a98878bfaf Mon Sep 17 00:00:00 2001 From: dsi Date: Tue, 14 Jan 2020 13:30:08 +0100 Subject: [PATCH 09/18] [Refactor] Rename the earliestTime variables in the PlaybackController.js to avoid confusion --- .../controllers/PlaybackController.js | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 92e82f8e95..58f7a1b704 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -51,7 +51,7 @@ function PlaybackController() { timelineConverter, liveStartTime, wallclockTimeIntervalId, - commonEarliestTime, + earliestTime, liveDelay, bufferedRange, streamInfo, @@ -106,9 +106,9 @@ function PlaybackController() { } function onPeriodSwitchStarted(e) { - if (!isDynamic && e.fromStreamInfo && commonEarliestTime[e.fromStreamInfo.id] !== undefined) { + if (!isDynamic && e.fromStreamInfo && earliestTime[e.fromStreamInfo.id] !== undefined) { delete bufferedRange[e.fromStreamInfo.id]; - delete commonEarliestTime[e.fromStreamInfo.id]; + delete earliestTime[e.fromStreamInfo.id]; } } @@ -281,7 +281,7 @@ function PlaybackController() { function reset() { liveStartTime = NaN; playOnceInitialized = false; - commonEarliestTime = {}; + earliestTime = {}; liveDelay = 0; availabilityStartTime = 0; bufferedRange = {}; @@ -386,8 +386,8 @@ function PlaybackController() { if (!isNaN(startTimeOffset) && startTimeOffset < Math.max(streamInfo.manifestInfo.duration, streamInfo.duration) && startTimeOffset >= 0) { presentationStartTime = startTimeOffset; } else { - let earliestTime = commonEarliestTime[streamInfo.id]; //set by ready bufferStart after first onBytesAppended - presentationStartTime = earliestTime !== undefined ? Math.max(earliestTime.audio !== undefined ? earliestTime.audio : 0, earliestTime.video !== undefined ? earliestTime.video : 0, streamInfo.start) : streamInfo.start; + let currentEarliestTime = earliestTime[streamInfo.id]; //set by ready bufferStart after first onBytesAppended + presentationStartTime = currentEarliestTime !== undefined ? Math.max(currentEarliestTime.audio !== undefined ? currentEarliestTime.audio : 0, currentEarliestTime.video !== undefined ? currentEarliestTime.video : 0, streamInfo.start) : streamInfo.start; } } } @@ -672,22 +672,22 @@ function PlaybackController() { function onBufferCleared(e) { const type = e.sender.getType(); - if (streamInfo && commonEarliestTime[streamInfo.id] && (commonEarliestTime[streamInfo.id][type] >= e.from && commonEarliestTime[streamInfo.id][type] <= e.to)) { + if (streamInfo && earliestTime[streamInfo.id] && (earliestTime[streamInfo.id][type] >= e.from && earliestTime[streamInfo.id][type] <= e.to)) { logger.info('Reset commonEarliestTime and bufferedRange for ' + type); bufferedRange[streamInfo.id][type] = undefined; - commonEarliestTime[streamInfo.id][type] = undefined; - commonEarliestTime[streamInfo.id].started = false; + earliestTime[streamInfo.id][type] = undefined; + earliestTime[streamInfo.id].started = false; } else { logger.info('No need to reset commonEarliestTime and bufferedRange for ' + type); } } function onBytesAppended(e) { - let earliestTime, + let commonEarliestTime, initialStartTime; let ranges = e.bufferedRanges; if (!ranges || !ranges.length) return; - if (commonEarliestTime[streamInfo.id] && commonEarliestTime[streamInfo.id].started === true) { + if (earliestTime[streamInfo.id] && earliestTime[streamInfo.id].started === true) { //stream has already been started. return; } @@ -700,13 +700,13 @@ function PlaybackController() { bufferedRange[streamInfo.id][type] = ranges; - if (commonEarliestTime[streamInfo.id] === undefined) { - commonEarliestTime[streamInfo.id] = []; - commonEarliestTime[streamInfo.id].started = false; + if (earliestTime[streamInfo.id] === undefined) { + earliestTime[streamInfo.id] = []; + earliestTime[streamInfo.id].started = false; } - if (commonEarliestTime[streamInfo.id][type] === undefined) { - commonEarliestTime[streamInfo.id][type] = Math.max(ranges.start(0), streamInfo.start); + if (earliestTime[streamInfo.id][type] === undefined) { + earliestTime[streamInfo.id][type] = Math.max(ranges.start(0), streamInfo.start); } const hasVideoTrack = streamController.isTrackTypePresent(Constants.VIDEO); @@ -715,36 +715,36 @@ function PlaybackController() { initialStartTime = getStreamStartTime(true); if (hasAudioTrack && hasVideoTrack) { //current stream has audio and video contents - if (!isNaN(commonEarliestTime[streamInfo.id].audio) && !isNaN(commonEarliestTime[streamInfo.id].video)) { + if (!isNaN(earliestTime[streamInfo.id].audio) && !isNaN(earliestTime[streamInfo.id].video)) { - if (commonEarliestTime[streamInfo.id].audio < commonEarliestTime[streamInfo.id].video) { + if (earliestTime[streamInfo.id].audio < earliestTime[streamInfo.id].video) { // common earliest is video time // check buffered audio range has video time, if ok, we seek, otherwise, we wait some other data - earliestTime = commonEarliestTime[streamInfo.id].video > initialStartTime ? commonEarliestTime[streamInfo.id].video : initialStartTime; + commonEarliestTime = earliestTime[streamInfo.id].video > initialStartTime ? earliestTime[streamInfo.id].video : initialStartTime; ranges = bufferedRange[streamInfo.id].audio; } else { // common earliest is audio time // check buffered video range has audio time, if ok, we seek, otherwise, we wait some other data - earliestTime = commonEarliestTime[streamInfo.id].audio > initialStartTime ? commonEarliestTime[streamInfo.id].audio : initialStartTime; + commonEarliestTime = earliestTime[streamInfo.id].audio > initialStartTime ? earliestTime[streamInfo.id].audio : initialStartTime; ranges = bufferedRange[streamInfo.id].video; } - if (checkTimeInRanges(earliestTime, ranges)) { + if (checkTimeInRanges(commonEarliestTime, ranges)) { if (!(checkTimeInRanges(getNormalizedTime(), bufferedRange[streamInfo.id].audio) && checkTimeInRanges(getNormalizedTime(), bufferedRange[streamInfo.id].video))) { - if (!compatibleWithPreviousStream && earliestTime !== 0) { - seek(earliestTime, true, true); + if (!compatibleWithPreviousStream && commonEarliestTime !== 0) { + seek(commonEarliestTime, true, true); } } - commonEarliestTime[streamInfo.id].started = true; + earliestTime[streamInfo.id].started = true; } } } else { //current stream has only audio or only video content - if (commonEarliestTime[streamInfo.id][type]) { - earliestTime = commonEarliestTime[streamInfo.id][type] > initialStartTime ? commonEarliestTime[streamInfo.id][type] : initialStartTime; + if (earliestTime[streamInfo.id][type]) { + commonEarliestTime = earliestTime[streamInfo.id][type] > initialStartTime ? earliestTime[streamInfo.id][type] : initialStartTime; if (!compatibleWithPreviousStream) { - seek(earliestTime, false, true); + seek(commonEarliestTime, false, true); } - commonEarliestTime[streamInfo.id].started = true; + earliestTime[streamInfo.id].started = true; } } } From 5ffdf5ecd6a87849d7f924895a910ba81fae9670 Mon Sep 17 00:00:00 2001 From: dsi Date: Tue, 14 Jan 2020 15:39:04 +0100 Subject: [PATCH 10/18] [Fix] Avoid jumps in the livestream when an incorrect currentTime is reported by the video element --- src/streaming/controllers/PlaybackController.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 58f7a1b704..956b40ddeb 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -400,10 +400,12 @@ function PlaybackController() { const DVRWindow = DVRMetrics ? DVRMetrics.range : null; let actualTime; - if (!DVRWindow) return NaN; + if (!DVRWindow) { + return NaN; + } if (currentTime > DVRWindow.end) { actualTime = Math.max(DVRWindow.end - streamInfo.manifestInfo.minBufferTime * 2, DVRWindow.start); - } else if (currentTime + 0.250 < DVRWindow.start && DVRWindow.start - currentTime > DVRWindow.start - 315360000) { + } else if (currentTime + 0.250 < DVRWindow.start && Math.abs(currentTime - DVRWindow.start) < 315360000) { // Checking currentTime plus 250ms as the 'timeupdate' is fired with a frequency between 4Hz and 66Hz // https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate // http://w3c.github.io/html/single-page.html#offsets-into-the-media-resource From 3948f8ee82f0d3b1c678f17bf4b0748389f2f62e Mon Sep 17 00:00:00 2001 From: dsi Date: Tue, 14 Jan 2020 15:53:05 +0100 Subject: [PATCH 11/18] [Fix] Use clearTimeout function to reset a timeout. --- src/streaming/ManifestUpdater.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/streaming/ManifestUpdater.js b/src/streaming/ManifestUpdater.js index c7e6a8c43a..f98a2f214e 100644 --- a/src/streaming/ManifestUpdater.js +++ b/src/streaming/ManifestUpdater.js @@ -107,7 +107,7 @@ function ManifestUpdater() { function stopManifestRefreshTimer() { if (refreshTimer !== null) { - clearInterval(refreshTimer); + clearTimeout(refreshTimer); refreshTimer = null; } } From ac01b6234fe1bad91c7f160ba21b55d6cacaec84 Mon Sep 17 00:00:00 2001 From: nicosang Date: Wed, 15 Jan 2020 09:17:15 +0100 Subject: [PATCH 12/18] remove default value in typeScript file --- index.d.ts | 2 +- src/streaming/protection/vo/ProtectionData.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 21500fd54f..208185288e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -865,7 +865,7 @@ declare namespace dashjs { clearkeys?: { [key: string]: string }; /** Priority level of the key system to be selected (0 is the highest prority, -1 for undefined priority) */ - priority?: number = -1; + priority?: number; } export interface KeySystem { diff --git a/src/streaming/protection/vo/ProtectionData.js b/src/streaming/protection/vo/ProtectionData.js index 0178ebb988..03c819fe4f 100644 --- a/src/streaming/protection/vo/ProtectionData.js +++ b/src/streaming/protection/vo/ProtectionData.js @@ -46,12 +46,14 @@ class ProtectionData { * @param {Object} clearkeys defines a set of clear keys that are available to * the key system. Object properties are base64-encoded keyIDs (with no padding). * Corresponding property values are keys, base64-encoded (no padding). + * @param {number|undefined} priority priority order of the current ProtectionData * @class */ - constructor(serverURL, httpRequestHeaders, clearkeys) { + constructor(serverURL, httpRequestHeaders, clearkeys, priority) { this.serverURL = serverURL; this.httpRequestHeaders = httpRequestHeaders; this.clearkeys = clearkeys; + this.priority = priority === undefined ? -1 : priority; } } @@ -87,4 +89,14 @@ class ProtectionData { * @memberof ProtectionData */ +/** + * priority + * + * @instance + * @type Object + * @name ProtectionData.priority + * @readonly + * @memberof ProtectionData + */ + export default ProtectionData; From 51d422f7375ae6ea7a95e6a807d70fb6fc87320f Mon Sep 17 00:00:00 2001 From: Jeff Cunat Date: Wed, 15 Jan 2020 09:48:44 +0100 Subject: [PATCH 13/18] avoid Edge mixed-content Security issue by providing https licenser server URL --- samples/dash-if-reference-player/app/sources.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/dash-if-reference-player/app/sources.json b/samples/dash-if-reference-player/app/sources.json index 45d6dffa2c..94fc9b2a7b 100644 --- a/samples/dash-if-reference-player/app/sources.json +++ b/samples/dash-if-reference-player/app/sources.json @@ -807,7 +807,7 @@ "url": "https://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)", "protData": { "com.microsoft.playready": { - "serverURL": "http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:true,sl:150)", + "serverURL": "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:true,sl:150)", "sessionType": "persistent-license" } } From e34f189a6b6cdf93c20ce2ed991b46fdb48a9c1a Mon Sep 17 00:00:00 2001 From: nicosang Date: Wed, 15 Jan 2020 15:07:34 +0100 Subject: [PATCH 14/18] update parseFloat call --- src/dash/parser/matchers/DurationMatcher.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dash/parser/matchers/DurationMatcher.js b/src/dash/parser/matchers/DurationMatcher.js index f25fc4fd52..c5c3d972c6 100644 --- a/src/dash/parser/matchers/DurationMatcher.js +++ b/src/dash/parser/matchers/DurationMatcher.js @@ -66,12 +66,12 @@ class DurationMatcher extends BaseMatcher { str => { //str = "P10Y10M10DT10H10M10.1S"; const match = durationRegex.exec(str); - let result = (parseFloat(match[2] || 0) * SECONDS_IN_YEAR + - parseFloat(match[4] || 0) * SECONDS_IN_MONTH + - parseFloat(match[6] || 0) * SECONDS_IN_DAY + - parseFloat(match[8] || 0) * SECONDS_IN_HOUR + - parseFloat(match[10] || 0) * SECONDS_IN_MIN + - parseFloat(match[12] || 0)); + let result = (parseFloat(match[3] || 0) * SECONDS_IN_YEAR + + parseFloat(match[5] || 0) * SECONDS_IN_MONTH + + parseFloat(match[7] || 0) * SECONDS_IN_DAY + + parseFloat(match[9] || 0) * SECONDS_IN_HOUR + + parseFloat(match[11] || 0) * SECONDS_IN_MIN + + parseFloat(match[13] || 0)); if (match[1] !== undefined) { result = -result; From be72f165c25460d1f6efe5d70d000b7df5b6832f Mon Sep 17 00:00:00 2001 From: dsi Date: Mon, 20 Jan 2020 11:58:46 +0100 Subject: [PATCH 15/18] Adjust tests in MediaController --- .../streaming.controllers.MediaController.js | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/test/unit/streaming.controllers.MediaController.js b/test/unit/streaming.controllers.MediaController.js index 752260fd1b..c8e220c795 100644 --- a/test/unit/streaming.controllers.MediaController.js +++ b/test/unit/streaming.controllers.MediaController.js @@ -239,7 +239,7 @@ describe('MediaController', function () { }); it('getTracksFor should return an empty array if parameters are defined, but internal tracks array is empty', function () { - const trackArray = mediaController.getTracksFor(Constants.VIDEO,{id: 'id'}); + const trackArray = mediaController.getTracksFor(Constants.VIDEO, {id: 'id'}); expect(trackArray).to.be.instanceOf(Array); // jshint ignore:line expect(trackArray).to.be.empty; // jshint ignore:line @@ -436,7 +436,6 @@ describe('MediaController', function () { }); it('should check initial media settings to choose initial track with a string/regex lang', function () { - const trackType = 'audio'; const streamInfo = { id: 'id' }; @@ -452,6 +451,13 @@ describe('MediaController', function () { mediaController.addTrack(track); + let trackList = mediaController.getTracksFor(trackType, streamInfo); + expect(trackList).to.have.lengthOf(1); + expect(objectUtils.areEqual(trackList[0], track)).to.be.true; // jshint ignore:line + + let currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + expect(objectUtils.areEqual(currentTrack, track)).to.be.false; // jshint ignore:line + // call to checkInitialMediaSettingsForType mediaController.setInitialSettings(trackType, { lang: 'fr|en|qtz', @@ -459,12 +465,11 @@ describe('MediaController', function () { }); mediaController.checkInitialMediaSettingsForType(trackType, streamInfo); - const currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); expect(objectUtils.areEqual(currentTrack, track)).to.be.true; // jshint ignore:line }); it('should check initial media settings to choose initial track with a regex lang', function () { - const trackType = 'audio'; const streamInfo = { id: 'id' }; @@ -490,6 +495,15 @@ describe('MediaController', function () { mediaController.addTrack(frTrack); mediaController.addTrack(qtzTrack); + let trackList = mediaController.getTracksFor(trackType, streamInfo); + expect(trackList).to.have.lengthOf(2); + expect(objectUtils.areEqual(trackList[0], frTrack)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(trackList[1], qtzTrack)).to.be.true; // jshint ignore:line + + let currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.false; // jshint ignore:line + expect(objectUtils.areEqual(currentTrack, qtzTrack)).to.be.false; // jshint ignore:line + // call to checkInitialMediaSettingsForType mediaController.setInitialSettings(trackType, { lang: /qtz|mis/, @@ -497,7 +511,7 @@ describe('MediaController', function () { }); mediaController.checkInitialMediaSettingsForType(trackType, streamInfo); - const currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); + currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo); expect(objectUtils.areEqual(currentTrack, qtzTrack)).to.be.true; // jshint ignore:line }); }); From 5f9dc0b0f6d4cb440e273758f580cf44453e2967 Mon Sep 17 00:00:00 2001 From: nicosang Date: Mon, 27 Jan 2020 15:16:10 +0100 Subject: [PATCH 16/18] update computeLiveDelay function --- src/streaming/controllers/PlaybackController.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index c548ddbb12..54b74e779c 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -228,10 +228,16 @@ function PlaybackController() { function computeLiveDelay(fragmentDuration, dvrWindowSize) { let delay, ret, + r, startTime; - let startTimeParameters = getStartTimeFromUriParameters(); const END_OF_PLAYLIST_PADDING = 10; + let uriParameters = uriFragmentModel.getURIFragmentData(); + + if (uriParameters) { + r = parseInt(uriParameters.r, 10); + } + let suggestedPresentationDelay = adapter.getSuggestedPresentationDelay(); if (settings.get().streaming.useSuggestedPresentationDelay && suggestedPresentationDelay !== null) { @@ -240,8 +246,8 @@ function PlaybackController() { delay = 0; } else if (mediaPlayerModel.getLiveDelay()) { delay = mediaPlayerModel.getLiveDelay(); // If set by user, this value takes precedence - } else if (startTimeParameters && startTimeParameters.fragT) { - delay = startTimeParameters.fragT; + } else if (r) { + delay = r; } else if (!isNaN(fragmentDuration)) { delay = fragmentDuration * settings.get().streaming.liveDelayFragmentCount; From 5b4cc89e4c4046d48df1160d91552f351ab0323e Mon Sep 17 00:00:00 2001 From: dsi Date: Tue, 28 Jan 2020 10:26:41 +0100 Subject: [PATCH 17/18] Increase version number from 3.0.1 to 3.0.2 --- package.json | 2 +- src/core/Version.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6d046c52a8..b4efa38884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dashjs", - "version": "3.0.1", + "version": "3.0.2", "description": "A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.", "main": "build/es5/index.js", "types": "build/typings/index.d.ts", diff --git a/src/core/Version.js b/src/core/Version.js index 428615b98c..4c1a777929 100644 --- a/src/core/Version.js +++ b/src/core/Version.js @@ -1,4 +1,4 @@ -const VERSION = '3.0.1'; +const VERSION = '3.0.2'; export function getVersionString() { return VERSION; } From 37ac86b0376a46334fc746a1cf12e948e02ec145 Mon Sep 17 00:00:00 2001 From: dsilhavy Date: Wed, 29 Jan 2020 17:32:40 +0100 Subject: [PATCH 18/18] Update README.md Add information about the sample folder to the Readme.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f6bd49290a..553b569bcf 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ For help, join our [Slack channel](https://dashif-slack.azurewebsites.net), our ## Reference players The released [pre-built reference players](http://reference.dashif.org/dash.js/) are publicly accessible if you want direct access without writing any Javascript. +Multiple dash.js samples covering a wide set of common use cases can be found in the project's sample folder hosted [here](http://reference.dashif.org/dash.js/latest/samples/index.html). + The [nightly build of the /dev branch reference player](http://reference.dashif.org/dash.js/nightly/samples/dash-if-reference-player/index.html), is pre-release but contains the latest fixes. It is a good place to start if you are debugging playback problems. A nightly build of the latest minified files are also available: [dash.all.min.js](http://reference.dashif.org/dash.js/nightly/dist/dash.all.min.js) and its debug version [dash.all.debug.js](http://reference.dashif.org/dash.js/nightly/dist/dash.all.debug.js).