From c67d3d311dc85d785ab16e93959c42e954eb77b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Cunat?= Date: Wed, 15 Jul 2020 10:55:42 +0200 Subject: [PATCH] Store and use fragmentedText settings in localStorage (#3293) * use text settings stored in DomStorage if no other settings set * modify multi captions test to ease multiple configuration (default, domStorage, initial settings...) * do not reset text settings between load * modify multi captions test to ease multiple configuration (default, domStorage, initial settings...) * fix pb when calling setTextDefaultEnabled(false) before player initialization * use /* */ for comments in sample page code * Update multi tracks captions sample * MediaController: update selectInitialTrack() to return first track in case of fragmentedText tracks * typo Co-authored-by: Bertrand Berthelot --- contrib/akamai/controlbar/ControlBar.js | 2 + samples/captioning/multi-track-captions.html | 118 ++++++++++++++++--- src/streaming/Stream.js | 9 +- src/streaming/controllers/MediaController.js | 60 ++++++---- src/streaming/text/TextController.js | 35 +++++- test/unit/mocks/MediaControllerMock.js | 2 + test/unit/streaming.text.TextController.js | 4 +- 7 files changed, 176 insertions(+), 54 deletions(-) diff --git a/contrib/akamai/controlbar/ControlBar.js b/contrib/akamai/controlbar/ControlBar.js index 8eb68f30bb..a22a3066e4 100644 --- a/contrib/akamai/controlbar/ControlBar.js +++ b/contrib/akamai/controlbar/ControlBar.js @@ -491,6 +491,8 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) { menuHandlersList.push(func); captionBtn.addEventListener('click', func); captionBtn.classList.remove('hide'); + } else { + setMenuItemsState(e.index + 1, 'caption-list'); } }; diff --git a/samples/captioning/multi-track-captions.html b/samples/captioning/multi-track-captions.html index ce33bb9412..60389b11c7 100644 --- a/samples/captioning/multi-track-captions.html +++ b/samples/captioning/multi-track-captions.html @@ -13,28 +13,75 @@ @@ -47,12 +94,24 @@ .dash-video-player { width: 640px; } + + .settings { + clear: both; + } + .settings>div { + padding: 5px 0; + } + + label { + font-size: 1.1em; + } + - +
- +
@@ -85,6 +144,35 @@
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
diff --git a/src/streaming/Stream.js b/src/streaming/Stream.js index 92a77fbce9..b7c3b5c1c0 100644 --- a/src/streaming/Stream.js +++ b/src/streaming/Stream.js @@ -489,14 +489,9 @@ function Stream(config) { return; } - if (type !== Constants.FRAGMENTED_TEXT || (type === Constants.FRAGMENTED_TEXT && textController.getTextDefaultEnabled())) { - mediaController.checkInitialMediaSettingsForType(type, streamInfo); - initialMediaInfo = mediaController.getCurrentTrackFor(type, streamInfo); - } - if (type === Constants.FRAGMENTED_TEXT && !textController.getTextDefaultEnabled()) { - initialMediaInfo = mediaController.getTracksFor(type, streamInfo)[0]; - } + mediaController.checkInitialMediaSettingsForType(type, streamInfo); + initialMediaInfo = mediaController.getCurrentTrackFor(type, streamInfo); eventBus.trigger(Events.STREAM_INITIALIZING, { streamInfo: streamInfo, diff --git a/src/streaming/controllers/MediaController.js b/src/streaming/controllers/MediaController.js index 53eaa9e540..cf809b4298 100644 --- a/src/streaming/controllers/MediaController.js +++ b/src/streaming/controllers/MediaController.js @@ -78,12 +78,6 @@ function MediaController() { const tracksForType = getTracksFor(type, streamInfo); const tracks = []; - if (type === Constants.FRAGMENTED_TEXT) { - // Choose the first track - setTrack(tracksForType[0]); - return; - } - if (!settings) { settings = domStorage.getSavedMediaSettings(type); setInitialSettings(type, settings); @@ -100,10 +94,10 @@ function MediaController() { } if (tracks.length === 0) { - setTrack(selectInitialTrack(tracksForType)); + setTrack(selectInitialTrack(type, tracksForType), true); } else { if (tracks.length > 1) { - setTrack(selectInitialTrack(tracks)); + setTrack(selectInitialTrack(type, tracks)); } else { setTrack(tracks[0]); } @@ -185,9 +179,10 @@ function MediaController() { /** * @param {MediaInfo} track + * @param {boolean} noSettingsSave specify if settings must be not be saved * @memberof MediaController# */ - function setTrack(track) { + function setTrack(track, noSettingsSave) { if (!track || !track.streamInfo) return; const type = track.type; @@ -199,28 +194,31 @@ function MediaController() { tracks[id][type].current = track; - if (tracks[id][type].current) { + if (tracks[id][type].current && !(noSettingsSave && type === Constants.FRAGMENTED_TEXT)) { eventBus.trigger(Events.CURRENT_TRACK_CHANGED, {oldMediaInfo: current, newMediaInfo: track, switchMode: switchMode[type]}); } - let settings = extractSettings(track); + if (!noSettingsSave) { - if (!settings || !tracks[id][type].storeLastSettings) return; + let settings = extractSettings(track); - if (settings.roles) { - settings.role = settings.roles[0]; - delete settings.roles; - } + if (!settings || !tracks[id][type].storeLastSettings) return; - if (settings.accessibility) { - settings.accessibility = settings.accessibility[0]; - } + if (settings.roles) { + settings.role = settings.roles[0]; + delete settings.roles; + } - if (settings.audioChannelConfiguration) { - settings.audioChannelConfiguration = settings.audioChannelConfiguration[0]; - } + if (settings.accessibility) { + settings.accessibility = settings.accessibility[0]; + } + + if (settings.audioChannelConfiguration) { + settings.audioChannelConfiguration = settings.audioChannelConfiguration[0]; + } - domStorage.setSavedMediaSettings(type, settings); + domStorage.setSavedMediaSettings(type, settings); + } } /** @@ -245,6 +243,13 @@ function MediaController() { return initialSettings[type]; } + /** + * @memberof MediaController# + */ + function saveTextSettingsDisabled() { + domStorage.setSavedMediaSettings(Constants.FRAGMENTED_TEXT, null); + } + /** * @param {string} type * @param {string} mode @@ -384,13 +389,17 @@ function MediaController() { function resetInitialSettings() { initialSettings = { audio: null, - video: null + video: null, + fragmentedText: null }; } - function selectInitialTrack(tracks) { + function selectInitialTrack(type, tracks) { + if (type === Constants.FRAGMENTED_TEXT) return tracks[0]; + let mode = getSelectionModeForInitialTrack(); let tmpArr = []; + const getTracksWithHighestBitrate = function (trackArr) { let max = 0; let result = []; @@ -497,6 +506,7 @@ function MediaController() { isMultiTrackSupportedByType: isMultiTrackSupportedByType, isTracksEqual: isTracksEqual, matchSettings: matchSettings, + saveTextSettingsDisabled: saveTextSettingsDisabled, setConfig: setConfig, reset: reset }; diff --git a/src/streaming/text/TextController.js b/src/streaming/text/TextController.js index a894b00811..00b5af31cf 100644 --- a/src/streaming/text/TextController.js +++ b/src/streaming/text/TextController.js @@ -55,6 +55,7 @@ function TextController() { ttmlParser, eventBus, defaultSettings, + initialSettingsSet, lastEnabledIndex, textDefaultEnabled, // this is used for default settings (each time a file is loaded, we check value of this settings ) allTracksAreDisabled, // this is used for one session (when a file has been loaded, we use this settings to enable/disable text) @@ -65,11 +66,11 @@ function TextController() { function setup() { - defaultSettings = {}; + defaultSettings = null; lastEnabledIndex = -1; - textDefaultEnabled = false; forceTextStreaming = false; textTracksAdded = false; + initialSettingsSet = false; disableTextBeforeTextTracksAdded = false; textTracks = TextTracks(context).getInstance(); vttParser = VTTParser(context).getInstance(); @@ -79,6 +80,7 @@ function TextController() { textTracks.initialize(); eventBus.on(Events.TEXT_TRACKS_QUEUE_INITIALIZED, onTextTracksAdded, instance); + eventBus.on(Events.CURRENT_TRACK_CHANGED, onCurrentTrackChanged, instance); /* * register those event callbacks in order to detect switch of periods and set @@ -174,15 +176,20 @@ function TextController() { function setTextDefaultLanguage(lang) { checkParameterType(lang, 'string'); + if (!defaultSettings) { + defaultSettings = {}; + } defaultSettings.lang = lang; + initialSettingsSet = true; } function setInitialSettings(settings) { defaultSettings = settings; + initialSettingsSet = true; } function getTextDefaultLanguage() { - return defaultSettings.lang || ''; + return defaultSettings && defaultSettings.lang || ''; } function onTextTracksAdded(e) { @@ -200,8 +207,8 @@ function TextController() { }); } - if (!textDefaultEnabled || disableTextBeforeTextTracksAdded) { - // disable text at startup + if (textDefaultEnabled === false || ( textDefaultEnabled === undefined && !defaultSettings ) || disableTextBeforeTextTracksAdded) { + // disable text at startup if explicitely configured with setTextDefaultEnabled(false) or if there is no defaultSettings (configuration or from domStorage) this.setTextTrack(-1); } @@ -214,6 +221,19 @@ function TextController() { textTracksAdded = true; } + function onCurrentTrackChanged(event) { + if (!initialSettingsSet && event && event.newMediaInfo) { + let mediaInfo = event.newMediaInfo; + if (mediaInfo.type === Constants.FRAGMENTED_TEXT) { + defaultSettings = { + lang: mediaInfo.lang, + role: mediaInfo.roles[0], + accessibility: mediaInfo.accessibility[0] + }; + } + } + } + function setTextDefaultEnabled(enable) { checkParameterType(enable,'boolean'); textDefaultEnabled = enable; @@ -227,7 +247,7 @@ function TextController() { } function getTextDefaultEnabled() { - return textDefaultEnabled; + return textDefaultEnabled === undefined ? false : textDefaultEnabled; } function enableText(enable) { @@ -282,6 +302,9 @@ function TextController() { let oldTrackIdx = textTracks.getCurrentTrackIdx(); if (oldTrackIdx !== idx) { + if (allTracksAreDisabled && mediaController) { + mediaController.saveTextSettingsDisabled(); + } textTracks.setModeForTrackIdx(oldTrackIdx, Constants.TEXT_HIDDEN); textTracks.setCurrentTrackIdx(idx); textTracks.setModeForTrackIdx(idx, Constants.TEXT_SHOWING); diff --git a/test/unit/mocks/MediaControllerMock.js b/test/unit/mocks/MediaControllerMock.js index 9cc46d793c..f0aa5a97e1 100644 --- a/test/unit/mocks/MediaControllerMock.js +++ b/test/unit/mocks/MediaControllerMock.js @@ -113,6 +113,8 @@ class MediaControllerMock { setConfig() {} + saveTextSettingsDisabled() {} + reset() { this.setup(); } diff --git a/test/unit/streaming.text.TextController.js b/test/unit/streaming.text.TextController.js index cffca5278e..1bc727230f 100644 --- a/test/unit/streaming.text.TextController.js +++ b/test/unit/streaming.text.TextController.js @@ -40,7 +40,9 @@ describe('TextController', function () { }); afterEach(function () { - delete global.document; + if (typeof window !== 'undefined' && global !== window) { + delete global.document; + } }); beforeEach(function () {