From a018f53307741bb22c4f077e2ed633c6b1490c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Fri, 27 Dec 2024 15:48:16 +0100 Subject: [PATCH] fix(Widevine): Add default audio/video robustness for Widevine (#7808) The following bug is avoided in Chromium: `It is recommended that a robustness level be specified. Not specifying the robustness level could result in unexpected behavior.Understand this warningAI` It also prevents errors when initializing EME on Android. Fixes https://github.com/shaka-project/shaka-player/issues/7760 --- demo/config.js | 16 +++++++++++++++- externs/shaka/player.js | 14 +++++++++++++- lib/drm/drm_engine.js | 12 ++++++++++++ lib/drm/drm_utils.js | 12 ++++++++++++ lib/util/player_configuration.js | 2 ++ test/drm/drm_utils_unit.js | 16 ++++++++++++++++ 6 files changed, 70 insertions(+), 2 deletions(-) diff --git a/demo/config.js b/demo/config.js index c476b2e4b0..89b50a6ceb 100644 --- a/demo/config.js +++ b/demo/config.js @@ -123,6 +123,14 @@ shakaDemo.Config = class { /** @private */ addDrmSection_() { + const widevineRobustnessLevels = { + '': '', + 'SW_SECURE_CRYPTO': 'SW_SECURE_CRYPTO', + 'SW_SECURE_DECODE': 'SW_SECURE_DECODE', + 'HW_SECURE_CRYPTO': 'HW_SECURE_CRYPTO', + 'HW_SECURE_DECODE': 'HW_SECURE_DECODE', + 'HW_SECURE_ALL': 'HW_SECURE_ALL', + }; const docLink = this.resolveExternLink_('.DrmConfiguration'); this.addSection_('DRM', docLink) .addBoolInput_('Delay License Request Until Played', @@ -137,7 +145,13 @@ shakaDemo.Config = class { 'drm.parseInbandPsshEnabled') .addTextInput_('Min HDCP version', 'drm.minHdcpVersion') .addBoolInput_('Ignore duplicate init data', - 'drm.ignoreDuplicateInitData'); + 'drm.ignoreDuplicateInitData') + .addSelectInput_('Default audio robustness for Widevine', + 'drm.defaultAudioRobustnessForWidevine', + widevineRobustnessLevels, widevineRobustnessLevels) + .addSelectInput_('Default video robustness for Widevine', + 'drm.defaultVideoRobustnessForWidevine', + widevineRobustnessLevels, widevineRobustnessLevels); const advanced = shakaDemoMain.getConfiguration().drm.advanced || {}; const addDRMAdvancedField = (name, valueName, suggestions, arrayString = false) => { diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 69841a3a14..dc0f4b5369 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -941,7 +941,9 @@ shaka.extern.PersistentSessionMetadata; * keySystemsMapping: !Object., * parseInbandPsshEnabled: boolean, * minHdcpVersion: string, - * ignoreDuplicateInitData: boolean + * ignoreDuplicateInitData: boolean, + * defaultAudioRobustnessForWidevine: string, + * defaultVideoRobustnessForWidevine: string * }} * * @property {shaka.extern.RetryParameters} retryParameters @@ -1025,6 +1027,16 @@ shaka.extern.PersistentSessionMetadata; *
* Defaults to false on Tizen 2, and true for all * other browsers. + * @property {string} defaultAudioRobustnessForWidevine + * Specify the default audio security level for Widevine when audio robustness + * is not specified. + *
+ * Defaults to 'SW_SECURE_CRYPTO'. + * @property {string} defaultVideoRobustnessForWidevine + * Specify the default video security level for Widevine when video robustness + * is not specified. + *
+ * Defaults to 'SW_SECURE_DECODE'. * @exportDoc */ shaka.extern.DrmConfiguration; diff --git a/lib/drm/drm_engine.js b/lib/drm/drm_engine.js index 3fadcd3989..d909ab8a45 100644 --- a/lib/drm/drm_engine.js +++ b/lib/drm/drm_engine.js @@ -419,6 +419,10 @@ shaka.drm.DrmEngine = class { * * robustness can be either a single item as a string or multiple items as * an array of strings. + * + * @param {!Array.} drmInfos + * @param {string} robustnessType + * @return {!Array.} */ const expandRobustness = (drmInfos, robustnessType) => { const newDrmInfos = []; @@ -427,6 +431,14 @@ shaka.drm.DrmEngine = class { (this.config_.advanced && this.config_.advanced[drmInfo.keySystem] && this.config_.advanced[drmInfo.keySystem][robustnessType]) || ''; + if (items == '' && + shaka.drm.DrmUtils.isWidevineKeySystem(drmInfo.keySystem)) { + if (robustnessType == 'audioRobustness') { + items = [this.config_.defaultAudioRobustnessForWidevine]; + } else if (robustnessType == 'videoRobustness') { + items = [this.config_.defaultVideoRobustnessForWidevine]; + } + } if (typeof items === 'string') { // if drmInfo's robustness has already been expanded, // use the drmInfo directly. diff --git a/lib/drm/drm_utils.js b/lib/drm/drm_utils.js index 4505ffc10e..7f6310bae5 100644 --- a/lib/drm/drm_utils.js +++ b/lib/drm/drm_utils.js @@ -113,6 +113,18 @@ shaka.drm.DrmUtils = class { return drmInfo ? drmInfo.keySystem : ''; } + /** + * @param {?string} keySystem + * @return {boolean} + */ + static isWidevineKeySystem(keySystem) { + if (keySystem) { + return !!keySystem.match(/^com\.widevine\.alpha/); + } + + return false; + } + /** * @param {?string} keySystem * @return {boolean} diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index c42311baa0..0e7d803b39 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -94,6 +94,8 @@ shaka.util.PlayerConfiguration = class { parseInbandPsshEnabled: shaka.util.Platform.isXboxOne(), minHdcpVersion: '', ignoreDuplicateInitData: !shaka.util.Platform.isTizen2(), + defaultAudioRobustnessForWidevine: 'SW_SECURE_CRYPTO', + defaultVideoRobustnessForWidevine: 'SW_SECURE_DECODE', }; // The Xbox One and PS4 only support the Playready DRM, so they should diff --git a/test/drm/drm_utils_unit.js b/test/drm/drm_utils_unit.js index 3a5cda9c86..7ddfb81da3 100644 --- a/test/drm/drm_utils_unit.js +++ b/test/drm/drm_utils_unit.js @@ -145,6 +145,22 @@ describe('DrmUtils', () => { }); }); // describe('getCommonDrmInfos') + describe('isWidevineKeySystem', () => { + it('should return true for Widevine', () => { + expect(shaka.drm.DrmUtils.isWidevineKeySystem( + 'com.widevine.alpha')).toBe(true); + expect(shaka.drm.DrmUtils.isWidevineKeySystem( + 'com.widevine.alpha.anything')).toBe(true); + }); + + it('should return false for non-Widevine key systems', () => { + expect(shaka.drm.DrmUtils.isWidevineKeySystem( + 'com.microsoft.playready')).toBe(false); + expect(shaka.drm.DrmUtils.isWidevineKeySystem( + 'com.apple.fps')).toBe(false); + }); + }); + describe('isPlayReadyKeySystem', () => { it('should return true for MS & Chromecast PlayReady', () => { expect(shaka.drm.DrmUtils.isPlayReadyKeySystem(