summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/encrypted-media/scripts
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/encrypted-media/scripts
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/encrypted-media/scripts')
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js46
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js35
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js26
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js52
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js52
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/events.js59
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/expiration.js43
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js72
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/invalid-license.js38
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js103
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/keystatuses.js165
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js50
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/onencrypted.js48
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js95
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js158
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js77
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js109
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js104
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js115
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js114
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js109
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js109
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-events.js131
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-expired.js95
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multikey-sequential.js122
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multisession.js76
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration-keystatus.js78
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration.js80
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-setMediaKeys.js105
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-two-videos.js83
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary-waitingforkey.js71
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/playback-temporary.js82
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/requestmediakeysystemaccess.js341
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/reset-src-after-setmediakeys.js61
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-playback.js79
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-resetting-src.js79
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-at-same-time.js59
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-different-mediakeys.js98
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-the-same-mediakeys.js46
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js54
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/setmediakeys.js50
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeys.js184
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysession.js452
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysystemaccess.js147
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/temporary-license-type.js61
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/unique-origin.js64
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/update-disallowed-input.js43
-rw-r--r--testing/web-platform/tests/encrypted-media/scripts/waiting-for-a-key.js166
48 files changed, 4686 insertions, 0 deletions
diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js b/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js
new file mode 100644
index 0000000000..ffab4a3491
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js
@@ -0,0 +1,46 @@
+function runTest(config, qualifier)
+{
+ function checkEncryptionScheme(encryptionScheme)
+ {
+ var simpleConfig = getSimpleConfiguration();
+ assert_greater_than(simpleConfig[0].audioCapabilities.length, 0);
+ simpleConfig[0].audioCapabilities.forEach(function(capability) {
+ capability.encryptionScheme = encryptionScheme;
+ });
+
+ return navigator.requestMediaKeySystemAccess(config.keysystem, simpleConfig)
+ .then(
+ function(access) {
+ var actualConfiguration = access.getConfiguration();
+ for (let i = 0; i < actualConfiguration.audioCapabilities.length; i++) {
+ const capability = actualConfiguration.audioCapabilities[i];
+
+ // If "encryptionScheme" is not supported, fail.
+ if (!('encryptionScheme' in capability)) {
+ return Promise.reject('Not implemented');
+ }
+
+ // If "encryptionScheme" is supported, it should be returned.
+ assert_equals(capability.encryptionScheme, encryptionScheme);
+ }
+ return Promise.resolve('Supported');
+ },
+ function error() {
+ // CDM does not support "encryptionScheme". Test should still pass.
+ return Promise.resolve('Not supported');
+ });
+ }
+
+ promise_test(
+ () => checkEncryptionScheme('cenc'),
+ testnamePrefix(qualifier, config.keysystem) + ' support for "cenc" encryption scheme.');
+
+ promise_test(
+ () => checkEncryptionScheme('cbcs'),
+ testnamePrefix(qualifier, config.keysystem) + ' support for "cbcs" encryption scheme.');
+
+ promise_test(
+ () => checkEncryptionScheme('cbcs-1-9'),
+ testnamePrefix(qualifier, config.keysystem) +
+ ' support for "cbcs-1-9" encryption scheme.');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js b/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js
new file mode 100644
index 0000000000..5c7cb6e4b9
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js
@@ -0,0 +1,35 @@
+ function runTest( config, qualifier )
+ {
+ function checkInitDataType(initDataType)
+ {
+ return isInitDataTypeSupported(initDataType).then(function(result) {
+ // If |initDataType| is not supported, simply succeed.
+ if (!result)
+ return Promise.resolve('Not supported');
+
+ return navigator.requestMediaKeySystemAccess( config.keysystem, getSimpleConfigurationForInitDataType(initDataType))
+ .then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession();
+ var initData = getInitData(initDataType);
+ return mediaKeySession.generateRequest(initDataType, initData);
+ });
+ });
+ }
+
+ promise_test(function()
+ {
+ return checkInitDataType('webm');
+ }, testnamePrefix( qualifier, config.keysystem ) + ' support for "webm".');
+
+ promise_test(function()
+ {
+ return checkInitDataType('cenc');
+ }, testnamePrefix( qualifier, config.keysystem ) + ' support for "cenc".');
+
+ promise_test(function()
+ {
+ return checkInitDataType('keyids');
+ }, testnamePrefix( qualifier, config.keysystem ) + ' support for "keyids".');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js b/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js
new file mode 100644
index 0000000000..ac30819695
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js
@@ -0,0 +1,26 @@
+function runTest(config, qualifier)
+{
+ function checkStatusForMinHdcpVersionPolicy(hdcpVersion)
+ {
+ return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration())
+ .then(function(access) {
+ return access.createMediaKeys();
+ })
+ .then(function(mediaKeys) {
+ // As HDCP policy depends on the hardware running this test,
+ // don't bother checking the result returned as it may or
+ // may not be supported. This simply verifies that
+ // getStatusForPolicy() exists and doesn't blow up.
+ return mediaKeys.getStatusForPolicy({minHdcpVersion: hdcpVersion});
+ });
+ }
+
+ promise_test(
+ () => checkStatusForMinHdcpVersionPolicy(''),
+ testnamePrefix(qualifier, config.keysystem) +
+ ' support for empty HDCP version.');
+
+ promise_test(
+ () => checkStatusForMinHdcpVersionPolicy('1.0'),
+ testnamePrefix(qualifier, config.keysystem) + ' support for HDCP 1.0.');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js b/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js
new file mode 100644
index 0000000000..7a5c073bfa
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js
@@ -0,0 +1,52 @@
+// This test is only applicable to clearkey
+function runTest(config, qualifier)
+{
+ var testname = testnamePrefix(qualifier, config.keysystem) + ' test handling of non-ASCII responses for update()';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ promise_test(function (test) {
+ var initDataType;
+ var initData;
+ var mediaKeySession;
+ var messageEventFired = false;
+
+ var p = navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+ initData = getInitData(config.content, initDataType);
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ mediaKeySession = mediaKeys.createSession();
+ var eventWatcher = new EventWatcher(test, mediaKeySession, ['message']);
+ var promise = eventWatcher.wait_for('message');
+ mediaKeySession.generateRequest(initDataType, initData);
+ return promise;
+ }).then(function (messageEvent) {
+ // |jwkSet| contains a non-ASCII character \uDC00.
+ var jwkSet = '{"keys":[{'
+ + '"kty":"oct",'
+ + '"k":"MDEyMzQ1Njc4OTAxMjM0NQ",'
+ + '"kid":"MDEyMzQ1Njc4O\uDC00TAxMjM0NQ"'
+ + '}]}';
+ messageEventFired = true;
+ return messageEvent.target.update(stringToUint8Array(jwkSet));
+ }).catch(function (error) {
+ // Ensure we reached the update() call we are trying to test.
+ if (!messageEventFired) {
+ assert_unreached(
+ `Failed to reach the update() call. Error: '${error.name}' '${error.message}'`);
+ }
+
+ // Propagate the error on through.
+ throw error;
+ });
+
+ return promise_rejects_js(
+ test, TypeError, p,
+ 'update() should fail because the processed message has non-ASCII character.');
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js b/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js
new file mode 100644
index 0000000000..44f683eac8
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js
@@ -0,0 +1,52 @@
+function runTest(config, qualifier)
+{
+ var testname = testnamePrefix(qualifier, config.keysystem) + ' test MediaKeySession closed event.';
+
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{
+ contentType: config.audioType
+ }],
+ videoCapabilities: [{
+ contentType: config.videoType
+ }],
+ sessionTypes: ['temporary']
+ };
+
+ promise_test(function (test) {
+ var initDataType;
+ var initData;
+ var mediaKeySession;
+
+ return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ mediaKeySession = mediaKeys.createSession();
+ if(config.initData) {
+ initData = config.initData;
+ } else {
+ initData = stringToUint8Array(atob(config.content.keys[0].initData));
+ }
+ return mediaKeySession.generateRequest(initDataType, initData);
+ }).then(function() {
+ // close() should result in the closed promise being
+ // fulfilled.
+ return mediaKeySession.close();
+ }).then(function (result) {
+ assert_equals(result, undefined);
+ // Wait for the session to be closed.
+ return mediaKeySession.closed;
+ }).then(function (result) {
+ assert_equals(result, undefined);
+ // Now that the session is closed, verify that the
+ // closed attribute immediately returns a fulfilled
+ // promise.
+ return mediaKeySession.closed;
+ }).then(function (result) {
+ assert_equals(result, undefined);
+ }).catch(function(error) {
+ assert_unreached('Error: ' + error.name);
+ });
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/events.js b/testing/web-platform/tests/encrypted-media/scripts/events.js
new file mode 100644
index 0000000000..85c86ae78d
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/events.js
@@ -0,0 +1,59 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem) + ', basic events';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test)
+ {
+ var initDataType;
+ var initData;
+ var mediaKeySession;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function processMessage(event)
+ {
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.target, mediaKeySession);
+ assert_equals(event.type, 'message');
+ assert_in_array(event.messageType,['license-request', 'individualization-request']);
+
+ config.messagehandler( event.messageType, event.message ).then(function(response) {
+ waitForEventAndRunStep('keystatuseschange', mediaKeySession, test.step_func(processKeyStatusesChange), test);
+ return mediaKeySession.update( response );
+ }).catch(onFailure);
+ }
+
+ function processKeyStatusesChange(event)
+ {
+ assert_true(event instanceof Event);
+ assert_equals(event.target, mediaKeySession);
+ assert_equals(event.type, 'keystatuseschange');
+ test.done();
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem,[configuration]).then(function(access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+
+ if (config.initDataType && config.initData) {
+ initData = config.initData;
+ } else {
+ initData = getInitData(config.content, initDataType);
+ }
+
+ return access.createMediaKeys();
+ }).then(test.step_func(function(mediaKeys) {
+ mediaKeySession = mediaKeys.createSession();
+ waitForEventAndRunStep('message', mediaKeySession, test.step_func(processMessage), test);
+ return mediaKeySession.generateRequest(initDataType, initData);
+ })).catch(onFailure);
+ }, testname );
+
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/expiration.js b/testing/web-platform/tests/encrypted-media/scripts/expiration.js
new file mode 100644
index 0000000000..96b7fbfeef
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/expiration.js
@@ -0,0 +1,43 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem) + ', expiration';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test) {
+
+ var _mediaKeys,
+ _mediaKeySession;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, [ 'license-request', 'individualization-request' ] );
+
+ config.messagehandler(event.messageType, event.message, {expiration: config.expiration}).then(function(response) {
+ return event.target.update(response);
+ }).then(test.step_func(function() {
+ assert_approx_equals(event.target.expiration, config.expiration, 4000, "expiration attribute should equal provided expiration time");
+ test.done();
+ })).catch(onFailure);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ _mediaKeySession = _mediaKeys.createSession( 'temporary' );
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ return _mediaKeySession.generateRequest(config.initDataType, config.initData);
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js b/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js
new file mode 100644
index 0000000000..9fd42ee85f
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js
@@ -0,0 +1,72 @@
+function runTest(config,qualifier) {
+ var tests = [ ], initData, keyId;
+ function push_test(keysystem, initDataType, initData, testname) {
+ tests.push({ keysystem: keysystem, initDataType: initDataType, initData: initData, testname: testname });
+ }
+
+ initData = new Uint8Array(70000);
+ push_test(config.keysystem, 'webm', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, webm, initData longer than 64Kb characters');
+
+ initData = new Uint8Array(70000);
+ push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, initData longer than 64Kb characters');
+
+ initData = new Uint8Array(70000);
+ push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, initData longer than 64Kb characters');
+
+ // Invalid 'pssh' box as the size specified is larger than what
+ // is provided.
+ initData = new Uint8Array([
+ 0x00, 0x00, 0xff, 0xff, // size = huge
+ 0x70, 0x73, 0x73, 0x68, // 'pssh'
+ 0x00, // version = 0
+ 0x00, 0x00, 0x00, // flags
+ 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID
+ 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
+ 0x00, 0x00, 0x00, 0x00 // datasize
+ ]);
+ push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (invalid pssh)');
+
+ // Invalid data as type = 'psss'.
+ initData = new Uint8Array([
+ 0x00, 0x00, 0x00, 0x00, // size = 0
+ 0x70, 0x73, 0x73, 0x73, // 'psss'
+ 0x00, // version = 0
+ 0x00, 0x00, 0x00, // flags
+ 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID
+ 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
+ 0x00, 0x00, 0x00, 0x00 // datasize
+ ]);
+ push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (not pssh)');
+
+ // Valid key ID size must be at least 1 character for keyids.
+ keyId = new Uint8Array(0);
+ initData = stringToUint8Array(createKeyIDs(keyId));
+ push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, invalid initdata (too short key ID)');
+
+ // Valid key ID size must be less than 512 characters for keyids.
+ keyId = new Uint8Array(600);
+ initData = stringToUint8Array(createKeyIDs(keyId));
+ push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, invalid initdata (too long key ID)');
+
+ Promise.all( tests.map(function(testspec) {
+ return isInitDataTypeSupported(testspec.keysystem,testspec.initDataType);
+ })).then(function(results) {
+ tests.filter(function(testspec, i) { return results[i]; } ).forEach(function(testspec) {
+ promise_test(function(test) {
+ // Create a "temporary" session for |keysystem| and call generateRequest()
+ // with the provided initData. generateRequest() should fail with an
+ // TypeError. Returns a promise that is resolved
+ // if the error occurred and rejected otherwise.
+ var p = navigator.requestMediaKeySystemAccess(testspec.keysystem, getSimpleConfigurationForInitDataType(testspec.initDataType)).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession("temporary");
+ return mediaKeySession.generateRequest(testspec.initDataType, testspec.initData);
+ });
+
+ return promise_rejects_js(test, TypeError, p,
+ "generateRequest() should fail");
+ }, testspec.testname);
+ });
+ });
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js b/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js
new file mode 100644
index 0000000000..89d43769e5
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js
@@ -0,0 +1,38 @@
+function runTest(config)
+{
+ promise_test(function (test) {
+ var initDataType;
+ var initData;
+ var keySystem = config.keysystem;
+ var invalidLicense = new Uint8Array([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]);
+ var messageEventFired = false;
+
+ var p = navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function (access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+ initData = getInitData(initDataType);
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var keySession = mediaKeys.createSession();
+ var eventWatcher = new EventWatcher(test, keySession, ['message']);
+ var promise = eventWatcher.wait_for('message');
+ keySession.generateRequest(initDataType, initData);
+ return promise;
+ }).then(function (messageEvent) {
+ messageEventFired = true;
+ return messageEvent.target.update(invalidLicense);
+ }).catch(function (error) {
+ // Ensure we reached the update() call we are trying to test.
+ if (!messageEventFired) {
+ assert_unreached(
+ `Failed to reach the update() call. Error: '${error.name}' '${error.message}'`);
+ }
+
+ // Propagate the error on through.
+ throw error;
+ });
+
+ return promise_rejects_js(
+ test, TypeError, p,
+ 'update() should fail because of an invalid license.');
+ }, 'Update with invalid Clear Key license');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js b/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js
new file mode 100644
index 0000000000..e9bf10e886
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js
@@ -0,0 +1,103 @@
+function runTest(config,qualifier)
+{
+ var testname = testnamePrefix(qualifier, config.keysystem) + ', temporary, keystatuses, multiple sessions';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) configuration.initDataTypes = [config.initDataType];
+
+ async_test(function(test)
+ {
+ var mediaKeySession1;
+ var mediaKeySession2;
+
+ // Even though key ids are uint8, using printable values so that
+ // they can be verified easily.
+ var key1 = new Uint8Array(config.content.keys[0].kid),
+ key2 = new Uint8Array(config.content.keys[1].kid),
+ variant1 = config.content.keys[0].variantId,
+ variant2 = config.content.keys[1].variantId;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test,error);
+ }
+
+ function processMessage1(event)
+ {
+ // This should only be called for session1.
+ assert_equals(event.target, mediaKeySession1);
+
+ // No keys added yet.
+ verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [], unexpected: [key1, key2]});
+
+ // Add key1 to session1.
+ config.messagehandler(event.messageType, event.message, {variantId:variant1}).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+
+ }
+
+ function processKeyStatusesChange1(event)
+ {
+ // This should only be called for session1.
+ assert_equals(event.target, mediaKeySession1);
+
+ // Check that keyStatuses contains the expected key1 only.
+ verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]});
+
+ // Now trigger a message event on session2.
+ mediaKeySession2.generateRequest(config.initDataType, config.initData[1]).catch(onFailure);
+ }
+
+ function processMessage2(event)
+ {
+ // This should only be called for session2.
+ assert_equals(event.target, mediaKeySession2);
+
+ // session2 has no keys added yet.
+ verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [], unexpected: [key1, key2]});
+
+ // session1 should still have 1 key.
+ verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]});
+
+ // Add key2 to session2.
+ config.messagehandler(event.messageType, event.message, {variantId:variant2}).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function processKeyStatusesChange2(event)
+ {
+ // This should only be called for session2.
+ assert_equals(event.target, mediaKeySession2);
+
+ // Check that keyStatuses contains the expected key2 only.
+ verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [key2], unexpected: [key1]});
+
+ // session1 should still have 1 key.
+ verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]});
+
+ test.done();
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ mediaKeySession1 = mediaKeys.createSession();
+ mediaKeySession2 = mediaKeys.createSession();
+
+ // There should be no keys defined on either session.
+ verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [], unexpected: [key1, key2]});
+ verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [], unexpected: [key1, key2]});
+
+ // Bind all the event handlers now.
+ waitForEventAndRunStep('message', mediaKeySession1, processMessage1, test);
+ waitForEventAndRunStep('message', mediaKeySession2, processMessage2, test);
+ waitForEventAndRunStep('keystatuseschange', mediaKeySession1, processKeyStatusesChange1, test);
+ waitForEventAndRunStep('keystatuseschange', mediaKeySession2, processKeyStatusesChange2, test);
+
+ // Generate a request on session1.
+ return mediaKeySession1.generateRequest(config.initDataType, config.initData[0]);
+ }).catch(onFailure);
+ }, testname );
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js b/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js
new file mode 100644
index 0000000000..8d33dd4210
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js
@@ -0,0 +1,165 @@
+function runTest(config,qualifier)
+{
+ var testname = testnamePrefix(qualifier, config.keysystem) + ', temporary, keystatuses';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test)
+ {
+ var mediaKeySession;
+ var initDataType;
+ var initData;
+ var closed = false;
+
+ // Even though key ids are uint8, using printable values so that
+ // they can be verified easily.
+ var key1 = new Uint8Array(config.content.keys[0].kid),
+ key2 = new Uint8Array(config.content.keys[1].kid),
+ key1String = arrayBufferAsString(key1),
+ key2String = arrayBufferAsString(key2);
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function processMessage(event)
+ {
+ // No keys added yet.
+ assert_equals(mediaKeySession.keyStatuses.size, 0);
+
+ waitForEventAndRunStep('keystatuseschange', mediaKeySession, processKeyStatusesChange, test);
+
+ // Add keys to session
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function checkKeyStatusFor2Keys()
+ {
+ // Two keys added, so both should show up in |keyStatuses|.
+ assert_equals(mediaKeySession.keyStatuses.size, 2);
+
+ // Check |keyStatuses| for 2 entries.
+ var result = [];
+ for (let item of mediaKeySession.keyStatuses) {
+ result.push({ key: arrayBufferAsString(item[0]), value: item[1] });
+ }
+ function lexicographical( a, b ) { return a < b ? -1 : a === b ? 0 : +1; }
+ function lexicographicalkey( a, b ) { return lexicographical( a.key, b.key ); }
+ var expected1 = [{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}].sort( lexicographicalkey );
+ var expected2 = [{ key: key1String, value: 'status-pending'}, { key: key2String, value: 'status-pending'}].sort( lexicographicalkey );
+ assert_in_array( JSON.stringify(result),
+ [ JSON.stringify(expected1),JSON.stringify(expected2) ],
+ "keystatuses should have the two expected keys with keystatus 'usable' or 'status-pending'");
+
+ // |keyStatuses| must contain both keys.
+ result = [];
+ for (var key of mediaKeySession.keyStatuses.keys()) {
+ result.push(arrayBufferAsString(key));
+ }
+ assert_array_equals(result,
+ [key1String, key2String].sort( lexicographical ),
+ "keyStatuses.keys() should return an iterable over the two expected keys");
+
+ // Both values in |mediaKeySession| should be 'usable' or 'status-pending'.
+ result = [];
+ for (var value of mediaKeySession.keyStatuses.values()) {
+ result.push(value);
+ }
+
+ assert_equals( result.length, 2, "keyStatuses.values() should have two elements" );
+ assert_equals( result[0], result[1], "the values in keyStatuses.values() should be equal" );
+ assert_in_array( result[0], [ 'usable', 'status-pending' ] );
+
+ // Check |keyStatuses.entries()|.
+ result = [];
+ for (var entry of mediaKeySession.keyStatuses.entries()) {
+ result.push({ key: arrayBufferAsString(entry[0]), value: entry[1] });
+ }
+ assert_in_array(JSON.stringify(result),
+ [ JSON.stringify(expected1), JSON.stringify(expected2) ],
+ "keyStatuses.entries() should return an iterable over the two expected keys, with keystatus 'usable' or 'status-pending'");
+
+ // forEach() should return both entries.
+ result = [];
+ mediaKeySession.keyStatuses.forEach(function(status, keyId) {
+ result.push({ key: arrayBufferAsString(keyId), value: status });
+ });
+ assert_in_array(JSON.stringify(result),
+ [ JSON.stringify(expected1), JSON.stringify(expected2) ],
+ "keyStatuses.forEach() should iterate over the two expected keys, with keystatus 'usable' or 'status-pending'");
+
+ // has() and get() should return the expected values.
+ assert_true(mediaKeySession.keyStatuses.has(key1), "keyStatuses should have key1");
+ assert_true(mediaKeySession.keyStatuses.has(key2), "keyStatuses should have key2");
+ assert_in_array(mediaKeySession.keyStatuses.get(key1), [ 'usable', 'status-pending' ], "key1 should have status 'usable' or 'status-pending'");
+ assert_in_array(mediaKeySession.keyStatuses.get(key2), [ 'usable', 'status-pending' ], "key2 should have status 'usable' or 'status-pending'");
+
+ // Try some invalid keyIds.
+ var invalid1 = key1.subarray(0, key1.length - 1);
+ assert_false(mediaKeySession.keyStatuses.has(invalid1), "keystatuses should not have invalid key (1)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid1), undefined, "keystatus value for invalid key should be undefined (1)");
+
+ var invalid2 = key1.subarray(1);
+ assert_false(mediaKeySession.keyStatuses.has(invalid2), "keystatuses should not have invalid key (2)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid2), undefined, "keystatus value for invalid key should be undefined (2)");
+
+ var invalid3 = new Uint8Array(key1);
+ invalid3[0] += 1;
+ assert_false(mediaKeySession.keyStatuses.has(invalid3), "keystatuses should not have invalid key (3)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid3), undefined, "keystatus value for invalid key should be undefined (3)");
+
+ var invalid4 = new Uint8Array(key1);
+ invalid4[invalid4.length - 1] -= 1;
+ assert_false(mediaKeySession.keyStatuses.has(invalid4), "keystatuses should not have invalid key (4)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid4), undefined, "keystatus value for invalid key should be undefined (4)");
+
+ var invalid5 = new Uint8Array(key1.length + 1);
+ invalid5.set(key1, 1); // First element will be 0.
+ assert_false(mediaKeySession.keyStatuses.has(invalid5), "keystatuses should not have invalid key (5)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid5), undefined, "keystatus value for invalid key should be undefined (5)");
+
+ var invalid6 = new Uint8Array(key1.length + 1);
+ invalid6.set(key1, 0); // Last element will be 0.
+ assert_false(mediaKeySession.keyStatuses.has(invalid6), "keystatuses should not have invalid key (6)");
+ assert_equals(mediaKeySession.keyStatuses.get(invalid6), undefined, "keystatus value for invalid key should be undefined (6)");
+ }
+
+ function processKeyStatusesChange(event)
+ {
+ if (!closed)
+ {
+ // The first keystatuseschange (caused by update())
+ // should include both keys.
+ checkKeyStatusFor2Keys();
+
+ mediaKeySession.close().catch(onFailure);
+ closed = true;
+ }
+ else
+ {
+ // The second keystatuseschange (caused by close())
+ // should not have any keys.
+ assert_equals(mediaKeySession.keyStatuses.size, 0);
+ test.done();
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(test.step_func(function(mediaKeys) {
+ mediaKeySession = mediaKeys.createSession();
+
+ // There should be no keys defined yet.
+ //verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [], unexpected: [key1, key2] });
+
+ waitForEventAndRunStep('message', mediaKeySession, processMessage, test);
+ return mediaKeySession.generateRequest(config.initDataType, config.initData);
+ })).catch(onFailure);
+ }, testname );
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js b/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js
new file mode 100644
index 0000000000..2642c71e0e
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js
@@ -0,0 +1,50 @@
+ function runTest(config,qualifier) {
+ // After creation, the MediaKeySession object is not
+ // callable, and we should get a InvalidStateError.
+
+ promise_test(function()
+ {
+ return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession();
+
+ var arbitraryResponse = new Uint8Array([0x00, 0x11]);
+ return mediaKeySession.update(arbitraryResponse).then(function(result) {
+ assert_unreached('update() succeeded unexpectedly.');
+ }).catch(function(error) {
+ assert_equals(error.name, 'InvalidStateError');
+ });
+ });
+ }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, update() immediately after createSession()');
+
+ promise_test(function()
+ {
+ return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession();
+
+ return mediaKeySession.close().then(function(result) {
+ assert_unreached('close() succeeded unexpectedly.');
+ }).catch(function(error) {
+ assert_equals(error.name, 'InvalidStateError');
+ });
+ });
+ }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, close() immediately after createSession()');
+
+ promise_test(function()
+ {
+ return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession();
+
+ return mediaKeySession.remove().then(function(result) {
+ assert_unreached('remove() succeeded unexpectedly.');
+ }).catch(function(error) {
+ assert_equals(error.name, 'InvalidStateError');
+ });
+ });
+ }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, remove() immediately after createSession()');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js b/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js
new file mode 100644
index 0000000000..acf0ffacc0
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js
@@ -0,0 +1,48 @@
+function runTest(config) {
+ var expectedInitData = [];
+ expectedInitData.push(stringToUint8Array(atob(config.keys[0].initData)));
+ expectedInitData.push(stringToUint8Array(atob(config.keys[1].initData)));
+
+ // Will get 2 identical events, one for audio, one for video.
+ var expectedEvents = 2;
+ var currentData;
+
+ async_test(function (test) {
+ var video = config.video,
+ mediaSource,
+ onEncrypted = function (event) {
+ currentData = new Uint8Array(event.initData);
+ assert_equals(event.target, config.video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+ assert_equals(event.initDataType, 'cenc');
+ // At this point we do not know if the event is related to audio or video. So check for both expected init data
+ assert_true(checkInitData(currentData, expectedInitData[0]) || checkInitData(currentData, expectedInitData[1]));
+
+ if (--expectedEvents === 0) {
+ test.done();
+ }
+ };
+
+ waitForEventAndRunStep('encrypted', video, onEncrypted, test);
+ testmediasource(config).then(function (source) {
+ mediaSource = source;
+ config.video.src = URL.createObjectURL(mediaSource);
+ return source.done;
+ }).then(function(){
+ video.play();
+ });
+ }, 'encrypted fired on encrypted media file.');
+}
+
+function checkInitData(data, expectedData) {
+ if (data.length !== expectedData.length) {
+ return false;
+ }
+ for (var i = 0; i < data.length; i++) {
+ if (data[i] !== expectedData[i]) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js
new file mode 100644
index 0000000000..8a6cacedb4
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js
@@ -0,0 +1,95 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix( qualifier, config.keysystem )
+ + ', persistent-license, '
+ + /video\/([^;]*)/.exec( config.videoType )[ 1 ]
+ + ', playback, destroy and acknowledge';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-license' ] };
+
+ async_test( function(test) {
+
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _sessionId,
+ _startedReleaseSequence = false;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData ).then( test.step_func(function() {
+ assert_not_equals( _mediaKeySession.sessionId, undefined, "SessionId should be defined" );
+ _sessionId = _mediaKeySession.sessionId;
+ })).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > ( config.duration || 1 ) && !_startedReleaseSequence) {
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ _video.pause();
+ _video.removeAttribute('src');
+ _video.load();
+
+ _startedReleaseSequence = true;
+ _mediaKeySession.closed.then(onClosed);
+ _mediaKeySession.remove().catch(onFailure);
+ }
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ function onClosed() {
+ // Try and reload and check this fails
+ var mediaKeySession = _mediaKeys.createSession( 'persistent-license' );
+ mediaKeySession.load(_sessionId).then( test.step_func(function(success) {
+ assert_false( success, "Load of removed session shouold fail" );
+ test.done();
+ })).catch(onFailure);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ _mediaKeySession = _mediaKeys.createSession('persistent-license');
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js
new file mode 100644
index 0000000000..2d99f679f4
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js
@@ -0,0 +1,158 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-license, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, check events';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-license' ] };
+
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _receivedTimeupdateEvent = false,
+ _startedReleaseSequence = false,
+ _events = [ ];
+
+ function recordEventFunc(eventType) {
+ return function() { _events.push(eventType); };
+ }
+
+ function recordEventFuncAndCheckExpirationForNaN(eventType) {
+ return function() {
+ _events.push(eventType);
+ assert_equals(_mediaKeySession.expiration, NaN);
+ };
+ }
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals( event.target, _mediaKeySession );
+ assert_true( event instanceof window.MediaKeyMessageEvent );
+ assert_equals( event.type, 'message');
+
+ if (!_startedReleaseSequence) {
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+ } else {
+ assert_equals(event.messageType, 'license-release');
+ }
+
+ if (event.messageType !== 'individualization-request') {
+ _events.push(event.messageType);
+ }
+
+ config.messagehandler(event.messageType, event.message ).then(function(response) {
+ _events.push(event.messageType + '-response');
+ return _mediaKeySession.update(response);
+ }).then(test.step_func(function() {
+ _events.push(event.messageType + '-response-resolved');
+ if (event.messageType === 'license-release') {
+ test.step_timeout(function() {
+ checkEventSequence(_events, [
+ 'generaterequest',
+ [ // potentially repeating
+ 'license-request',
+ 'license-request-response',
+ 'license-request-response-resolved'
+ ],
+ 'keystatuseschange-usablekey',
+ 'playing',
+ 'remove-resolved',
+ 'keystatuseschange-allkeysreleased',
+ 'license-release',
+ 'license-release-response',
+ 'closed-attribute-resolved',
+ 'license-release-response-resolved',
+ 'keystatuseschange-empty'
+ ]);
+ test.done();
+ }, 100);
+ }
+ })).catch(onFailure);
+ }
+
+ function onKeyStatusesChange(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.Event);
+ assert_equals(event.type, 'keystatuseschange');
+ var hasKeys = false,
+ usableKey = false; // true if any key usable.
+ _mediaKeySession.keyStatuses.forEach(function(value, keyid) {
+ assert_in_array(value, ['usable', 'released']);
+ hasKeys = true;
+ usableKey = usableKey || (value === 'usable');
+ });
+
+ if (!hasKeys) {
+ _events.push('keystatuseschange-empty');
+ } else if (usableKey) {
+ _events.push('keystatuseschange-usablekey');
+ } else {
+ _events.push('keystatuseschange-allkeysreleased');
+ }
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData ).then(recordEventFunc('generaterequest')
+ ).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if ( _video.currentTime > ( config.duration || 1 ) && !_receivedTimeupdateEvent ) {
+ _receivedTimeupdateEvent = true;
+ _video.pause();
+ _video.removeAttribute('src');
+ _video.load();
+
+ _startedReleaseSequence = true;
+ _mediaKeySession.remove()
+ .then(recordEventFuncAndCheckExpirationForNaN('remove-resolved'))
+ .catch(onFailure);
+ }
+ }
+
+ function onPlaying(event) {
+ _events.push( 'playing' );
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ _mediaKeySession = _mediaKeys.createSession( 'persistent-license' );
+ waitForEventAndRunStep('keystatuseschange', _mediaKeySession, onKeyStatusesChange, test);
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.closed
+ .then(recordEventFuncAndCheckExpirationForNaN('closed-attribute-resolved'))
+ .catch(onFailure);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js
new file mode 100644
index 0000000000..c7e56e3aea
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js
@@ -0,0 +1,77 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-license, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + 'playback';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-license' ] };
+
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals( event.target, _mediaKeySession );
+ assert_true( event instanceof window.MediaKeyMessageEvent );
+ assert_equals( event.type, 'message');
+
+ assert_in_array( event.messageType, [ 'license-request', 'individualization-request' ] );
+
+ config.messagehandler(event.messageType, event.message).then( function( response ) {
+ return _mediaKeySession.update(response)
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData ).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1)) {
+ _video.pause();
+ test.done();
+ }
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ _mediaKeySession = _mediaKeys.createSession( 'persistent-license' );
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js
new file mode 100644
index 0000000000..e8e1e54790
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js
@@ -0,0 +1,109 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-usage-record, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, check events';
+
+ var configuration = { initDataTypes: [config.initDataType ],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['persistent-usage-record']};
+
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _sessionId,
+ _timeupdateEvent = false,
+ _events = [ ];
+
+ function recordEventFunc(eventType) {
+ return function() { _events.push(eventType); };
+ }
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ if (event.messageType !== 'individualization-request') {
+ _events.push(event.messageType);
+ }
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ _events.push(event.messageType + '-response');
+ return _mediaKeySession.update(response);
+ }).then(test.step_func(function() {
+ _events.push('update-resolved');
+ if (event.messageType === 'license-release') {
+ checkEventSequence( _events,
+ ['encrypted','generaterequest-done',
+ ['license-request', 'license-request-response', 'update-resolved'], // potentially repeating
+ 'keystatuseschange',
+ 'playing',
+ 'remove-resolved',
+ 'keystatuseschange',
+ 'license-release',
+ 'license-release-response',
+ 'closed-attribute-resolved',
+ 'update-resolved' ]);
+ test.done();
+ }
+
+ if ( event.messageType === 'license-request' ) {
+ _video.setMediaKeys(_mediaKeys);
+ }
+ })).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ _events.push(event.type);
+ _mediaKeySession.generateRequest( config.initDataType || event.initDataType,
+ config.initData || event.initData ).then( function() {
+ _events.push( 'generaterequest-done' );
+ _sessionId = _mediaKeySession.sessionId;
+ }).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1) && !_timeupdateEvent) {
+ _timeupdateEvent = true;
+ _video.pause();
+ _mediaKeySession.remove().then(recordEventFunc('remove-resolved')).catch(onFailure);
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, recordEventFunc('playing'), test);
+
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+
+ _mediaKeySession = _mediaKeys.createSession( 'persistent-usage-record' );
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ waitForEventAndRunStep('keystatuseschange', _mediaKeySession, recordEventFunc('keystatuseschange'), test);
+ _mediaKeySession.closed.then(recordEventFunc('closed-attribute-resolved'));
+ return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true;
+ }).then(function( success ) {
+ return testmediasource(config);
+ }).then(function(source) {
+ _video.src = URL.createObjectURL(source);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js
new file mode 100644
index 0000000000..1772b4bd5f
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js
@@ -0,0 +1,104 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-usage-record, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + 'playback';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-usage-record' ] };
+
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _releaseSequence = false;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ // event instance verification failing on CastTV
+ // assert_true( event instanceof window.MediaKeyMessageEvent );
+ assert_equals(event.type, 'message');
+
+ if (!_releaseSequence)
+ {
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+ }
+ else
+ {
+ assert_equals(event.messageType, 'license-release');
+ }
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).then(function() {
+ if(event.messageType === 'license-request') {
+ return _video.setMediaKeys(_mediaKeys);
+ } else if(event.messageType === 'license-release') {
+ test.done();
+ }
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData )
+ .catch(onFailure);
+ }
+
+ function onClosed(event) {
+ _video.src = "";
+ _video.setMediaKeys( null );
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > ( config.duration || 1) && !_releaseSequence) {
+ _video.removeEventListener('timeupdate', onTimeupdate );
+ _video.pause();
+ _releaseSequence = true;
+
+ _mediaKeySession.closed.then(test.step_func(onClosed));
+ _mediaKeySession.remove().catch(onFailure);
+
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ }
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ _mediaKeySession = _mediaKeys.createSession('persistent-usage-record');
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true;
+ }).then(function(success) {
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js
new file mode 100644
index 0000000000..83cba34028
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js
@@ -0,0 +1,115 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-license, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', ' + config.testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-license' ] };
+
+
+ async_test( function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _sessionId;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData ).then( function() {
+ _sessionId = _mediaKeySession.sessionId;
+ }).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1)) {
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ _video.pause();
+ _video.removeAttribute('src');
+ _video.load();
+
+ _mediaKeySession.closed
+ .then(test.step_func(onClosed))
+ .catch(onFailure);
+ _mediaKeySession.close()
+ .catch(onFailure);
+ }
+ }
+
+ function onClosed() {
+ // Open a new window in which we will attempt to play with the persisted license
+ var win = window.open(config.windowscript);
+ assert_not_equals(win, null, "Popup windows not allowed?");
+
+ // Lisen for an event from the new window containing its test assertions
+ window.addEventListener('message', test.step_func(function(messageEvent) {
+ if (messageEvent.data.testResult) {
+ messageEvent.data.testResult.forEach(test.step_func(function(assertion) {
+ assert_equals(assertion.actual, assertion.expected, assertion.message);
+ }));
+
+ win.close();
+ test.done();
+ }
+ }));
+
+ // Delete things which can't be cloned and posted over to the new window
+ delete config.video;
+ delete config.messagehandler;
+
+ // Post the config and session id to the new window when it is ready
+ win.onload = function() {
+ win.postMessage({config: config, sessionId: _sessionId}, '*');
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys( mediaKeys );
+ }).then(function() {
+ _mediaKeySession = _mediaKeys.createSession('persistent-license');
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js
new file mode 100644
index 0000000000..a04f97d2ca
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js
@@ -0,0 +1,114 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', persistent-usage-record, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, retrieve in new window';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'persistent-usage-record' ] };
+
+
+ async_test( function( test ) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _sessionId,
+ _isClosing = false;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initDataType || event.initDataType,
+ config.initData || event.initData ).then( function() {
+ _sessionId = _mediaKeySession.sessionId;
+ }).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array( event.messageType,['license-request', 'individualization-request']);
+
+ config.messagehandler( event.messageType, event.message ).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).then(function() {
+ return _video.setMediaKeys(_mediaKeys);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ function onTimeupdate(event) {
+ if (!_isClosing && _video.currentTime > (config.duration || 1)) {
+ _isClosing = true;
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ _video.pause();
+ _mediaKeySession.closed.then( test.step_func(onClosed));
+ _mediaKeySession.close();
+ }
+ }
+
+ function onClosed(event) {
+ _video.src = "";
+ _video.setMediaKeys( null );
+
+ var win = window.open(config.windowscript);
+ assert_not_equals(win, null, "Popup windows not allowed?");
+
+ window.addEventListener('message', test.step_func(function(event) {
+ if (event.data.testResult) {
+ event.data.testResult.forEach(test.step_func(function(assertion) {
+ assert_equals(assertion.actual, assertion.expected, assertion.message);
+ }));
+
+ win.close();
+ test.done();
+ }
+ }));
+
+ delete config.video;
+ delete config.messagehandler;
+
+ win.onload = function() {
+ win.postMessage({ config: config, sessionId: _sessionId }, '*');
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(mediaKeys);
+ }).then(function(){
+ _mediaKeySession = _mediaKeys.createSession( 'persistent-usage-record' );
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true;
+ }).then(function(success) {
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js
new file mode 100644
index 0000000000..8f5af2cd6b
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js
@@ -0,0 +1,109 @@
+function runTest(configEncrypted,configClear,qualifier) {
+
+ var testname = testnamePrefix(qualifier, configEncrypted.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(configEncrypted.videoType)[1]
+ + ', playback, encrypted and clear sources in separate segments';
+
+ var configuration = { initDataTypes: [ configEncrypted.initDataType ],
+ audioCapabilities: [ { contentType: configEncrypted.audioType } ],
+ videoCapabilities: [ { contentType: configEncrypted.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var didAppendEncrypted = false,
+ _video = configEncrypted.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _sourceBuffer;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onVideoError(event) {
+ var message = (_video.error || {}).message || 'Got unknown error from <video>';
+ forceTestFailureFromPromise(test, new Error(message));
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ configEncrypted.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ var initDataType = configEncrypted.initDataType || event.initDataType;
+ var initData = configEncrypted.initData || event.initData;
+
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest(initDataType, initData).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (configEncrypted.duration || 1) + (configClear.duration || 1)) {
+ _video.pause();
+ test.done();
+ }
+ if (_video.currentTime > 1 && !didAppendEncrypted) {
+ didAppendEncrypted = true;
+ _sourceBuffer.timestampOffset = configClear.duration;
+ fetchAndAppend(configEncrypted.videoPath).then(function() {
+ _mediaSource.endOfStream();
+ }).catch(onFailure);
+ }
+ }
+
+ function fetchAndAppend(path) {
+ return fetch(path).then(function(response) {
+ if (!response.ok) throw new Error('Resource fetch failed');
+ return response.arrayBuffer();
+ }).then(function(data) {
+ return new Promise(function(resolve, reject) {
+ _sourceBuffer.appendBuffer(data);
+ _sourceBuffer.addEventListener('updateend', resolve);
+ _sourceBuffer.addEventListener('error', reject);
+ });
+ });
+ }
+
+ _video.addEventListener('error', onVideoError);
+ navigator.requestMediaKeySystemAccess(configEncrypted.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+
+ return new Promise(function(resolve, reject) {
+ _mediaSource = new MediaSource();
+ _mediaSource.addEventListener('sourceopen', resolve);
+ _video.src = URL.createObjectURL(_mediaSource);
+ });
+ }).then(function() {
+ _sourceBuffer = _mediaSource.addSourceBuffer(configEncrypted.videoType);
+ return fetchAndAppend(configClear.videoPath);
+ }).then(function() {
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js
new file mode 100644
index 0000000000..41ea183f2e
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js
@@ -0,0 +1,109 @@
+function runTest(configEncrypted,configClear,qualifier) {
+
+ var testname = testnamePrefix(qualifier, configEncrypted.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(configEncrypted.videoType)[1]
+ + ', playback, encrypted and clear sources';
+
+ var configuration = { initDataTypes: [ configEncrypted.initDataType ],
+ audioCapabilities: [ { contentType: configEncrypted.audioType } ],
+ videoCapabilities: [ { contentType: configEncrypted.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var playbackCount = 0,
+ _video = configEncrypted.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ configEncrypted.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update( response );
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest(configEncrypted.initData ? configEncrypted.initDataType : event.initDataType,
+ configEncrypted.initData || event.initData).then(function(){
+ return _video.setMediaKeys(_mediaKeys);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event)
+ {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeUpdate, true);
+ }
+
+ function onTimeUpdate(event) {
+ if (_video.currentTime < (configEncrypted.duration || 0.5)) {
+ return;
+ }
+
+ _video.removeEventListener('timeupdate', onTimeUpdate, true);
+
+ resetSrc().then(function(){
+ if (playbackCount >= 2) {
+ test.done();
+ } else {
+ playbackCount++;
+ startPlayback();
+ }
+ }).catch(onFailure);
+ }
+
+ function resetSrc() {
+ _video.pause();
+ _video.removeAttribute('src');
+ _video.load();
+ return _video.setMediaKeys(null);
+ }
+
+ function startPlayback() {
+ // Alternate between encrypted and unencrypted files.
+ if (playbackCount % 2) {
+ // Unencrypted files don't require MediaKeys
+ testmediasource( configClear ).then(function( source ) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ _video.play();
+ }).catch(onFailure);
+ } else {
+ navigator.requestMediaKeySystemAccess(configEncrypted.keysystem, [ configuration ]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ _mediaKeySession = _mediaKeys.createSession( 'temporary' );
+ }).then(function() {
+ return testmediasource(configEncrypted);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }
+ }
+
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ startPlayback();
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-events.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-events.js
new file mode 100644
index 0000000000..28f45222cf
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-events.js
@@ -0,0 +1,131 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, check events';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource,
+ _timeupdateEvent = false,
+ _events = [ ];
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array( event.messageType, ['license-request', 'individualization-request']);
+
+ if (event.messageType !== 'individualization-request') {
+ _events.push(event.messageType);
+ }
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ _events.push('license-request-response');
+ waitForEventAndRunStep('keystatuseschange', _mediaKeySession, onKeyStatusesChange, test);
+ return _mediaKeySession.update( response );
+ }).then(function() {
+ _events.push('update-resolved');
+ }).catch(onFailure);
+ }
+
+ function onKeyStatusesChange(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.Event);
+ assert_equals(event.type, 'keystatuseschange');
+ var hasKeys = false, pendingKeys = false;
+ _mediaKeySession.keyStatuses.forEach(function(value, keyid) {
+ assert_in_array(value, ['status-pending', 'usable']);
+ hasKeys = true;
+ pendingKeys = pendingKeys || (value === 'status-pending');
+ });
+
+ if (!hasKeys) {
+ _events.push('emptykeyslist');
+ } else if (!pendingKeys ) {
+ _events.push('allkeysusable');
+ _video.setMediaKeys(_mediaKeys).catch(onFailure);
+ } else {
+ assert_unreached('unexpected ' + event.type + ' event');
+ }
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest(config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData ).then(function() {
+ _events.push('generaterequest');
+ }).catch(onFailure);
+ }
+
+ function onClosed(event) {
+ _events.push('closed-attribute-resolved');
+ setTimeout(test.step_func(function() {
+ checkEventSequence( _events,
+ ['generaterequest',
+ ['license-request', 'license-request-response', 'update-resolved'], // potentially repeating
+ 'allkeysusable',
+ 'playing',
+ 'closed-attribute-resolved',
+ 'close-promise-resolved',
+ 'emptykeyslist']);
+ test.done();
+ } ), 0);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1) && !_timeupdateEvent) {
+ _timeupdateEvent = true;
+ _video.pause();
+
+ _mediaKeySession.closed.then(test.step_func(onClosed));
+ _mediaKeySession.close().then(function() {
+ _events.push('close-promise-resolved');
+ }).catch(onFailure);
+ }
+ }
+
+ function onPlaying(event) {
+ _events.push('playing');
+
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ }).then(function() {
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-expired.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-expired.js
new file mode 100644
index 0000000000..3d1bd9591d
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-expired.js
@@ -0,0 +1,95 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', expired license';
+
+ var configuration = { initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['temporary'] };
+
+ async_test(function(test) {
+
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ // Only create the session for the first encrypted event
+ if (_mediaKeySession !== undefined) return;
+
+ var initDataType = config.initData ? config.initDataType : event.initDataType;
+ var initData = config.initData || event.initData;
+
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest(initDataType, initData).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ // Generate a license that expires 1 second from now.
+ var expiration = Date.now().valueOf() + 1000;
+ config.messagehandler(event.messageType, event.message, { expiration: expiration }).then(function(response) {
+ // Wait 2 seconds before calling update() to ensure that the
+ // license has really expired. This is to avoid problems
+ // where the browser starts buffering frames as soon as a
+ // valid license is received.
+ test.step_timeout(function() {
+ event.target.update(response).then(function() {
+ // License server may only have second granularity, so check
+ // that session expiration time is close to the desired value.
+ assert_approx_equals(event.target.expiration, expiration, 3000,
+ "expiration attribute should equal provided expiration time");
+ assert_greater_than(Date.now().valueOf(), expiration, "Starting play before license expired");
+ _video.play();
+ // Wait 2 seconds to ensure that the video does not play.
+ test.step_timeout(function() { test.done(); }, 2000);
+ }).catch(onFailure);
+ }, 2000);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', test.step_func(onTimeupdate), true);
+ }
+
+ function onTimeupdate(event) {
+ _video.pause();
+ assert_unreached("Playback should not start with expired license");
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multikey-sequential.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multikey-sequential.js
new file mode 100644
index 0000000000..597e8f9b0c
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multikey-sequential.js
@@ -0,0 +1,122 @@
+function runTest(config,qualifier) {
+
+ // config.initData contains a list of keys. We expect those to be needed in order and get
+ // one waitingforkey event for each one.
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', successful playback, temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', multiple keys, sequential'
+ + (config.checkReadyState ? ', readyState' : '');
+
+ var configuration = { initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['temporary'] };
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySessions = [],
+ _mediaSource,
+ _waitingForKey = false,
+ _playingCount = 0,
+ _canplayCount = 0,
+ _timeupdateWhileWaitingCount = 0;
+
+ function startNewSession() {
+ assert_less_than(_mediaKeySessions.length, config.initData.length);
+ var mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
+ _mediaKeySessions.push(mediaKeySession);
+ mediaKeySession.variantId = config.variantIds ? config.variantIds[_mediaKeySessions.length - 1] : undefined;
+ mediaKeySession.generateRequest(config.initDataType, config.initData[_mediaKeySessions.length - 1]).catch(onFailure);
+ }
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ var firstMessage = !_video.src;
+ config.messagehandler(event.messageType, event.message, {variantId: event.target.variantId}).then(function(response) {
+ return event.target.update(response);
+ }).then(function(){
+ if (firstMessage) {
+ _video.src = URL.createObjectURL(_mediaSource);
+ return _mediaSource.done;
+ } else if (event.target.keyStatuses.size > 0){
+ _waitingForKey = false;
+ return Promise.resolve();
+ }
+ }).then(function(){
+ if (firstMessage) {
+ _video.play();
+ }
+ }).catch(onFailure);
+ }
+
+ function onWaitingForKey(event) {
+ _waitingForKey = true;
+ if (config.checkReadyState) {
+ // This test does not start playing until the first license has been provided,
+ // so this event should occur when transitioning between keys.
+ // Thus, the frame at the current playback position is available and readyState
+ // should be HAVE_CURRENT_DATA.
+ assert_equals(_video.readyState, _video.HAVE_CURRENT_DATA, "Video readyState should be HAVE_CURRENT_DATA on watingforkey event");
+ }
+ startNewSession();
+ }
+
+ function onPlaying(event) {
+ _playingCount++;
+ assert_equals(_mediaKeySessions.length, _playingCount, "Should get one 'playing' event per key / session added");
+ assert_less_than_equal(_playingCount, 2, "Should not get more than two 'playing' events.");
+ }
+
+ function onCanPlay(event) {
+ _canplayCount++;
+ assert_equals(_mediaKeySessions.length, _canplayCount, "Should get one 'canplay' event per key / session added");
+ assert_less_than_equal(_canplayCount, 2, "Should not get more than two 'canplay' events.");
+ }
+
+ function onTimeupdate(event) {
+ // We should not receive 'timeupdate' events due to playing while waiting for a key, except
+ // when we first start waiting for key we should change the readyState to HAVE_CURRENT_DATA
+ // which will trigger the "If the previous ready state was HAVE_FUTURE_DATA or more, and
+ // the new ready state is HAVE_CURRENT_DATA or less" case of the readyState change
+ // algorithm which requires a "timeupdate" event be fired.
+ if (_waitingForKey) {
+ assert_equals(++_timeupdateWhileWaitingCount, 1, "Should only receive one timeupdate while waiting for key");
+ assert_equals(_video.readyState, _video.HAVE_CURRENT_DATA, "Video readyState should be HAVE_CURRENT_DATA while wating for key");
+ }
+
+ if (_video.currentTime > config.duration) {
+ assert_equals(_mediaKeySessions.length, config.initData.length, "It should require all keys to reach end of content");
+ assert_equals(_timeupdateWhileWaitingCount, 1, "Should have only received exactly one timeupdate while waiting for key");
+ _video.pause();
+ test.done();
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', test.step_func(onTimeupdate), true);
+
+ waitForEventAndRunStep('waitingforkey', _video, onWaitingForKey, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ waitForEventAndRunStep('canplay', _video, onCanPlay, test);
+
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ startNewSession();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multisession.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multisession.js
new file mode 100644
index 0000000000..d23bd1097e
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multisession.js
@@ -0,0 +1,76 @@
+function runTest(config,qualifier) {
+
+ // This test assumes one session is required for each provided initData
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback with multiple sessions, '
+ + config.testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySessions = [],
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_any(assert_equals, event.target, _mediaKeySessions);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message, {variantId: event.target._variantId}).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1)) {
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ _video.pause();
+ test.done();
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+
+ config.initData.forEach(function(initData,i) {
+ var mediaKeySession = _mediaKeys.createSession( 'temporary' );
+ mediaKeySession._variantId = config.variantIds ? config.variantIds[i] : undefined;
+ waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
+ _mediaKeySessions.push(mediaKeySession);
+ mediaKeySession.generateRequest(config.initDataType, initData).catch(onFailure);
+ } );
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration-keystatus.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration-keystatus.js
new file mode 100644
index 0000000000..e21b8f8f2a
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration-keystatus.js
@@ -0,0 +1,78 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback with limited playduration, check keystatus, ' + config.testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ // Only create the session for the first encrypted event
+ if (_mediaKeySession !== undefined) return;
+
+ var initDataType = config.initData ? config.initDataType : event.initDataType;
+ var initData = config.initData || event.initData;
+
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( initDataType, initData ).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message, {playDuration: config.playduration}).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ waitForEventAndRunStep('keystatuseschange', _mediaKeySession, onKeystatuseschange, test);
+ }
+
+ function onKeystatuseschange(event) {
+ for (var status of event.target.keyStatuses.values()) {
+ assert_equals(status, "expired", "All keys should have keyStatus expired");
+ }
+ test.done();
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration.js
new file mode 100644
index 0000000000..6ce6157529
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration.js
@@ -0,0 +1,80 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback with limited playduration, ' + config.testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ // Only create the session for the first encrypted event
+ if (_mediaKeySession !== undefined) return;
+
+ var initDataType = config.initData ? config.initDataType : event.initDataType;
+ var initData = config.initData || event.initData;
+
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( initDataType, initData ).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message, {playDuration: config.playduration}).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', test.step_func(onTimeupdate), true);
+ test.step_timeout(function(){
+ test.done();
+ },config.playduration * 2);
+ }
+
+ function onTimeupdate(event) {
+ assert_less_than(_video.currentTime * 1000, config.playduration, "Video should not play for more than playDuration from licence");
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-setMediaKeys.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-setMediaKeys.js
new file mode 100644
index 0000000000..fddcf56774
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-setMediaKeys.js
@@ -0,0 +1,105 @@
+SETMEDIAKEYS_IMMEDIATELY = 0;
+SETMEDIAKEYS_AFTER_SRC = 1;
+SETMEDIAKEYS_ONENCRYPTED = 2;
+SETMEDIAKEYS_AFTER_UPDATE = 3;
+
+function runTest(config,qualifier) {
+
+ var testcase = (config.testcase === SETMEDIAKEYS_IMMEDIATELY) ? 'setMediaKeys first'
+ : (config.testcase === SETMEDIAKEYS_AFTER_SRC) ? 'setMediaKeys after setting video.src'
+ : (config.testcase === SETMEDIAKEYS_ONENCRYPTED) ? 'setMediaKeys in encrypted event'
+ : (config.testcase === SETMEDIAKEYS_AFTER_UPDATE) ? 'setMediaKeys after updating session'
+ : 'unknown';
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, ' + testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array( event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update( response );
+ }).then(function() {
+ if (config.testcase === SETMEDIAKEYS_AFTER_UPDATE) {
+ return _video.setMediaKeys(_mediaKeys);
+ }
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ var promise = ( config.testcase === SETMEDIAKEYS_ONENCRYPTED )
+ ? _video.setMediaKeys(_mediaKeys)
+ : Promise.resolve();
+
+ promise.then( function() {
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ return _mediaKeySession.generateRequest(config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData );
+ }).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1)) {
+ _video.pause();
+ test.done();
+ }
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(test.step_func(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ if ( config.testcase === SETMEDIAKEYS_IMMEDIATELY ) {
+ return _video.setMediaKeys( _mediaKeys );
+ }
+ })).then(function(){
+ _mediaKeySession = _mediaKeys.createSession( 'temporary' );
+
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+
+ if (config.testcase === SETMEDIAKEYS_AFTER_SRC) {
+ return _video.setMediaKeys(_mediaKeys);
+ }
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-two-videos.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-two-videos.js
new file mode 100644
index 0000000000..b17168d113
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-two-videos.js
@@ -0,0 +1,83 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback two videos';
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ promise_test(function(test)
+ {
+ var promises = config.video.map(function(video) { return play_video_as_promise(test,video); });
+ return Promise.all(promises);
+
+ }, testname);
+
+ function play_video_as_promise(test, _video) {
+ var _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array( event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return _mediaKeySession.update(response);
+ }).catch(onFailure);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+
+ _mediaKeySession.generateRequest(config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData).catch(onFailure);
+ }
+
+ function wait_for_timeupdate_message(video)
+ {
+ return new Promise(function(resolve) {
+ video.addEventListener('timeupdate', function listener(event) {
+ if (event.target.currentTime > (config.duration || 1))
+ {
+ video.removeEventListener('timeupdate', listener);
+ resolve(event);
+ }
+ });
+ });
+ };
+
+ return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ return wait_for_timeupdate_message(_video);
+ }).catch(onFailure);
+ }
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-waitingforkey.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-waitingforkey.js
new file mode 100644
index 0000000000..daa9f3b169
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-waitingforkey.js
@@ -0,0 +1,71 @@
+function runTest(config,qualifier) {
+
+ // config.initData contains a list of keys. We expect those to be needed in order and get
+ // one waitingforkey event for each one.
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', successful playback, temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', waitingforkey event, '
+ + config.initData.length + ' key' + (config.initData.length > 1 ? 's' : '');
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySessions = [],
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ config.messagehandler( event.messageType, event.message ).then( function( response ) {
+ return event.target.update( response );
+ }).catch(onFailure);
+ }
+
+ function onWaitingForKey(event) {
+ // Expect one waitingforkey event for each initData we were given
+ assert_less_than(_mediaKeySessions.length, config.initData.length);
+ var mediaKeySession = _mediaKeys.createSession( 'temporary' );
+ waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
+ _mediaKeySessions.push(mediaKeySession);
+ mediaKeySession.generateRequest(config.initDataType, config.initData[_mediaKeySessions.length - 1]).catch(onFailure);
+ }
+
+ function onTimeupdate(event) {
+ if (_video.currentTime > (config.duration || 1)) {
+ assert_equals(_mediaKeySessions.length, config.initData.length);
+ _video.removeEventListener('timeupdate', onTimeupdate);
+ _video.pause();
+ test.done();
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('waitingforkey', _video, onWaitingForKey, test);
+
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary.js
new file mode 100644
index 0000000000..2f79824ec7
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary.js
@@ -0,0 +1,82 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', temporary, '
+ + /video\/([^;]*)/.exec(config.videoType)[1]
+ + ', playback, ' + config.testcase;
+
+ var configuration = { initDataTypes: [ config.initDataType ],
+ audioCapabilities: [ { contentType: config.audioType } ],
+ videoCapabilities: [ { contentType: config.videoType } ],
+ sessionTypes: [ 'temporary' ] };
+
+ async_test(function(test) {
+
+ var _video = config.video,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onEncrypted(event) {
+ assert_equals(event.target, _video);
+ assert_true(event instanceof window.MediaEncryptedEvent);
+ assert_equals(event.type, 'encrypted');
+
+ // Only create the session for the firs encrypted event
+ if (_mediaKeySession !== undefined) return;
+
+ var initDataType = config.initData ? config.initDataType : event.initDataType;
+ var initData = config.initData || event.initData;
+
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( initDataType, initData ).catch(onFailure);
+ }
+
+ function onMessage(event) {
+ assert_equals(event.target, _mediaKeySession);
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.type, 'message');
+
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ return event.target.update(response);
+ }).catch(onFailure);
+ }
+
+ function onPlaying(event) {
+ // Not using waitForEventAndRunStep() to avoid too many
+ // EVENT(onTimeUpdate) logs.
+ _video.addEventListener('timeupdate', onTimeupdate, true);
+ }
+
+ function onTimeupdate(event) {
+ if ( _video.currentTime > (config.duration || 1)) {
+ _video.pause();
+ test.done();
+ }
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ _mediaKeys = mediaKeys;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(){
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ waitForEventAndRunStep('playing', _video, onPlaying, test);
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ _video.src = URL.createObjectURL(_mediaSource);
+ return source.done;
+ }).then(function(){
+ _video.play();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/requestmediakeysystemaccess.js b/testing/web-platform/tests/encrypted-media/scripts/requestmediakeysystemaccess.js
new file mode 100644
index 0000000000..a60d4a1e76
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/requestmediakeysystemaccess.js
@@ -0,0 +1,341 @@
+function runTest(config, qualifier) {
+
+ var prefix = testnamePrefix(qualifier, config.keysystem) + ', requestMediaKeySystemAccess: ';
+
+ function expect_error(keySystem, configurations, expectedError, testname) {
+
+ var audioCapabilities = configurations.length ? configurations[0].audioCapabilities : undefined,
+ videoCapabilities = configurations.length ? configurations[0].videoCapabilities : undefined,
+ audiocontenttypes = audioCapabilities ? audioCapabilities.map( function(ac) { return "'" + ac.contentType + "'"; } ).join(',') : '',
+ videocontenttypes = videoCapabilities ? videoCapabilities.map( function(ac) { return "'" + ac.contentType + "'"; } ).join(',') : '',
+ modifiedtestname = testname.replace( '%audiocontenttype', audiocontenttypes ).replace( '%videocontenttype', videocontenttypes );
+
+ promise_test(function(test) {
+ var p = navigator.requestMediaKeySystemAccess(keySystem, configurations);
+ // expectedError is a string name for the error. We can differentiate
+ // JS Errors from DOMExceptions by checking whether
+ // window[expectedError] exists. If it does, expectedError is the name
+ // of a JS Error subclass and window[expectedError] is the constructor
+ // for that subclass. Otherwise it's a name for a DOMException.
+ if (window[expectedError]) {
+ return promise_rejects_js(test, window[expectedError], p);
+ } else {
+ return promise_rejects_dom(test, expectedError, p);
+ }
+ }, prefix + modifiedtestname + ' should result in ' + expectedError );
+ }
+
+ function assert_subset(actual, expected, path) {
+ if (typeof expected == 'string') {
+ assert_equals(actual, expected, path);
+ } else {
+ if (expected.hasOwnProperty('length')) {
+ assert_equals(actual.length, expected.length, path + '.length');
+ }
+ for (property in expected) {
+ assert_subset(actual[property], expected[property], path + '.' + property);
+ }
+ }
+ }
+
+ function expect_config(keySystem, configurations, expectedConfiguration, testname) {
+ promise_test(function(test) {
+ return navigator.requestMediaKeySystemAccess(keySystem, configurations).then(function(a) {
+ assert_subset(a.getConfiguration(), expectedConfiguration, testname + ': ');
+ });
+ }, testname);
+ }
+
+ // Tests for Key System.
+ expect_error('', [{}], 'TypeError', 'Empty Key System');
+ expect_error('com.example.unsupported', [{}], 'NotSupportedError', 'Unsupported Key System');
+ expect_error(config.keysystem + '.', [{}], 'NotSupportedError', 'Key System ending in "."');
+ expect_error(config.keysystem.toUpperCase(), [{}], 'NotSupportedError', 'Capitalized Key System');
+ expect_error(config.keysystem + '\u028F', [{}], 'NotSupportedError', 'Non-ASCII Key System');
+
+ // Parent of Clear Key not supported.
+ expect_error(config.keysystem.match(/^(.*?)\./)[1], [{}], 'NotSupportedError', 'Root domain of Key System alone');
+ expect_error(config.keysystem.match(/^(.*?)\./)[0], [{}], 'NotSupportedError', 'Root domain of Key System, with dot');
+ expect_error(config.keysystem.match(/^(.*?\..*?)\./)[1], [{}], 'NotSupportedError', 'Domain of Key System along');
+ expect_error(config.keysystem.match(/^(.*?\..*?)\./)[0], [{}], 'NotSupportedError', 'Domain of Key System, with dot');
+
+ // Child of Clear Key not supported.
+ expect_error(config.keysystem+'.foo', [{}], 'NotSupportedError', 'Child of Key System');
+
+ // Prefixed Clear Key not supported.
+ expect_error('webkit-'+config.keysystem, [{}], 'NotSupportedError', 'Prefixed Key System');
+
+ // Incomplete names.
+ expect_error(config.keysystem.substr(0,7)+config.keysystem.substr(8), [{}], 'NotSupportedError', 'Missing characters in middle of Key System name');
+ expect_error(config.keysystem.substr(0,config.keysystem.length-1), [{}], 'NotSupportedError', 'Missing characters at end of Key System name');
+
+ // Spaces in key system name not supported.
+ expect_error(' '+config.keysystem, [{}], 'NotSupportedError', 'Leading space in Key System name');
+ expect_error(config.keysystem.substr(0,6) + ' ' + config.keysystem.substr(6), [{}], 'NotSupportedError', 'Extra space in Key System name');
+ expect_error(config.keysystem + ' ', [{}], 'NotSupportedError', 'Trailing space in Key System name');
+
+ // Extra dots in key systems names not supported.
+ expect_error('.' + config.keysystem, [{}], 'NotSupportedError', 'Leading dot in Key System name');
+ expect_error(config.keysystem.substr(0,6) + '.' + config.keysystem.substr(6), [{}], 'NotSupportedError', 'Extra dot in middle of Key System name');
+ expect_error(config.keysystem + '.', [{}], 'NotSupportedError', 'Trailing dot in Key System name');
+
+ // Key system name is case sensitive.
+ if (config.keysystem !== config.keysystem.toUpperCase()) {
+ expect_error(config.keysystem.toUpperCase(), [{}], 'NotSupportedError', 'Key System name is case sensitive');
+ }
+
+ if (config.keysystem !== config.keysystem.toLowerCase()) {
+ expect_error(config.keysystem.toLowerCase(), [{}], 'NotSupportedError', 'Key System name is case sensitive');
+ }
+
+ // Tests for trivial configurations.
+ expect_error(config.keysystem, [], 'TypeError', 'Empty supportedConfigurations');
+ expect_error(config.keysystem, [{}], 'NotSupportedError', 'Empty configuration');
+
+ // Various combinations of supportedConfigurations.
+ expect_config(config.keysystem, [{
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ label: 'abcd',
+ }], {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ label: 'abcd',
+ }, 'Basic supported configuration');
+
+ expect_config(config.keysystem, [{
+ initDataTypes: ['fakeidt', config.initDataType],
+ audioCapabilities: [{contentType: 'audio/fake'}, {contentType: config.audioType}],
+ videoCapabilities: [{contentType: 'video/fake'}, {contentType: config.videoType}],
+ }], {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ }, 'Partially supported configuration');
+
+ expect_config(config.keysystem, [{
+ audioCapabilities: [{contentType: config.audioType}],
+ }], {
+ audioCapabilities: [{contentType: config.audioType}],
+ }, 'Supported audio codec');
+
+ expect_config(config.keysystem, [{
+ audioCapabilities: [{contentType: config.audioType.replace(/^(.*?);(.*)/, "$1; $2")}],
+ }], {
+ audioCapabilities: [{contentType: config.audioType.replace(/^(.*?);(.*)/, "$1; $2")}],
+ }, 'ContentType formatting must be preserved');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [{contentType: 'audio/webm; codecs=fake'}],
+ }], 'NotSupportedError', 'Unsupported audio codec (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [{contentType: 'video/webm; codecs=fake'}],
+ }], 'NotSupportedError', 'Unsupported video codec (%videocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/webm; codecs=mp4a'},
+ {contentType: 'audio/webm; codecs=mp4a.40.2'}
+ ],
+ }], 'NotSupportedError', 'Mismatched audio container/codec (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [{contentType: config.videoType}],
+ }], 'NotSupportedError', 'Video codec specified in audio field (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: config.audioType}],
+ }], 'NotSupportedError', 'Audio codec specified in video field (%videocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/webm; codecs=avc1'},
+ {contentType: 'audio/webm; codecs=avc1.42e01e'}
+ ],
+ }], 'NotSupportedError', 'Mismatched audio container/codec (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/mp4; codecs=vorbis'}
+ ],
+ }], 'NotSupportedError', 'Mismatched audio container/codec (%audiocontenttype)');
+
+ expect_config(config.keysystem, [{
+ initDataTypes: ['fakeidt'],
+ videoCapabilities: [{contentType: config.videoType}]
+ }, {
+ initDataTypes: [config.initDataType],
+ videoCapabilities: [{contentType: config.videoType}]
+ }
+ ], {
+ initDataTypes: [config.initDataType],
+ videoCapabilities: [{contentType: config.videoType}]
+ }, 'Two configurations, one supported');
+
+ expect_config(config.keysystem, [{
+ initDataTypes: [config.initDataType],
+ videoCapabilities: [{contentType: config.videoType}]
+ }, {
+ videoCapabilities: [{contentType: config.videoType}]
+ }
+ ], {
+ initDataTypes: [config.initDataType],
+ videoCapabilities: [{contentType: config.videoType}]
+ }, 'Two configurations, both supported');
+
+ // Audio MIME type does not support video codecs.
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/webm; codecs="vp8,vorbis"'},
+ {contentType: 'audio/webm; codecs="vorbis, vp8"'},
+ {contentType: 'audio/webm; codecs="vp8"'}
+ ],
+ }], 'NotSupportedError', 'Audio MIME type does not support video codecs (webm) (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/mp4; codecs="avc1"'},
+ {contentType: 'audio/mp4; codecs="avc1.4d401e"'},
+ ],
+ }], 'NotSupportedError', 'Audio MIME type does not support video codecs (mp4) (%audiocontenttype)');
+
+ // Video MIME type does not support audio codecs.
+ expect_error(config.keysystem, [{
+ videoCapabilities: [
+ {contentType: 'video/webm; codecs="vp8,vorbis"'},
+ {contentType: 'video/webm; codecs="vorbis, vp8"'},
+ {contentType: 'video/webm; codecs="vorbis"'}
+ ],
+ }], 'NotSupportedError', 'Video MIME type does not support audio codecs (webm) (%videocontenttype)');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [
+ {contentType: 'video/mp4; codecs="mp4a"'},
+ {contentType: 'video/mp4; codecs="mp4a.40.2"'}
+ ],
+ }], 'NotSupportedError', 'Video MIME type does not support audio codecs (mp4) (%videocontenttype)');
+
+ // WebM does not support AVC1/AAC.
+ expect_error(config.keysystem, [{
+ audioCapabilities: [
+ {contentType: 'audio/webm; codecs="aac"'},
+ {contentType: 'audio/webm; codecs="avc1"'},
+ {contentType: 'audio/webm; codecs="vp8,aac"'}
+ ],
+ }], 'NotSupportedError', 'WebM audio does not support AVC1/AAC (%audiocontenttype)');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [
+ {contentType: 'video/webm; codecs="aac"'},
+ {contentType: 'video/webm; codecs="avc1"'},
+ {contentType: 'video/webm; codecs="vp8,aac"'}
+ ],
+ }], 'NotSupportedError', 'WebM video does not support AVC1/AAC (%videocontenttype)');
+
+ // Extra space is allowed in contentType.
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: ' ' + config.videoType}],
+ }], {
+ videoCapabilities: [{contentType: ' ' + config.videoType}],
+ }, 'Leading space in contentType');
+
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?);(.*)/, "$1 ;$2")}],
+ }], {
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?);(.*)/, "$1 ;$2")}],
+ }, 'Space before ; in contentType');
+
+
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType + ' '}],
+ }], {
+ videoCapabilities: [{contentType: config.videoType + ' '}],
+ }, 'Trailing space in contentType');
+
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?codecs=\")(.*)/, "$1 $2")}],
+ }], {
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?codecs=\")(.*)/, "$1 $2")}],
+ }, 'Space at start of codecs parameter');
+
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?codecs=\".*)\"/, "$1 \"")}],
+ }], {
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?codecs=\".*)\"/, "$1 \"")}],
+ }, 'Space at end of codecs parameter');
+
+ // contentType is not case sensitive (except the codec names).
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: 'V' + config.videoType.substr(1)}],
+ }], {
+ videoCapabilities: [{contentType: 'V' + config.videoType.substr(1)}],
+ }, 'Video/' );
+
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?)c(odecs.*)/, "$1C$2")}],
+ }], {
+ videoCapabilities: [{contentType: config.videoType.replace( /^(.*?)c(odecs.*)/, "$1C$2")}],
+ }, 'Codecs=');
+
+ var t = config.videoType.match(/(.*?)(;.*)/);
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: t[1].toUpperCase() + t[2]}],
+ }], {
+ videoCapabilities: [{contentType: t[1].toUpperCase() + t[2]}],
+ }, 'Upper case MIME type');
+
+ t = config.videoType.match(/(.*?)codecs(.*)/);
+ expect_config(config.keysystem, [{
+ videoCapabilities: [{contentType: t[1] + 'CODECS' + t[2]}],
+ }], {
+ videoCapabilities: [{contentType: t[1] + 'CODECS' + t[2]}],
+ }, 'CODECS=');
+
+ // Unrecognized attributes are not allowed.
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: 'video/webm; foo="bar"'}],
+ }], 'NotSupportedError', 'Unrecognized foo with webm (%videocontenttype)');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: 'video/mp4; foo="bar"'}],
+ }], 'NotSupportedError', 'Unrecognized foo with mp4 (%videocontenttype)');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: config.videoType + '; foo="bar"'}],
+ }], 'NotSupportedError', 'Unrecognized foo with codecs (%videocontenttype)');
+
+ // Invalid contentTypes.
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: 'fake'}],
+ }], 'NotSupportedError', 'contentType: %videocontenttype');
+
+ expect_error(config.keysystem, [{
+ audioCapabilities: [{contentType: 'audio/fake'}],
+ }], 'NotSupportedError', 'contentType: %audiocontenttype');
+
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: 'video/fake'}],
+ }], 'NotSupportedError', 'contentType: %videocontenttype');
+
+ // The actual codec names are case sensitive.
+ t = config.videoType.match( /(.*?codecs=\")(.*?\")(.*)/ );
+ if (t[2] !== t[2].toUpperCase()) {
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: t[1] + t[2].toUpperCase() + t[3] }],
+ }], 'NotSupportedError', 'contentType: %videocontenttype');
+ }
+
+ if (t[2] !== t[2].toLowerCase()) {
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: t[1] + t[2].toLowerCase() + t[3] }],
+ }], 'NotSupportedError', 'contentType: %videocontenttype');
+ }
+
+ // Extra comma is not allowed in codecs.
+ expect_error(config.keysystem, [{
+ videoCapabilities: [{contentType: t[1] + ',' + t[2] + t[3] }],
+ }], 'NotSupportedError', 'contentType: %videocontenttype');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/reset-src-after-setmediakeys.js b/testing/web-platform/tests/encrypted-media/scripts/reset-src-after-setmediakeys.js
new file mode 100644
index 0000000000..0ccce3275e
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/reset-src-after-setmediakeys.js
@@ -0,0 +1,61 @@
+function runTest(config)
+{
+ async_test(function(test) {
+ var mediaKeys;
+ var mediaSource;
+ var encryptedEventIndex = 0;
+ var video = config.video;
+ var keysystem = config.keysystem;
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{
+ contentType: config.audioType
+ }],
+ videoCapabilities: [{
+ contentType: config.videoType
+ }],
+ sessionTypes: ['temporary']
+ };
+
+ assert_not_equals(video, null);
+
+ var onEncrypted = function(event) {
+ ++encryptedEventIndex;
+ assert_equals(video.mediaKeys, mediaKeys);
+
+ // This event is fired once for the audio stream and once
+ // for the video stream each time .src is set.
+ if (encryptedEventIndex === 2) {
+ // Finished first video; Create new media source and wait for two more encrypted events
+ return testmediasource(config).then(function (source) {
+ video.src = URL.createObjectURL(source);
+ }).catch(function (error) {
+ forceTestFailureFromPromise(test, error)
+ });
+ } else if (encryptedEventIndex === 4) {
+ // Finished second video.
+ test.done();
+ }
+ };
+
+ // Create a MediaKeys object and assign it to video.
+ navigator.requestMediaKeySystemAccess(keysystem, [configuration]).then(test.step_func(function (access) {
+ assert_equals(access.keySystem, keysystem);
+ return access.createMediaKeys();
+ })).then(test.step_func(function (result) {
+ mediaKeys = result;
+ assert_not_equals(mediaKeys, null);
+ return video.setMediaKeys(mediaKeys);
+ })).then(test.step_func(function () {
+ assert_equals(video.mediaKeys, mediaKeys);
+ return testmediasource(config);
+ })).then(function (source) {
+ waitForEventAndRunStep('encrypted', video, onEncrypted, test);
+ mediaSource = source;
+ video.src = URL.createObjectURL(mediaSource);
+ }).catch(function (error) {
+ forceTestFailureFromPromise(test, error);
+ });
+
+ }, 'Reset src after setMediaKeys().');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-playback.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-playback.js
new file mode 100644
index 0000000000..772bfcaa87
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-playback.js
@@ -0,0 +1,79 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', setmediakeys again after playback';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test) {
+ var _video = config.video,
+ _access,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ config.messagehandler(event.messageType, event.message).then( function(response) {
+ _mediaKeySession.update(response).catch(onFailure).then(function() {
+ _video.play();
+ });
+ });
+ }
+
+ function onEncrypted(event) {
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData )
+ .catch(onFailure);
+ }
+
+ function playVideo()
+ {
+ return new Promise(function(resolve) {
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ _video.src = URL.createObjectURL(_mediaSource);
+ resolve('success');
+ });
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ _access = access;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ return config.servercertificate ? _mediaKeys.setServerCertificate( config.servercertificate ) : true;
+ }).then(function( success ) {
+ return testmediasource(config);
+ }).then(function(source) {
+ _mediaSource = source;
+ return playVideo();
+ }).then(function(results) {
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ return waitForEvent('playing', _video);
+ }).then(test.step_func(function(result) {
+ assert_false(_video.ended);
+ return _video.setMediaKeys(_mediaKeys);
+ })).then(function() {
+ // Able to change MediaKeys while playing.
+ // This is not required to fail.
+ _video.src='';
+ test.done();
+ }, test.step_func(function(error) {
+ assert_in_array(error.name, ['InvalidStateError','NotSupportedError']);
+ _video.src='';
+ test.done();
+ })).catch(onFailure);
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-resetting-src.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-resetting-src.js
new file mode 100644
index 0000000000..a870600982
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-resetting-src.js
@@ -0,0 +1,79 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', setmediakeys again after resetting src';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test) {
+ var _video = config.video,
+ _access,
+ _mediaKeys,
+ _mediaKeySession,
+ _mediaSource;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function onMessage(event) {
+ config.messagehandler(event.messageType, event.message).then(function(response) {
+ _mediaKeySession.update(response).catch(onFailure).then(function() {
+ _video.play();
+ });
+ });
+ }
+
+ function onEncrypted(event) {
+ waitForEventAndRunStep('message', _mediaKeySession, onMessage, test);
+ _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType,
+ config.initData || event.initData )
+ .catch(onFailure);
+ }
+
+ function playVideoAndWaitForTimeupdate()
+ {
+ return new Promise(function(resolve) {
+ testmediasource(config).then(function(source) {
+ _mediaKeySession = _mediaKeys.createSession('temporary');
+ _video.src = URL.createObjectURL(source);
+ });
+ _video.addEventListener('timeupdate', function listener(event) {
+ if (event.target.currentTime < (config.duration || 1))
+ return;
+ _video.removeEventListener('timeupdate', listener);
+ resolve('success');
+ });
+ });
+ }
+
+ waitForEventAndRunStep('encrypted', _video, onEncrypted, test);
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ _access = access;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ return config.servercertificate ? _mediaKeys.setServerCertificate( config.servercertificate ) : true;
+ }).then(function( success ) {
+ return playVideoAndWaitForTimeupdate();
+ }).then(function(results) {
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ _video.src = '';
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ return config.servercertificate ? _mediaKeys.setServerCertificate( config.servercertificate ) : true;
+ }).then(function( success ) {
+ return playVideoAndWaitForTimeupdate();
+ }).then(function() {
+ _video.src = '';
+ test.done();
+ }).catch(onFailure);
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-at-same-time.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-at-same-time.js
new file mode 100644
index 0000000000..6d67d95b1f
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-at-same-time.js
@@ -0,0 +1,59 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', setmediakeys at same time';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ async_test(function(test) {
+ var _video = config.video,
+ _access,
+ _mediaKeys1,
+ _mediaKeys2,
+ _mediaKeys3,
+ _mediaKeys4,
+ _mediaKeys5;
+
+ // Test MediaKeys assignment.
+ assert_equals(_video.mediaKeys, null);
+ assert_equals(typeof _video.setMediaKeys, 'function');
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function setMediaKeys(mediaKeys) {
+ return _video.setMediaKeys(mediaKeys)
+ .then(function() {return 1}, function() {return 0})
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ _access = access;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys1 = result;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys2 = result;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys3 = result;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys4 = result;
+ return _access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys5 = result;
+ return Promise.all([
+ setMediaKeys(_mediaKeys1),
+ setMediaKeys(_mediaKeys2),
+ setMediaKeys(_mediaKeys3),
+ setMediaKeys(_mediaKeys4),
+ setMediaKeys(_mediaKeys5)
+ ]);
+ }).then(function(results) {
+ var sum = results.reduce((a, b) => a + b, 0);
+ assert_in_array(sum,[1,5]);
+ test.done();
+ }).catch(onFailure);
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-different-mediakeys.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-different-mediakeys.js
new file mode 100644
index 0000000000..ef44477b16
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-different-mediakeys.js
@@ -0,0 +1,98 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix( qualifier, config.keysystem )
+ + ', setmediakeys multiple times with different mediakeys';
+
+ var configuration = getSimpleConfigurationForContent( config.content );
+
+ async_test (function (test) {
+ var _video = config.video,
+ _access,
+ _mediaKeys1,
+ _mediaKeys2,
+ _usingMediaKeys2 = false;;
+
+ // Test MediaKeys assignment.
+ assert_equals(_video.mediaKeys, null);
+ assert_equals(typeof _video.setMediaKeys, 'function');
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ _access = access;
+ return _access.createMediaKeys();
+ }).then(test.step_func(function(result) {
+ _mediaKeys1 = result;
+ assert_not_equals(_mediaKeys1, null);
+ // Create a second mediaKeys.
+ return _access.createMediaKeys();
+ })).then(test.step_func(function(result) {
+ _mediaKeys2 = result;
+ assert_not_equals(_mediaKeys2, null);
+ // Set _mediaKeys1 on video.
+ return _video.setMediaKeys(_mediaKeys1);
+ })).then(test.step_func(function() {
+ assert_equals(_video.mediaKeys, _mediaKeys1);
+ // Set _mediaKeys2 on video (switching MediaKeys).
+ return _video.setMediaKeys(_mediaKeys2);
+ })).then(test.step_func(function() {
+ assert_equals(_video.mediaKeys, _mediaKeys2);
+ // Clear mediaKeys from video.
+ return _video.setMediaKeys(null);
+ })).then(test.step_func(function() {
+ assert_equals(_video.mediaKeys, null);
+ // Set _mediaKeys1 on video again.
+ return _video.setMediaKeys(_mediaKeys1);
+ })).then(test.step_func(function() {
+ assert_equals(_video.mediaKeys, _mediaKeys1);
+ return testmediasource(config);
+ })).then(function(source) {
+ // Set src attribute on Video Element
+ _video.src = URL.createObjectURL(source);
+ // According to the specification, support for changing the Media Keys object after
+ // the src attribute on the video element has been set is optional. The following operation
+ // may therefore either succeed or fail. We handle both cases.
+ return _video.setMediaKeys(_mediaKeys2);
+ }).then(test.step_func(function() {
+ // Changing the Media Keys object succeeded
+ _usingMediaKeys2 = true;
+ assert_equals(_video.mediaKeys, _mediaKeys2);
+ // Return something so the promise resolves properly.
+ return Promise.resolve();
+ }), test.step_func(function(error) {
+ // Changing the Media Keys object failed
+ _usingMediaKeys2 = false;
+ assert_equals(_video.mediaKeys, _mediaKeys1);
+ // The specification allows either NotSupportedError or InvalidStateError depending on
+ // whether the failure was because changing Media Keys object is not supported
+ // or just not allowed at this time, respectively.
+ assert_in_array(error.name, ['InvalidStateError','NotSupportedError']);
+ assert_not_equals(error.message, '');
+ // Return something so the promise resolves properly.
+ return Promise.resolve();
+ })).then(function() {
+ // According to the specification, support for clearing the Media Keys object associated
+ // with the video element is optional. The following operation
+ // may therefore either succeed or fail. We handle both cases.
+ return _video.setMediaKeys(null);
+ }).then(test.step_func(function() {
+ // Clearing the media keys succeeded
+ assert_equals(_video.mediaKeys, null);
+ test.done();
+ }), test.step_func(function(error) {
+ // Clearing the media keys failed
+ if(!_usingMediaKeys2) {
+ assert_equals(_video.mediaKeys, _mediaKeys1);
+ } else {
+ assert_equals(_video.mediaKeys, _mediaKeys2);
+ }
+ // The specification allows either NotSupportedError or InvalidStateError depending on
+ // whether the failure was because changing Media Keys object is not supported
+ // or just not allowed at this time, respectively.
+ assert_in_array(error.name, ['InvalidStateError','NotSupportedError']);
+ assert_not_equals(error.message, '');
+ test.done();
+ })).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-the-same-mediakeys.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-the-same-mediakeys.js
new file mode 100644
index 0000000000..f6af8267f2
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-the-same-mediakeys.js
@@ -0,0 +1,46 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix( qualifier, config.keysystem )
+ + ', setmediakeys multiple times with the same mediakeys';
+
+ var configuration = getSimpleConfigurationForContent( config.content );
+
+ if ( config.initDataType && config.initData ) {
+ configuration.initDataTypes = [ config.initDataType ];
+ }
+
+ async_test (function (test) {
+ var _video = config.video,
+ _mediaKeys;
+
+ // Test MediaKeys assignment.
+ assert_equals(_video.mediaKeys, null);
+ assert_equals(typeof _video.setMediaKeys, 'function');
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ return access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ // Set mediaKeys for first time on video should work.
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(result) {
+ assert_equals(_video.mediaKeys, _mediaKeys);
+ // Set mediaKeys on video again should return a resolved promise.
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function (result) {
+ assert_equals(_video.mediaKeys, _mediaKeys);
+ return testmediasource(config);
+ }).then(function(source) {
+ // Set src attribute on Video Element
+ _video.src = URL.createObjectURL(source);
+ // Set mediaKeys again on video should still return a resolved promise.
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function() {
+ assert_equals(_video.mediaKeys, _mediaKeys);
+ test.done();
+ }).catch(onFailure);
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js
new file mode 100644
index 0000000000..4c7faef69d
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js
@@ -0,0 +1,54 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix(qualifier, config.keysystem)
+ + ', setMediaKeys to multiple video elements';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if ( config.initDataType && config.initData ) {
+ configuration.initDataTypes = [ config.initDataType ];
+ }
+
+ async_test (function (test) {
+ var _video1 = config.video1,
+ _video2 = config.video2,
+ _mediaKeys;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ assert_equals(access.keySystem, config.keysystem)
+ return access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ assert_not_equals(_mediaKeys, null);
+ assert_equals(typeof _mediaKeys.createSession, 'function');
+ return _video1.setMediaKeys(_mediaKeys);
+ }).then(function(result) {
+ assert_not_equals(_video1.mediaKeys, null);
+ assert_equals(_video1.mediaKeys, _mediaKeys);
+ // The specification allows this to fail, but it is not required to fail.
+ return _video2.setMediaKeys(_mediaKeys);
+ }).then(function(result) {
+ // Second setMediaKeys is not required to fail.
+ assert_equals(_video2.mediaKeys, _mediaKeys);
+ return Promise.resolve();
+ }, function(error) {
+ assert_equals(error.name, 'QuotaExceededError');
+ assert_not_equals(error.message, '');
+ // Return something so the promise resolves properly.
+ return Promise.resolve();
+ }).then(function() {
+ // Now clear it from video1.
+ return _video1.setMediaKeys(null);
+ }).then(function() {
+ // Should be assignable to video2.
+ return _video2.setMediaKeys(_mediaKeys);
+ }).then(function(result) {
+ assert_not_equals(_video2.mediaKeys, null);
+ assert_equals(_video2.mediaKeys, _mediaKeys);
+ test.done();
+ }).catch(onFailure);
+ }, testname);
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/encrypted-media/scripts/setmediakeys.js b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys.js
new file mode 100644
index 0000000000..a85adeaeaf
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/setmediakeys.js
@@ -0,0 +1,50 @@
+function runTest(config, qualifier) {
+ var testname = testnamePrefix( qualifier, config.keysystem )
+ + ', setMediaKeys';
+
+ var configuration = getSimpleConfigurationForContent( config.content );
+
+ if ( config.initDataType && config.initData ) {
+ configuration.initDataTypes = [ config.initDataType ];
+ }
+
+ async_test (function (test) {
+ var _video = config.video,
+ _mediaKeys;
+
+ // Test MediaKeys assignment.
+ assert_equals(_video.mediaKeys, null);
+ assert_equals(typeof _video.setMediaKeys, 'function');
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ // Try setting mediaKeys to null.
+ _video.setMediaKeys(null).then(function(result) {
+ assert_equals(_video.mediaKeys, null);
+
+ // setMediaKeys should fail when setting to the wrong type of object - Date.
+ return _video.setMediaKeys(new Date());
+ }).then(function (result) {
+ assert_unreached('setMediaKeys should fail when setting to wrong kind of object (Date)');
+ }, function(error) {
+ // The error should be TypeError.
+ assert_throws_js(TypeError, () => { throw error; },
+ 'setMediaKeys should return a TypeError when setting to wrong kind of object (Date)');
+ return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]);
+ }).then(function(access) {
+ assert_equals(access.keySystem, config.keysystem)
+ return access.createMediaKeys();
+ }).then(function(result) {
+ _mediaKeys = result;
+ assert_not_equals(_mediaKeys, null);
+ assert_equals(typeof _mediaKeys.createSession, 'function');
+ return _video.setMediaKeys(_mediaKeys);
+ }).then(function(result) {
+ assert_not_equals(_video.mediaKeys, null);
+ assert_equals(_video.mediaKeys, _mediaKeys);
+ test.done();
+ }).catch(onFailure);
+ }, testname);
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeys.js b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeys.js
new file mode 100644
index 0000000000..4ec6551e8f
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeys.js
@@ -0,0 +1,184 @@
+function runTest(config) {
+ var keysystem = config.keysystem;
+ var testname = testnamePrefix(null, config.keysystem);
+ var initDataType = config.initDataType;
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['temporary']
+ };
+
+ function createMediaKeysAttributeTest() {
+ return new Promise(function (resolve, reject) {
+ var access;
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
+ assert_true(isTypeSupported, "initDataType should be supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (result) {
+ access = result;
+ assert_equals(access.keySystem, keysystem);
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ assert_not_equals(mediaKeys, null);
+ assert_equals(typeof mediaKeys, 'object');
+ assert_equals(typeof mediaKeys.createSession, 'function');
+ assert_equals(typeof mediaKeys.setServerCertificate, 'function');
+
+ // Test creation of a second MediaKeys.
+ // The extra parameter is ignored.
+ return access.createMediaKeys('extra');
+ }).then(function (mediaKeys) {
+ assert_not_equals(mediaKeys, null);
+ assert_equals(typeof mediaKeys, 'object');
+ assert_equals(typeof mediaKeys.createSession, 'function');
+ assert_equals(typeof mediaKeys.setServerCertificate, 'function');
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+
+ promise_test(function() {
+ return createMediaKeysAttributeTest();
+ }, testname + ' test MediaKeys attribute syntax');
+
+ var kSetServerCertificateExceptionsTestCases = [
+ // Too few parameters.
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate();
+ }
+ },
+ // Invalid parameters.
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate('');
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate(null);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate(undefined);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate(1);
+ }
+ },
+ // Empty array.
+ {
+ exception: 'TypeError',
+ func: function (mk) {
+ return mk.setServerCertificate(new Uint8Array(0));
+ }
+ }
+ ];
+
+
+ function setServerCertificateTestExceptions() {
+ return new Promise(function(resolve, reject) {
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var promises = kSetServerCertificateExceptionsTestCases.map(function (testCase) {
+ return test_exception(testCase, mediaKeys);
+ });
+ assert_not_equals(promises.length, 0);
+ return Promise.all(promises);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return setServerCertificateTestExceptions();
+ }, testname + ' test MediaKeys setServerCertificate() exceptions.');
+
+ // All calls to |func| in this group resolve. setServerCertificate with these cert may either resolve with true
+ // for clearkey or throw a DOMException.
+ var kSetServerCertificateTestCases = [
+ {
+ // Pass in ArrayBufferView
+ func: function (mk) {
+ var cert = new Uint8Array(200);
+ assert_true(ArrayBuffer.isView(cert));
+
+ return new Promise(function (resolve, reject) {
+ mk.setServerCertificate(cert).then(function (value) {
+ resolve(value);
+ }).catch(function (error) {
+ if (Object.prototype.toString.call(error) === "[object DOMException]") {
+ resolve(false);
+ }
+ });
+ })
+ },
+ expected: false
+ },
+ {
+ // Pass in ArrayBuffer.
+ func: function (mk) {
+ var cert = new ArrayBuffer(200);
+ assert_false(ArrayBuffer.isView(cert));
+ return new Promise(function (resolve) {
+ mk.setServerCertificate(cert).then(function (resolveValue) {
+ resolve(resolveValue);
+ }).catch(function (error) {
+ if (Object.prototype.toString.call(error) === "[object DOMException]") {
+ resolve(false);
+ }
+ });
+ })
+ },
+ expected: false
+ }
+ ];
+ function setServerCertificateTest(){
+ return new Promise(function(resolve, reject){
+ var expected_result;
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var promises = kSetServerCertificateTestCases.map(function (testCase) {
+ return testCase.func.call(null, mediaKeys);
+ });
+ expected_result = kSetServerCertificateTestCases.map(function (testCase) {
+ return testCase.expected;
+ });
+ assert_not_equals(promises.length, 0);
+ return Promise.all(promises);
+ }).then(function (result) {
+ assert_array_equals(result, expected_result);
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return setServerCertificateTest();
+ }, testname + ' test MediaKeys setServerCertificate() syntax with non-empty certificate.');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysession.js b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysession.js
new file mode 100644
index 0000000000..fac31cbb3e
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysession.js
@@ -0,0 +1,452 @@
+function runTest(config) {
+ var keysystem = config.keysystem;
+ var testname = testnamePrefix(null, config.keysystem);
+ var initDataType = config.initDataType;
+ var initData = config.initData;
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['temporary']
+ };
+
+ var kTypeSpecificGenerateRequestExceptionsTestCases = [
+ // Tests in this set use a shortened parameter name due to
+ // format_value() only returning the first 60 characters as the
+ // result. With a longer name the first 60 characters is not
+ // enough to determine which test failed. Even with the
+ // shortened name, the error message for the last couple of
+ // tests is the same.
+
+ // Too few parameters.
+ {
+ exception: 'TypeError',
+ func: function (mk1, type) {
+ return mk1.createSession().generateRequest(type);
+ }
+ },
+ // Invalid parameters.
+ {
+ exception: 'TypeError',
+ func: function (mk2, type) {
+ return mk2.createSession().generateRequest(type, '');
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk3, type) {
+ return mk3.createSession().generateRequest(type, null);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk4, type) {
+ return mk4.createSession().generateRequest(type, undefined);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk5, type) {
+ return mk5.createSession().generateRequest(type, 1);
+ }
+ },
+ // (new Uint8Array(0)) returns empty array. So 'TypeError' should
+ // be returned.
+ {
+ exception: 'TypeError',
+ func: function (mk6, type) {
+ return mk6.createSession().generateRequest(type, new Uint8Array(0));
+ }
+ },
+ // Using an empty type should return a 'TypeError'.
+ {
+ exception: 'TypeError',
+ func: function (mk7, type) {
+ return mk7.createSession().generateRequest('', initData);
+ }
+ },
+ ];
+ function generateRequestTestExceptions(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var mp4SessionPromises = kTypeSpecificGenerateRequestExceptionsTestCases.map(function (testCase) {
+ return test_exception(testCase, mediaKeys, initDataType, initData);
+ });
+ assert_not_equals(mp4SessionPromises.length, 0);
+ return Promise.all(mp4SessionPromises);
+ }).then(function (result) {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return generateRequestTestExceptions();
+ }, testname + ' test MediaKeySession generateRequest() exceptions.');
+
+ var kLoadExceptionsTestCases = [
+ // Too few parameters.
+ {
+ exception: 'TypeError',
+ func: function (mk1) {
+ return mk1.createSession('temporary').load();
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk3) {
+ return mk3.createSession('temporary').load('');
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk4) {
+ return mk4.createSession('temporary').load(1);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk5) {
+ return mk5.createSession('temporary').load('!@#$%^&*()');
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (mk6) {
+ return mk6.createSession('temporary').load('1234');
+ }
+ }
+ ];
+ function loadTestExceptions(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var sessionPromises = kLoadExceptionsTestCases.map(function (testCase) {
+ return test_exception(testCase, mediaKeys);
+ });
+ assert_not_equals(sessionPromises.length, 0);
+ return Promise.all(sessionPromises);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return loadTestExceptions();
+ }, testname + ' test MediaKeySession load() exceptions.');
+
+ // All calls to |func| in this group are supposed to succeed.
+ // However, the spec notes that some things are optional for
+ // Clear Key. In particular, support for persistent sessions
+ // is optional. Since some implementations won't support some
+ // features, a NotSupportedError is treated as a success
+ // if |isNotSupportedAllowed| is true.
+ var kCreateSessionTestCases = [
+ // Use the default sessionType.
+ {
+ func: function(mk) { return mk.createSession(); },
+ isNotSupportedAllowed: false
+ },
+ // Try variations of sessionType.
+ {
+ func: function(mk) { return mk.createSession('temporary'); },
+ isNotSupportedAllowed: false
+ },
+ {
+ func: function(mk) { return mk.createSession(undefined); },
+ isNotSupportedAllowed: false
+ },
+ {
+ // Since this is optional, some Clear Key implementations
+ // will succeed, others will return a "NotSupportedError".
+ // Both are allowed results.
+ func: function(mk) { return mk.createSession('persistent-license'); },
+ isNotSupportedAllowed: true
+ },
+ // Try additional parameter, which should be ignored.
+ {
+ func: function(mk) { return mk.createSession('temporary', 'extra'); },
+ isNotSupportedAllowed: false
+ }
+ ];
+ // This function checks that calling generateRequest() works for
+ // various sessions. |testCase.func| creates a MediaKeySession
+ // object, and then generateRequest() is called on that object. It
+ // allows for an NotSupportedError to be generated and treated as a
+ // success, if allowed. See comment above kCreateSessionTestCases.
+ function test_generateRequest(testCase, mediaKeys, type, initData) {
+ var mediaKeySession;
+ try {
+ mediaKeySession = testCase.func.call(null, mediaKeys);
+ } catch (e) {
+ assert_true(testCase.isNotSupportedAllowed);
+ assert_equals(e.name, 'NotSupportedError');
+ return Promise.resolve('not supported');
+ }
+ return mediaKeySession.generateRequest(type, initData);
+ }
+ function generateRequestForVariousSessions(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType should be supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var mp4SessionPromises = kCreateSessionTestCases.map(function (testCase) {
+ return test_generateRequest(testCase, mediaKeys, initDataType, initData);
+ });
+ assert_not_equals(mp4SessionPromises.length, 0);
+ return Promise.all(mp4SessionPromises);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return generateRequestForVariousSessions();
+ }, testname + ' test if MediaKeySession generateRequest() resolves for various sessions');
+
+ var kUpdateSessionExceptionsTestCases = [
+ // Tests in this set use a shortened parameter name due to
+ // format_value() only returning the first 60 characters as the
+ // result. With a longer name (mediaKeySession) the first 60
+ // characters is not enough to determine which test failed.
+
+ // Too few parameters.
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update();
+ }
+ },
+ // Invalid parameters.
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update('');
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update(null);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update(undefined);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update(1);
+ }
+ },
+ // (new Uint8Array(0)) returns empty array. So 'TypeError' should
+ // be returned.
+ {
+ exception: 'TypeError',
+ func: function (s) {
+ return s.update(new Uint8Array(0));
+ }
+ }
+ ];
+
+ function updateTestExceptions(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ var mp4SessionPromises = kUpdateSessionExceptionsTestCases.map(function (testCase) {
+ var mediaKeySession = mediaKeys.createSession();
+ return mediaKeySession.generateRequest(initDataType, initData).then(function (result) {
+ return test_exception(testCase, mediaKeySession);
+ });
+ });
+ assert_not_equals(mp4SessionPromises.length, 0);
+ return Promise.all(mp4SessionPromises);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return updateTestExceptions();
+ }, testname + ' test MediaKeySession update() exceptions.');
+
+ function create_close_exception_test(mediaKeys) {
+ var mediaKeySession = mediaKeys.createSession();
+ return mediaKeySession.close().then(function (result) {
+ assert_unreached('close() should not succeed if session uninitialized');
+ }).catch(function (error) {
+ assert_equals(error.name, 'InvalidStateError');
+ // Return something so the promise resolves.
+ return Promise.resolve();
+ });
+ }
+ function closeTestExceptions(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ return create_close_exception_test(mediaKeys);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ });
+ }
+ promise_test(function() {
+ return closeTestExceptions();
+ }, testname + ' test MediaKeySession close() exceptions.');
+
+ function create_remove_exception_test(mediaKeys, type, initData) {
+ // remove() on an uninitialized session should fail.
+ var mediaKeySession = mediaKeys.createSession('temporary');
+ return mediaKeySession.remove().then(function (result) {
+ assert_unreached('remove() should not succeed if session uninitialized');
+ }, function (error) {
+ assert_equals(error.name, 'InvalidStateError');
+ });
+ }
+ function removeTestException(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ return create_remove_exception_test(mediaKeys, initDataType, initData);
+ }).then(function () {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ });
+ }
+ promise_test(function() {
+ return removeTestException();
+ }, testname + ' test MediaKeySession remove() exceptions.');
+
+ // All calls to |func| in this group are supposed to succeed.
+ // However, the spec notes that some things are optional for
+ // Clear Key. In particular, support for persistent sessions
+ // is optional. Since some implementations won't support some
+ // features, a NotSupportedError is treated as a success
+ // if |isNotSupportedAllowed| is true.
+ var kCreateSessionTestCases = [
+ // Use the default sessionType.
+ {
+ func: function (mk) {
+ return mk.createSession();
+ },
+ isNotSupportedAllowed: false
+ },
+ // Try variations of sessionType.
+ {
+ func: function (mk) {
+ return mk.createSession('temporary');
+ },
+ isNotSupportedAllowed: false
+ },
+ {
+ func: function (mk) {
+ return mk.createSession(undefined);
+ },
+ isNotSupportedAllowed: false
+ },
+ {
+ // Since this is optional, some Clear Key implementations
+ // will succeed, others will return a "NotSupportedError".
+ // Both are allowed results.
+ func: function (mk) {
+ return mk.createSession('persistent-license');
+ },
+ isNotSupportedAllowed: true
+ },
+ // Try additional parameter, which should be ignored.
+ {
+ func: function (mk) {
+ return mk.createSession('temporary', 'extra');
+ },
+ isNotSupportedAllowed: false
+ }
+ ];
+
+ // This function checks that calling |testCase.func| creates a
+ // MediaKeySession object with some default values. It also
+ // allows for an NotSupportedError to be generated and treated as a
+ // success, if allowed. See comment above kCreateSessionTestCases.
+ function test_createSession(testCase, mediaKeys) {
+ var mediaKeySession;
+ try {
+ mediaKeySession = testCase.func.call(null, mediaKeys);
+ } catch (e) {
+ assert_true(testCase.isNotSupportedAllowed);
+ return;
+ }
+ assert_equals(typeof mediaKeySession, 'object');
+ assert_equals(typeof mediaKeySession.addEventListener, 'function');
+ assert_equals(typeof mediaKeySession.sessionId, 'string');
+ assert_equals(typeof mediaKeySession.expiration, 'number');
+ assert_equals(typeof mediaKeySession.closed, 'object');
+ assert_equals(typeof mediaKeySession.keyStatuses, 'object');
+ assert_equals(typeof mediaKeySession.onkeystatuseschange, 'object');
+ assert_equals(typeof mediaKeySession.onmessage, 'object');
+ assert_equals(typeof mediaKeySession.generateRequest, 'function');
+ assert_equals(typeof mediaKeySession.load, 'function');
+ assert_equals(typeof mediaKeySession.update, 'function');
+ assert_equals(typeof mediaKeySession.close, 'function');
+ assert_equals(typeof mediaKeySession.remove, 'function');
+ assert_equals(mediaKeySession.sessionId, '');
+ }
+ function createSessionTest(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ kCreateSessionTestCases.map(function (testCase) {
+ test_createSession(testCase, mediaKeys);
+ });
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return createSessionTest();
+ }, testname + ' test MediaKeySession attribute syntax.');
+
+
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysystemaccess.js b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysystemaccess.js
new file mode 100644
index 0000000000..bbc7b6700b
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysystemaccess.js
@@ -0,0 +1,147 @@
+function runTest(config) {
+ var keysystem = config.keysystem;
+ var testname = testnamePrefix(null, config.keysystem);
+ var initDataType = config.initDataType;
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{contentType: config.audioType}],
+ videoCapabilities: [{contentType: config.videoType}],
+ sessionTypes: ['temporary']
+ };
+
+ var kRequestMediaKeySystemAccessExceptionsTestCases = [
+ // Too few parameters.
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess();
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem);
+ }
+ },
+ // Invalid key systems. Note that JavaScript converts all these
+ // values into strings by calling toString(), so they fail due
+ // to the key system not being supported, not due to the type.
+ {
+ exception: 'NotSupportedError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(null, [{}]);
+ }
+ },
+ {
+ exception: 'NotSupportedError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(undefined, [{}]);
+ }
+ },
+ {
+ exception: 'NotSupportedError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(1, [{}]);
+ }
+ },
+ {
+ exception: 'NotSupportedError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess('unsupported', [{}]);
+ }
+ },
+ // Empty keysystem string should be rejected with TypeError.
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess('', [{}]);
+ }
+ },
+ // (new Uint8Array(0)).toString() should return ''. So this case should be the same
+ // as the above.
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(new Uint8Array(0), [{}]);
+ }
+ },
+ // Non-ASCII names.
+ {
+ exception: 'NotSupportedError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem + '\u263A', [{}]);
+ }
+ },
+ // Empty sequence of MediaKeySystemConfiguration.
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem, []);
+ }
+ },
+ // Things that don't convert to valid sequences of MediaKeySystemConfigurations.
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem, {});
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem, "invalid");
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem, [{}, 6]);
+ }
+ },
+ {
+ exception: 'TypeError',
+ func: function () {
+ return navigator.requestMediaKeySystemAccess(keysystem, ["invalid", "upsupported"]);
+ }
+ }
+ ];
+
+ function requestMediaKeySystemAccessTestExceptions(){
+ return new Promise(function(resolve, reject){
+ var createPromises = kRequestMediaKeySystemAccessExceptionsTestCases.map(function (testCase) {
+ return test_exception(testCase);
+ });
+ Promise.all(createPromises).then(function (result) {
+ resolve();
+ }).catch(function (error) {
+ reject(error);
+ });
+ })
+ }
+ promise_test(function() {
+ return requestMediaKeySystemAccessTestExceptions();
+ }, testname + ' test requestMediaKeySystemAccess() exceptions.');
+
+ function requestMediaKeySystemAccessTestAttributes(){
+ return new Promise(function(resolve, reject){
+ isInitDataTypeSupported(keysystem, initDataType).then(function (isTypeSupported) {
+ assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
+ assert_true(isTypeSupported, "initDataType not supported");
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]);
+ }).then(function (access) {
+ assert_not_equals(access, null);
+ assert_equals(typeof access, 'object');
+ assert_equals(access.keySystem, keysystem);
+ assert_equals(typeof access.getConfiguration, 'function');
+ assert_equals(typeof access.createMediaKeys, 'function');
+ resolve();
+ }).catch(function(error){
+ reject(error);
+ })
+ })
+ }
+ promise_test(function() {
+ return requestMediaKeySystemAccessTestAttributes();
+ }, testname + ' test MediaKeySystemAccess attribute syntax.');
+
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/temporary-license-type.js b/testing/web-platform/tests/encrypted-media/scripts/temporary-license-type.js
new file mode 100644
index 0000000000..44c9f15808
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/temporary-license-type.js
@@ -0,0 +1,61 @@
+function runTest(config,qualifier) {
+
+ var testname = testnamePrefix(qualifier, config.keysystem) + ', cannot load persistent license into temporary session';
+
+ var configuration = getSimpleConfigurationForContent(config.content);
+
+ if (config.initDataType && config.initData) {
+ configuration.initDataTypes = [config.initDataType];
+ }
+
+ async_test(function(test)
+ {
+ var initDataType;
+ var initData;
+ var mediaKeySession;
+
+ function onFailure(error) {
+ forceTestFailureFromPromise(test, error);
+ }
+
+ function processMessage(event)
+ {
+ assert_true(event instanceof window.MediaKeyMessageEvent);
+ assert_equals(event.target, mediaKeySession);
+ assert_equals(event.type, 'message');
+ assert_in_array(event.messageType, ['license-request', 'individualization-request']);
+
+ config.messagehandler(event.messageType, event.message).then( function(response) {
+ mediaKeySession.update(response).then( test.step_func( function() {
+ if ( event.messageType !== 'license-request' ) {
+ return;
+ }
+ assert_unreached( "Update with incorrect license type should fail" )
+ } ) ).catch( test.step_func( function( error ) {
+ if ( event.messageType !== 'license-request' ) {
+ forceTestFailureFromPromise(test, error);
+ return;
+ }
+
+ assert_throws_js(TypeError, () => { throw error; });
+ test.done();
+ } ) );
+ }).catch(onFailure);
+ }
+
+ navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+ if (config.initDataType && config.initData) {
+ initData = config.initData;
+ } else {
+ initData = getInitData(config.content, initDataType);
+ }
+ return access.createMediaKeys();
+ }).then(test.step_func(function(mediaKeys) {
+ mediaKeySession = mediaKeys.createSession('temporary');
+ waitForEventAndRunStep('message', mediaKeySession, test.step_func(processMessage), test);
+ return mediaKeySession.generateRequest(initDataType, initData);
+ })).catch(onFailure);
+ }, testname );
+
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/unique-origin.js b/testing/web-platform/tests/encrypted-media/scripts/unique-origin.js
new file mode 100644
index 0000000000..015ea9d4e9
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/unique-origin.js
@@ -0,0 +1,64 @@
+function runTest(config) {
+ // When the sandbox attribute is present on an iframe, it will
+ // treat the content as being from a unique origin. So try to
+ // call createMediaKeys() inside an iframe and it should fail.
+
+ function load_iframe(src, sandbox) {
+ return new Promise(function (resolve) {
+ var iframe = document.createElement('iframe');
+ iframe.onload = function () {
+ resolve(iframe);
+ };
+ iframe.sandbox = sandbox;
+ iframe.srcdoc = src;
+ document.documentElement.appendChild(iframe);
+ });
+ }
+
+ function wait_for_message() {
+ return new Promise(function (resolve) {
+ self.addEventListener('message', function listener(e) {
+ resolve(e.data);
+ self.removeEventListener('message', listener);
+ });
+ });
+ }
+
+ promise_test(function (test) {
+ var script =
+ '<script>' +
+ ' window.onmessage = function(e) {' +
+ ' navigator.requestMediaKeySystemAccess("' + config.keysystem + '", [{' +
+ ' initDataTypes: [\"' + config.initDataType + '\"],' +
+ ' audioCapabilities: [' +
+ ' { contentType:\'' + config.audioType + '\'},' +
+ ' ]' +
+ ' }]).then(function(access) {' +
+ ' return access.createMediaKeys();' +
+ ' }).then(function(mediaKeys) {' +
+ ' window.parent.postMessage({result: \'allowed\'}, \'*\');' +
+ ' }, function(error) {' +
+ ' window.parent.postMessage({result: \'failed\'}, \'*\');' +
+ ' });' +
+ ' };' +
+ '<\/script>';
+
+ // Verify that this page can create a MediaKeys first.
+ return navigator.requestMediaKeySystemAccess(config.keysystem, [{
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [
+ {contentType: config.audioType},
+ ]
+ }]).then(function (access) {
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ // Success, so now create the iframe and try there.
+ return load_iframe(script, 'allow-scripts allow-secure-context');
+ }).then(function (iframe) {
+ iframe.contentWindow.postMessage({}, '*');
+ return wait_for_message();
+ }).then(function (message) {
+ assert_equals(message.result, 'failed');
+ });
+ }, 'Unique origin is unable to create MediaKeys');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/update-disallowed-input.js b/testing/web-platform/tests/encrypted-media/scripts/update-disallowed-input.js
new file mode 100644
index 0000000000..2a30ad38d4
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/update-disallowed-input.js
@@ -0,0 +1,43 @@
+function runTest(config)
+{
+ // This test passes |response| to update() as a JSON Web Key Set.
+ // CDMs other than Clear Key won't expect |response| in this format.
+ promise_test(function(test) {
+ var initDataType;
+ var initData;
+ var keySystem = config.keysystem;
+ var mediaKeySession;
+
+ function createReallyLongJWKSet()
+ {
+ // This is just a standard JWKSet with a lot of
+ // extra items added to the end. Key ID and key
+ // doesn't really matter.
+ var jwkSet = '{"keys":[{'
+ + '"kty":"oct",'
+ + '"k":"MDEyMzQ1Njc4OTAxMjM0NQ",'
+ + '"kid":"MDEyMzQ1Njc4OTAxMjM0NQ"'
+ + '}]';
+ return jwkSet + ',"test":"unknown"'.repeat(4000) + '}';
+ }
+
+ var p = navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function(access) {
+ initDataType = access.getConfiguration().initDataTypes[0];
+ initData = getInitData(initDataType);
+ return access.createMediaKeys();
+ }).then(function(mediaKeys) {
+ mediaKeySession = mediaKeys.createSession();
+ var eventWatcher = new EventWatcher(test, mediaKeySession, ['message']);
+ var promise = eventWatcher.wait_for('message');
+ mediaKeySession.generateRequest(initDataType, initData);
+ return promise;
+ }).then(function () {
+ var jwkSet = createReallyLongJWKSet();
+ assert_greater_than(jwkSet.length, 65536);
+ var jwkSetArray = stringToUint8Array(jwkSet);
+ return mediaKeySession.update(jwkSetArray);
+ });
+
+ return promise_rejects_js(test, TypeError, p);
+ }, 'update() with invalid response (longer than 64Kb characters) should fail.');
+}
diff --git a/testing/web-platform/tests/encrypted-media/scripts/waiting-for-a-key.js b/testing/web-platform/tests/encrypted-media/scripts/waiting-for-a-key.js
new file mode 100644
index 0000000000..fdfb855677
--- /dev/null
+++ b/testing/web-platform/tests/encrypted-media/scripts/waiting-for-a-key.js
@@ -0,0 +1,166 @@
+function runTest(config)
+{
+ // For debugging timeouts, keep track of the number of the
+ // various events received.
+ var debugEncryptedEventFired = false;
+ var debugWaitingForKeyEventFired = false;
+ var debugTimeUpdateEventCount = 0;
+ var debugMessage = '';
+
+ // Set global option explicit_timeout to true and control
+ // the timeout in the promise test below.
+ setup({
+ explicit_timeout: true
+ });
+
+ promise_test(function (test) {
+ var video = config.video;
+ var keysystem = config.keysystem;
+ var configuration = {
+ initDataTypes: [config.initDataType],
+ audioCapabilities: [{
+ contentType: config.audioType
+ }],
+ videoCapabilities: [{
+ contentType: config.videoType
+ }],
+ sessionTypes: ['temporary']
+ };
+ var initData;
+ var initDataType;
+ var mediaKeySession;
+ // As this code doesn't wait for the 'message' event for clearkey to avoid
+ // race conditions with 'waitingforkey', specify the key ID and
+ // key used by the encrypted content.
+ var keyId = new Uint8Array(config.content.keys[0].kid);
+ var rawKey = new Uint8Array(config.content.keys[0].key);
+ // Use the message handler for non clearkey drm
+ var handler = config.messageHandler || null;
+
+ // Override timeout() to use custom message instead of default
+ // message "Test timed out"
+ test.timeout = function () {
+ var message = 'timeout. message = ' + debugMessage
+ + ', encrypted: ' + debugEncryptedEventFired
+ + ', waitingforkey: ' + debugWaitingForKeyEventFired
+ + ', timeupdate count: ' + debugTimeUpdateEventCount;
+
+ this.timeout_id = null;
+ this.set_status(this.TIMEOUT, message);
+ this.phase = this.phases.HAS_RESULT;
+ this.done();
+ };
+
+ return navigator.requestMediaKeySystemAccess(keysystem, [configuration]).then(function (access) {
+ debugMessage = 'createMediaKeys()';
+ return access.createMediaKeys();
+ }).then(function (mediaKeys) {
+ debugMessage = 'setMediaKeys()';
+ return video.setMediaKeys(mediaKeys);
+ }).then(function () {
+ return testmediasource(config);
+ }).then(function (source) {
+ debugMessage = 'wait_for_encrypted_event()';
+ mediaSource = source;
+ video.src = URL.createObjectURL(mediaSource);
+ video.play();
+ return wait_for_encrypted_event(video);
+ }).then(function (e) {
+ // Received the 'encrypted' event(s), so keep a copy of
+ // the initdata for use when creating the session later.
+ initDataType = config.initData ? config.initDataType : e.initDataType;
+ initData = config.initData || e.initData;
+ // Wait until the video indicates that it needs a key to
+ // continue.
+ debugMessage = 'wait_for_waitingforkey_event()';
+ return wait_for_waitingforkey_event(video);
+ }).then(function () {
+ // Make sure the video is NOT paused and not progressing
+ // before a key is provided. This requires the video
+ // to NOT have a clear lead.
+ assert_false(video.paused);
+ assert_less_than(video.currentTime, 0.2);
+ // Create a session.
+ mediaKeySession = video.mediaKeys.createSession('temporary');
+ debugMessage = 'generateRequest()';
+ return mediaKeySession.generateRequest(initDataType, initData);
+ }).then(function () {
+ // generateRequest() will cause a 'message' event to
+ // occur specifying the keyId that is needed
+ // Add the key needed to decrypt.
+ return wait_for_message_event(mediaKeySession, handler);
+ }).then(function () {
+ // Video should start playing now that it can decrypt the
+ // streams, so wait until a little bit of the video has
+ // played.
+ debugMessage = 'wait_for_timeupdate_event()';
+ return wait_for_timeupdate_event(video);
+ }).catch(function (error) {
+ assert_unreached('Error: ' + error.name);
+ });
+
+ // Typical test duration is 6 seconds on release builds
+ // (12 seconds on debug).
+ }, 'Waiting for a key.');
+
+ // Wait for an 'encrypted' event
+ function wait_for_encrypted_event(video)
+ {
+ return new Promise(function (resolve) {
+ video.addEventListener('encrypted', function listener(e) {
+ assert_equals(e.target, video);
+ assert_true(e instanceof window.MediaEncryptedEvent);
+ assert_equals(e.type, 'encrypted');
+ debugEncryptedEventFired = true;
+ video.removeEventListener('encrypted', listener);
+ resolve(e);
+ });
+ });
+ };
+
+ // Wait for a 'waitingforkey' event. Promise resolved when the
+ // event is received.
+ function wait_for_waitingforkey_event(video)
+ {
+ return new Promise(function (resolve) {
+ video.addEventListener('waitingforkey', function listener(e) {
+ assert_equals(e.target, video);
+ assert_equals(e.type, 'waitingforkey');
+ debugWaitingForKeyEventFired = true;
+ video.removeEventListener('waitingforkey', listener);
+ resolve(e);
+ });
+ });
+ };
+
+ // Wait for a 'timeupdate' event. Promise resolved if |video| has
+ // played for more than 0.2 seconds.
+ function wait_for_timeupdate_event(video)
+ {
+ return new Promise(function (resolve) {
+ video.addEventListener('timeupdate', function listener(e) {
+ assert_equals(e.target, video);
+ ++debugTimeUpdateEventCount;
+ if (video.currentTime < 0.2)
+ return;
+ video.removeEventListener('timeupdate', listener);
+ resolve(e);
+ });
+ });
+ };
+
+ // We need to wait for the message even if for non clearkey DRMs.
+ function wait_for_message_event(mediaKeySession, handler)
+ {
+ return new Promise(function (resolve, reject) {
+ mediaKeySession.addEventListener('message', function listener(e) {
+ assert_equals(e.target, mediaKeySession);
+ assert_equals(e.type, 'message');
+ video.removeEventListener('message', listener);
+ return handler(e.messageType, e.message).then(function (response) {
+ return e.target.update(response)
+ }).then(resolve, reject);
+ });
+ });
+ }
+}