Skip to content

Commit 6449b30

Browse files
feat(DRM): Add preferred key systems config
We'll allow users to configure key system priorities through the 'drm.preferredKeySystems' configuration. Edge now supports both Widevine and PlayReady, and users should be able to configure the priorities of the key systems. If no key system is preferred, or no preferred key systems is valid, we'll fall back to the original behavior of choosing the first key system with configured license server url in the manifest. Example: player.configure('drm.preferredKeySystems', [ 'com.widevine.alpha', 'com.microsoft.playready', ]); If both Widevine and Playready have a license server and are supported, the config sets Widevine as the first choice, and PlayReady as the second. Issue shaka-project#3002 Change-Id: Idb881ef4921259bb3e1879cd8ec2bb6966d6580d
1 parent 9b4502c commit 6449b30

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

externs/shaka/player.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,8 @@ shaka.extern.AdvancedDrmConfiguration;
574574
* ((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
575575
* undefined),
576576
* logLicenseExchange: boolean,
577-
* updateExpirationTime: number
577+
* updateExpirationTime: number,
578+
* preferredKeySystems: !Array.<string>
578579
* }}
579580
*
580581
* @property {shaka.extern.RetryParameters} retryParameters
@@ -612,6 +613,9 @@ shaka.extern.AdvancedDrmConfiguration;
612613
* @property {number} updateExpirationTime
613614
* <i>Defaults to 1.</i> <br>
614615
* The frequency in seconds with which to check the expiration of a session.
616+
* @property {!Array.<string>} preferredKeySystems
617+
* <i>Defaults to an empty array. </i> <br>
618+
* Specifies the priorties of available DRM key systems.
615619
*
616620
* @exportDoc
617621
*/

lib/media/drm_engine.js

+38-5
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,22 @@ shaka.media.DrmEngine = class {
10161016
shaka.util.Error.Category.DRM,
10171017
shaka.util.Error.Code.NO_RECOGNIZED_KEY_SYSTEMS);
10181018
}
1019+
1020+
// If we have configured preferredKeySystems, choose a preferred keySystem
1021+
// if available.
1022+
for (const preferredKeySystem of this.config_.preferredKeySystems) {
1023+
for (const variant of variants) {
1024+
const decodingInfo = variant.decodingInfos.find((decodingInfo) => {
1025+
return decodingInfo.supported &&
1026+
decodingInfo.keySystemAccess != null &&
1027+
decodingInfo.keySystemAccess.keySystem == preferredKeySystem;
1028+
});
1029+
if (decodingInfo) {
1030+
return decodingInfo.keySystemAccess;
1031+
}
1032+
}
1033+
}
1034+
10191035
// Try key systems with configured license servers first. We only have to
10201036
// try key systems without configured license servers for diagnostic
10211037
// reasons, so that we can differentiate between "none of these key
@@ -1071,6 +1087,24 @@ shaka.media.DrmEngine = class {
10711087
}
10721088
}
10731089

1090+
// If we have configured preferredKeySystems, choose the preferred one if
1091+
// available.
1092+
for (const keySystem of this.config_.preferredKeySystems) {
1093+
if (configsByKeySystem.has(keySystem)) {
1094+
const config = configsByKeySystem.get(keySystem);
1095+
try {
1096+
mediaKeySystemAccess = // eslint-disable-next-line no-await-in-loop
1097+
await navigator.requestMediaKeySystemAccess(keySystem, [config]);
1098+
return mediaKeySystemAccess;
1099+
} catch (error) {
1100+
// Suppress errors.
1101+
shaka.log.v2(
1102+
'Requesting', keySystem, 'failed with config', config, error);
1103+
}
1104+
this.destroyer_.ensureNotDestroyed();
1105+
}
1106+
}
1107+
10741108
// Try key systems with configured license servers first. We only have to
10751109
// try key systems without configured license servers for diagnostic
10761110
// reasons, so that we can differentiate between "none of these key
@@ -1092,14 +1126,13 @@ shaka.media.DrmEngine = class {
10921126

10931127
try {
10941128
mediaKeySystemAccess = // eslint-disable-next-line no-await-in-loop
1095-
await navigator.requestMediaKeySystemAccess(
1096-
keySystem, [config]);
1129+
await navigator.requestMediaKeySystemAccess(keySystem, [config]);
10971130
return mediaKeySystemAccess;
10981131
} catch (error) {
1132+
// Suppress errors.
10991133
shaka.log.v2(
1100-
'Requesting', keySystem, 'failed with config',
1101-
config, error);
1102-
} // Suppress errors.
1134+
'Requesting', keySystem, 'failed with config', config, error);
1135+
}
11031136
this.destroyer_.ensureNotDestroyed();
11041137
}
11051138
}

lib/util/player_configuration.js

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ shaka.util.PlayerConfiguration = class {
7575
initDataTransform: shaka.media.DrmEngine.defaultInitDataTransform,
7676
logLicenseExchange: false,
7777
updateExpirationTime: 1,
78+
preferredKeySystems: [],
7879
};
7980

8081
const manifest = {

test/media/drm_engine_unit.js

+24
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,30 @@ function testDrmEngine(useMediaCapabilities) {
257257
}
258258
});
259259

260+
it('chooses systems by configured preferredKeySystems', async () => {
261+
// Accept both drm.abc and drm.def. Only one can be chosen.
262+
setRequestMediaKeySystemAccessSpy(['drm.abc', 'drm.def']);
263+
config.preferredKeySystems = ['drm.def'];
264+
drmEngine.configure(config);
265+
logErrorSpy.and.stub();
266+
267+
const variants = manifest.variants;
268+
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds,
269+
useMediaCapabilities);
270+
271+
if (useMediaCapabilities) {
272+
expect(variants[0].decodingInfos.length).toBe(2);
273+
} else {
274+
expect(requestMediaKeySystemAccessSpy).toHaveBeenCalledTimes(1);
275+
// Although drm.def appears second in the manifest, it is queried first
276+
// and also selected because it has a server configured.
277+
const calls = requestMediaKeySystemAccessSpy.calls;
278+
expect(calls.argsFor(0)[0]).toBe('drm.def');
279+
}
280+
expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
281+
.toBe('drm.def');
282+
});
283+
260284
it('chooses systems with configured license servers', async () => {
261285
// Accept both drm.abc and drm.def. Only one can be chosen.
262286
setRequestMediaKeySystemAccessSpy(['drm.abc', 'drm.def']);

0 commit comments

Comments
 (0)