Skip to content

Commit

Permalink
Only use configured license servers if provided
Browse files Browse the repository at this point in the history
If the application developer specifies license servers, only those
should be used.  Before this, a manifest-specified license server
for a certain key system could still be used if the application didn't
provide one.

Now, if there are _any_ license servers specified by the app, _no_
license servers will be used from the manifest.  This is important
because it allows the application a clear way to indicate which DRM
systems should be used on platforms with multiple DRM systems.

The new order of preference for drmInfo:
1. Clear Key config, used for debugging, should override everything else.
   (The application can still specify a clearkey license server.)
2. Application-configured servers, if any are present, should override
   anything from the manifest.  Nuance: if key system A is in the manifest
   and key system B is in the player config, only B will be used, not A.
3. Manifest-provided license servers are only used if nothing else is
   specified.

Introduced in #1644 to solve #484
Internal issue b/131264101
Closes #1905

Change-Id: I1a36a70044dc7bcc22681e3e4246d0a43d58e413
  • Loading branch information
joeyparrish committed May 2, 2019
1 parent aac3657 commit d27d818
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 10 deletions.
35 changes: 28 additions & 7 deletions lib/media/drm_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,8 @@ shaka.media.DrmEngine.prototype.queryMediaKeys_ = function(configsByKeySystem) {
return Promise.reject(new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.DRM,
shaka.util.Error.Code.NO_LICENSE_SERVER_GIVEN));
shaka.util.Error.Code.NO_LICENSE_SERVER_GIVEN,
this.currentDrmInfo_.keySystem));
}

return mediaKeySystemAccess.createMediaKeys();
Expand Down Expand Up @@ -1931,24 +1932,44 @@ shaka.media.DrmEngine.processDrmInfos_ =
*/
shaka.media.DrmEngine.fillInDrmInfoDefaults_ = function(
drmInfo, servers, advancedConfigs) {
const keySystem = drmInfo.keySystem;

if (!keySystem) {
if (!drmInfo.keySystem) {
// This is a placeholder from the manifest parser for an unrecognized key
// system. Skip this entry, to avoid logging nonsensical errors.
return;
}

const server = servers.get(keySystem);
if (server) {
// The order of preference for drmInfo:
// 1. Clear Key config, used for debugging, should override everything else.
// (The application can still specify a clearkey license server.)
// 2. Application-configured servers, if any are present, should override
// anything from the manifest. Nuance: if key system A is in the manifest
// and key system B is in the player config, only B will be used, not A.
// 3. Manifest-provided license servers are only used if nothing else is
// specified.
// This is important because it allows the application a clear way to indicate
// which DRM systems should be used on platforms with multiple DRM systems.
// The only way to get license servers from the manifest is not to specify any
// in your player config.

if (drmInfo.keySystem == 'org.w3.clearkey' && drmInfo.licenseServerUri) {
// Preference 1: Clear Key with pre-configured keys will have a data URI
// assigned as its license server. Don't change anything.
return;
} else if (servers.size) {
// Preference 2: If anything is configured at the application level,
// override whatever was in the manifest.
const server = servers.get(drmInfo.keySystem) || '';
drmInfo.licenseServerUri = server;
} else {
// Preference 3: Keep whatever we had in drmInfo.licenseServerUri, which
// comes from the manifest.
}

if (!drmInfo.keyIds) {
drmInfo.keyIds = [];
}

const advancedConfig = advancedConfigs.get(keySystem);
const advancedConfig = advancedConfigs.get(drmInfo.keySystem);
if (advancedConfig) {
if (!drmInfo.distinctiveIdentifierRequired) {
drmInfo.distinctiveIdentifierRequired =
Expand Down
1 change: 1 addition & 0 deletions lib/util/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ shaka.util.Error.Code = {
/**
* No license server was given for the key system signaled by the manifest.
* A license server URI is required for every key system.
* <br> error.data[0] is the key system identifier.
*/
'NO_LICENSE_SERVER_GIVEN': 6012,

Expand Down
47 changes: 44 additions & 3 deletions test/media/drm_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,46 @@ describe('DrmEngine', function() {
}
});

it('overrides manifest with configured license servers', async () => {
// Accept both drm.abc and drm.def. Only one can be chosen.
requestMediaKeySystemAccessSpy.and.callFake(
fakeRequestMediaKeySystemAccess.bind(null, ['drm.abc', 'drm.def']));

// Add manifest-supplied license servers for both.
for (const drmInfo of manifest.periods[0].variants[0].drmInfos) {
if (drmInfo.keySystem == 'drm.abc') {
drmInfo.licenseServerUri = 'http://foo.bar/abc';
} else if (drmInfo.keySystem == 'drm.def') {
drmInfo.licenseServerUri = 'http://foo.bar/def';
}

// Make sure we didn't somehow choose manifest-supplied values that
// match the config. This would invalidate parts of the test.
const configServer = config.servers[drmInfo.keySystem];
expect(drmInfo.licenseServerUri).not.toEqual(configServer);
}

// Remove the server URI for drm.abc from the config, so that only drm.def
// could be used, in spite of the manifest-supplied license server URI.
delete config.servers['drm.abc'];
drmEngine.configure(config);

// Ignore error logs, which we expect to occur due to the missing server.
logErrorSpy.and.stub();

const variants = Periods.getAllVariantsFrom(manifest.periods);
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);

// Although drm.def appears second in the manifest, it is queried first
// because it has a server configured. The manifest-supplied server for
// drm.abc will not be used.
expect(requestMediaKeySystemAccessSpy.calls.count()).toBe(1);
const selectedDrmInfo = drmEngine.getDrmInfo();
expect(selectedDrmInfo).not.toBe(null);
expect(selectedDrmInfo.keySystem).toBe('drm.def');
expect(selectedDrmInfo.licenseServerUri).toBe(config.servers['drm.def']);
});

it('detects content type capabilities of key system', async () => {
requestMediaKeySystemAccessSpy.and.callFake(
fakeRequestMediaKeySystemAccess.bind(null, ['drm.abc']));
Expand Down Expand Up @@ -472,7 +512,7 @@ describe('DrmEngine', function() {
expect(requestMediaKeySystemAccessSpy.calls.count()).toBe(1);
});

it('uses advanced config to override DrmInfo fields', async () => {
it('uses advanced config to fill in DrmInfo', async () => {
// Leave only one drmInfo
manifest = new shaka.test.ManifestGenerator()
.addPeriod(0)
Expand Down Expand Up @@ -516,7 +556,7 @@ describe('DrmEngine', function() {
}
});

it('does not use config if DrmInfo already filled out', async () => {
it('prefers advanced config from manifest if present', async () => {
// Leave only one drmInfo
manifest = new shaka.test.ManifestGenerator()
.addPeriod(0)
Expand Down Expand Up @@ -585,7 +625,8 @@ describe('DrmEngine', function() {
shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.DRM,
shaka.util.Error.Code.NO_LICENSE_SERVER_GIVEN));
shaka.util.Error.Code.NO_LICENSE_SERVER_GIVEN,
'drm.abc'));
}
});
}); // describe('init')
Expand Down

0 comments on commit d27d818

Please sign in to comment.