Update web-platform-tests to revision 346d5b51a122f7bb1c7747064499ef281a0200f7

This commit is contained in:
Ms2ger 2016-06-24 10:13:49 +02:00
parent 581c8ba1c8
commit 79b1e6c40c
1728 changed files with 20243 additions and 5349 deletions

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test asynchronous creation of MediaKeys and MediaKeySession while running garbage collection</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
// Run garbage collection often.
setInterval(asyncGC, 0);
var initDataType;
var initData;
var mediaKeySession;
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest(initDataType, initData);
}).then(function() {
return mediaKeySession.close();
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Test asynchronous creation of MediaKeys and MediaKeySession while running garbage collection.');
</script>
</body>
</html>

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test asynchronous setServerCertificate while running garbage collection</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Run garbage collection continuously.
setInterval(asyncGC, 0);
promise_test(function(test)
{
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var cert = new Uint8Array(200);
return mediaKeys.setServerCertificate(cert);
}).then(function(result) {
assert_false(result);
});
}, 'Test asynchronous setServerCertificate while running garbage collection.');
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test support of different initDataTypes.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function checkInitDataType(initDataType)
{
return isInitDataTypeSupported(initDataType).then(function(result) {
// If |initDataType| is not supported, simply succeed.
if (!result)
return Promise.resolve('Not supported');
var options = [ { initDataTypes: [initDataType] } ];
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', options)
.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');
}, 'Clear key support for "webm".');
promise_test(function()
{
return checkInitDataType('cenc');
}, 'Clear key support for "cenc".');
promise_test(function()
{
return checkInitDataType('keyids');
}, 'Clear key support for "keyids".');
</script>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Invalid Clear Key License.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
var initDataType;
var initData;
var invalidLicense = new Uint8Array(
[0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]);
function handleMessage(event) {
event.target.update(invalidLicense).then(function(event) {
assert_unreached('Error: update() succeeded unexpectedly.');
test.done();
}).catch(function(error) {
assert_equals(error.name, 'InvalidAccessError');
test.done();
});
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var keySession = mediaKeys.createSession();
keySession.addEventListener('message', handleMessage, false);
keySession.generateRequest(initDataType, initData);
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Invalid Clear Key License.');
</script>
</body>
</html>

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test Clear Key handling of non-ASCII responses for update().</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// This test passes |response| to update() as a JSON Web Key Set.
// CDMs other than Clear Key won't expect |response| in this format.
async_test(function(test)
{
var initDataType;
var mediaKeySession;
function processMessage(event)
{
// |jwkSet| includes some non-ASCII characters.
var jwkSet = '{"keys":[{'
+ '"kty":"oct\uDC00\uD800",'
+ '"k":"MDEyMzQ1Njc4OTAxMjM0NQ",'
+ '"kid":"MDEyMzQ1Njc4OTAxMjM0NQ"'
+ '\xff\xfe}]';
mediaKeySession.update(stringToUint8Array(jwkSet)).then(function() {
forceTestFailureFromPromise(test, 'Error: update() succeeded');
}, function(error) {
assert_equals(error.name, 'InvalidAccessError');
test.done();
});
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, processMessage, test);
return mediaKeySession.generateRequest(initDataType, getInitData(initDataType));
});
}, 'Clear Key update() with non-ASCII response.');
</script>
</body>
</html>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Verify v2 events</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Currently Clear Key only generates aynchronous "message" and
// "keychange" events.
async_test(function(test)
{
var initDataType;
var initData;
var mediaKeySession;
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
function processMessage(event)
{
assert_true(event instanceof window.MediaKeyMessageEvent);
assert_equals(event.target, mediaKeySession);
assert_equals(event.type, 'message');
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
waitForEventAndRunStep('keystatuseschange', mediaKeySession, test.step_func(processKeyStatusesChange), test);
mediaKeySession.update(jwkSet).catch(test.step_func(function(error) {
forceTestFailureFromPromise(test, error);
}));
}
function processKeyStatusesChange(event)
{
assert_true(event instanceof Event);
assert_equals(event.target, mediaKeySession);
assert_equals(event.type, 'keystatuseschange');
test.done();
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
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(test.step_func(function(error) {
forceTestFailureFromPromise(test, error);
}));
}, 'Verify v2 events.');
</script>
</body>
</html>

View file

@ -0,0 +1,104 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test handling of invalid initData for generateRequest().</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Create a session and call generateRequest() with |initDataType|
// and |initData|. generateRequest() should fail with an
// InvalidAccessError. Returns a promise that resolves successfully
// if the error happened, rejects otherwise.
function test_session(initDataType, initData)
{
return isInitDataTypeSupported(initDataType).then(function(result) {
// If |initDataType| is not supported, simply succeed.
if (!result)
return Promise.resolve('Not supported');
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest(initDataType, initData);
}).then(function() {
assert_unreached('generateRequest() succeeded');
}, function(error) {
assert_equals(error.name, 'InvalidAccessError');
return Promise.resolve('success');
});
})
}
promise_test(function()
{
var initData = new Uint8Array(70000);
return test_session('webm', initData);
}, 'generateRequest() with webm initData longer than 64Kb characters.');
promise_test(function()
{
var initData = new Uint8Array(70000);
return test_session('cenc', initData);
}, 'generateRequest() with cenc initData longer than 64Kb characters.');
promise_test(function()
{
var initData = new Uint8Array(70000);
return test_session('keyids', initData);
}, 'generateRequest() with keyids initData longer than 64Kb characters.');
promise_test(function()
{
// Invalid 'pssh' box as the size specified is larger than what
// is provided.
var 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
]);
return test_session('cenc', initData);
}, 'generateRequest() with invalid pssh data.');
promise_test(function()
{
// Invalid data as type = 'psss'.
var 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
]);
return test_session('cenc', initData);
}, 'generateRequest() with non pssh data.');
promise_test(function()
{
// Valid key ID size must be at least 1 character for keyids.
var keyId = new Uint8Array(0);
var initData = stringToUint8Array(createKeyIDs(keyId));
return test_session('keyids', initData);
}, 'generateRequest() with too short key ID.');
promise_test(function()
{
// Valid key ID size must be less than 512 characters for keyids.
var keyId = new Uint8Array(600);
var initData = stringToUint8Array(createKeyIDs(keyId));
return test_session('keyids', initData);
}, 'generateRequest() with too long key ID.');
</script>
</body>
</html>

View file

@ -0,0 +1,120 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Verify MediaKeySession.keyStatuses with multiple sessions</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
var mediaKeySession1;
var mediaKeySession2;
var initDataType;
var initData;
// Even though key ids are uint8, using printable values so that
// they can be verified easily.
var key1 = stringToUint8Array('123');
var key2 = stringToUint8Array('4567890');
var rawKey1 = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
var rawKey2 = new Uint8Array([0x3c, 0xae, 0xe4, 0xfc, 0x2a, 0x12, 0xef, 0x68,
0x7b, 0xd2, 0x14, 0x68, 0xf1, 0x62, 0xdd, 0xeb]);
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.
var jwkSet = stringToUint8Array(createJWKSet(createJWK(key1, rawKey1)));
mediaKeySession1.update(jwkSet).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function processKeyStatusesChange1(event)
{
// This should only be called for session1.
assert_equals(event.target, mediaKeySession1);
// Check that keyStatuses contains the expected key1 only.
dumpKeyStatuses(mediaKeySession1.keyStatuses);
verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [key1], unexpected: [key2] });
// Now trigger a message event on session2.
mediaKeySession2.generateRequest(initDataType, initData).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
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.
var jwkSet = stringToUint8Array(createJWKSet(createJWK(key2, rawKey2)));
mediaKeySession2.update(jwkSet).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function processKeyStatusesChange2(event)
{
// This should only be called for session2.
assert_equals(event.target, mediaKeySession2);
// Check that keyStatuses contains the expected key2 only.
dumpKeyStatuses(mediaKeySession2.keyStatuses);
verifyKeyStatuses(mediaKeySession2.keyStatuses, { expected: [key2], unexpected: [key1] });
// session1 should still have 1 key.
verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [key1], unexpected: [key2] });
test.done();
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).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(initDataType, initData);
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Verify MediaKeySession.keyStatuses with multiple sessions.');
</script>
</body>
</html>

View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Verify MediaKeySession.keyStatuses with multiple updates</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
var initDataType;
var initData;
var mediaKeySession;
var firstEvent;
// Even though key ids are uint8, using printable values so that
// they can be verified easily.
var key1 = stringToUint8Array('123');
var key2 = stringToUint8Array('4567890');
var rawKey1 = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
var rawKey2 = new Uint8Array([0x3c, 0xae, 0xe4, 0xfc, 0x2a, 0x12, 0xef, 0x68,
0x7b, 0xd2, 0x14, 0x68, 0xf1, 0x62, 0xdd, 0xeb]);
function processMessage(event)
{
// No keys added yet.
verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [], unexpected: [key1, key2] });
// Add key1 to the session.
firstEvent = true;
var jwkSet = stringToUint8Array(createJWKSet(createJWK(key1, rawKey1)));
mediaKeySession.update(jwkSet).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function processKeyStatusesChange(event)
{
if (firstEvent) {
// Verify that the session only contains key1.
dumpKeyStatuses(mediaKeySession.keyStatuses);
verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [key1], unexpected: [key2] });
// Now add key2 to the session.
firstEvent = false;
var jwkSet = stringToUint8Array(createJWKSet(createJWK(key2, rawKey2)));
mediaKeySession.update(jwkSet).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
} else {
// Verify that the session now contains key1 and key2.
dumpKeyStatuses(mediaKeySession.keyStatuses);
verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [key1, key2] });
test.done();
}
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
// There should be no keys defined yet.
assert_equals(mediaKeySession.keyStatuses.size, 0);
waitForEventAndRunStep('message', mediaKeySession, processMessage, test);
waitForEventAndRunStep('keystatuseschange', mediaKeySession, processKeyStatusesChange, test);
return mediaKeySession.generateRequest(initDataType, initData);
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Verify MediaKeySession.keyStatuses with multiple updates.');
</script>
</body>
</html>

View file

@ -0,0 +1,124 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Verify MediaKeySession.keyStatuses</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
var mediaKeySession;
var initDataType;
var initData;
// Even though key ids are uint8, using printable values so that
// they can be verified easily.
var key1String = '123';
var key2String = '4567890';
var key1 = stringToUint8Array(key1String);
var key2 = stringToUint8Array(key2String);
var rawKey1 = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
var rawKey2 = new Uint8Array([0x3c, 0xae, 0xe4, 0xfc, 0x2a, 0x12, 0xef, 0x68,
0x7b, 0xd2, 0x14, 0x68, 0xf1, 0x62, 0xdd, 0xeb]);
function processMessage(event)
{
// No keys added yet.
assert_equals(mediaKeySession.keyStatuses.size, 0);
waitForEventAndRunStep('keystatuseschange', mediaKeySession, processKeyStatusesChange, test);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(key1, rawKey1), createJWK(key2, rawKey2)));
mediaKeySession.update(jwkSet).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function processKeyStatusesChange(event)
{
// Two keys added, so both should show up in |keyStatuses|.
assert_equals(mediaKeySession.keyStatuses.size, 2);
dumpKeyStatuses(mediaKeySession.keyStatuses);
// Check |keyStatuses| for 2 entries.
var result = [];
for (var entry of mediaKeySession.keyStatuses) {
result.push({ key: arrayBufferAsString(entry[0]), value: entry[1] });
}
assert_object_equals(result,
[{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}],
'keyStatuses fails');
// |keyStatuses| must contain both keys.
result = [];
for (var key of mediaKeySession.keyStatuses.keys()) {
result.push(arrayBufferAsString(key));
}
assert_array_equals(result,
[key1String, key2String],
'keyStatuses.keys() fails');
// Both values in |mediaKeySession| should be 'usable'.
result = [];
for (var value of mediaKeySession.keyStatuses.values()) {
result.push(value);
}
assert_array_equals(result,
['usable', 'usable'],
'keyStatuses.values() fails');
// Check |keyStatuses.entries()|.
result = [];
for (var entry of mediaKeySession.keyStatuses.entries()) {
result.push({ key: arrayBufferAsString(entry[0]), value: entry[1] });
}
assert_object_equals(result,
[{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}],
'keyStatuses.entries() fails');
// forEach() should return both entries.
result = [];
mediaKeySession.keyStatuses.forEach(function(value, key, map) {
result.push({ key: arrayBufferAsString(key), value: value });
});
assert_object_equals(result,
[{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}],
'keyStatuses.forEach() fails');
assert_true(mediaKeySession.keyStatuses.has(key1));
assert_true(mediaKeySession.keyStatuses.has(key2));
assert_false(mediaKeySession.keyStatuses.has(stringToUint8Array('123456')));
assert_equals(mediaKeySession.keyStatuses.get(key1), 'usable');
assert_equals(mediaKeySession.keyStatuses.get(key2), 'usable');
assert_equals(mediaKeySession.keyStatuses.get(stringToUint8Array('123456')), undefined);
test.done();
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
// There should be no keys defined yet.
assert_equals(mediaKeySession.keyStatuses.size, 0);
waitForEventAndRunStep('message', mediaKeySession, processMessage, test);
return mediaKeySession.generateRequest(initDataType, initData);
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Verify MediaKeySession.keyStatuses.');
</script>
</body>
</html>

View file

@ -0,0 +1,104 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeys lifetime when adding a session</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// MediaKeySessions remain as long as:
// JavaScript has a reference to it
// OR (MediaKeys is around
// AND the session has not received a close() event)
// In the tests below, we do not close any session nor keep a
// Javascript reference to any session, so MediaKeySessions remain
// as long as the associated MediaKeys object is around.
// For this test, create a MediaKeySession and verify lifetime.
async_test(function(test)
{
var initDataType;
var initData;
var mediaKeys;
var startingActiveDOMObjectCount = window.internals.activeDOMObjectCount(document);
function numActiveDOMObjectsCreated()
{
return window.internals.activeDOMObjectCount(document) - startingActiveDOMObjectCount;
}
// Create a MediaKeys object with a session.
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
assert_equals(access.keySystem, 'org.w3.clearkey');
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
// Verify MediaKeys is an ActiveDOMObject.
// In non-Oilpan, numActiveDOMObjectsCreate() == 1.
// In Oilpan, numActiveDOMObjectsCreate() <= 4.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 1 MediaKeySystemAccessInitializer (navigator.requestMediaKeySystemAccess() use above),
// 1 MediaKeySystemAccessInitializer (isInitDataSupported() (via getSupportedInitDataType())))
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 4, 'MediaKeys.create()');
var mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest(initDataType, initData);
}).then(function() {
// Should be 1 MediaKeys + 1 MediaKeySession.
// In non-Oilpan, numActiveDOMObjectsCreate() == 2.
// In Oilpan, numActiveDOMObjectsCreate() <= 6.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializer,
// 1 ContentDecryptionModuleResultPromise and
// 1 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 6, 'MediaKeys.createSession()');
// Run gc(), should not affect MediaKeys object nor the
// session since we still have a reference to it.
// When enabling oilpan GC, the in-active
// ScriptPromiseResolvers will be destroyed.
return createGCPromise();
}).then(function(result) {
assert_equals(typeof mediaKeys.createSession, 'function');
// MediaKeys + MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 3, 'After gc()');
// Drop reference to the MediaKeys object and run gc()
// again. Object should be collected this time. Since
// MediaKeySessions remain alive as long as MediaKeys is
// around, it is possible that gc() checks the
// MediaKeySession object first, and doesn't collect it
// since MediaKeys hasn't been collected yet. Thus run gc()
// twice, to ensure that the unreferenced MediaKeySession
// object get collected.
mediaKeys = null;
return createGCPromise();
}).then(function(result) {
return createGCPromise();
}).then(function(result) {
// No MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 0, 1, 'After final gc()');
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'MediaKeys lifetime with session');
</script>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeys lifetime</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
// Create a MediaKeys object and free immediately.
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
// Do nothing with the created object
}).then(function(result) {
// No way to verify that MediaKeys object is actually
// collected, but make sure it doesn't crash.
return createGCPromise();
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Creating and destroying MediaKeys does not crash');
async_test(function(test)
{
var mediaKeys;
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
return createGCPromise();
}).then(function(result) {
// Check that the object still exists.
assert_equals(typeof mediaKeys.createSession, 'function');
mediaKeys = null;
// Now that the reference is dropped, it should be
// collected. No way to verify that it is actually
// collected, but make sure it doesn't crash.
return createGCPromise();
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'MediaKeys is not collected as long as we have a reference');
</script>
</body>
</html>

View file

@ -0,0 +1,157 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeySession lifetime without release()</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Since MediaKeySession (and MediaKeys) are ActiveDOMObjects,
// we can determine when they are garbage collected.
// MediaKeySessions remain as long as:
// JavaScript has a reference to it
// OR (MediaKeys is around
// AND the session has not received a close() event)
async_test(function(test)
{
var mediaKeys;
var mediaKeySession1;
var mediaKeySession2;
var mediaKeySession3;
var initDataType;
var initData;
var startingActiveDOMObjectCount = window.internals.activeDOMObjectCount(document);
function numActiveDOMObjectsCreated()
{
return window.internals.activeDOMObjectCount(document) - startingActiveDOMObjectCount;
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
assert_equals(access.keySystem, 'org.w3.clearkey');
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
assert_equals(typeof mediaKeys.createSession, 'function');
// Verify MediaKeys is an ActiveDOMObject.
// In non-Oilpan, numActiveDOMObjectsCreate() == 1.
// In Oilpan, numActiveDOMObjectsCreate() <= 4.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 1 MediaKeySystemAccessInitializer (navigator.requestMediaKeySystemAccess() use above),
// 1 MediaKeySystemAccessInitializer (isInitDataSupported() (via getSupportedInitDataType())))
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 4, 'MediaKeys.create()');
// Create 3 sessions.
mediaKeySession1 = mediaKeys.createSession();
return mediaKeySession1.generateRequest(initDataType, initData);
}).then(function() {
assert_true(mediaKeySession1.sessionId && mediaKeySession1.sessionId.length > 0);
// Should be 1 MediaKeys + 1 MediaKeySession.
// In non-Oilpan, numActiveDOMObjectsCreate() == 2.
// In Oilpan, numActiveDOMObjectsCreate() <= 6.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializer,
// 1 ContentDecryptionModuleResultPromise and
// 1 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 6, 'MediaKeys.createSession(1)');
mediaKeySession2 = mediaKeys.createSession();
return mediaKeySession2.generateRequest(initDataType, initData);
}).then(function() {
assert_true(mediaKeySession2.sessionId && mediaKeySession2.sessionId.length > 0);
// Should be 1 MediaKeys + 2 MediaKeySessions.
// In non-Oilpan, numActiveDOMObjectsCreate() == 3.
// In Oilpan, numActiveDOMObjectsCreate() <= 8.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializers,
// 2 ContentDecryptionModuleResultPromise and
// 2 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 8, 'mediaKeys.createSession(2)');
mediaKeySession3 = mediaKeys.createSession();
return mediaKeySession3.generateRequest(initDataType, initData);
}).then(function() {
assert_true(mediaKeySession3.sessionId && mediaKeySession3.sessionId.length > 0);
// Should be 1 MediaKeys + 3 MediaKeySessions.
// In non-Oilpan, numActiveDOMObjectsCreate() == 4.
// In Oilpan, numActiveDOMObjectsCreate() <= 10.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializers,
// 3 ContentDecryptionModuleResultPromise and
// 3 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 4, 10, 'mediaKeys.createSession(3)');
// Run gc(). All sessions should remain as we have a
// reference to each one. However, running gc()
// asynchronously should free up the last PromiseResolver.
return createGCPromise();
}).then(function(result) {
// Only MediaKeys + 3 MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 4, 5, 'After gc()');
// Now drop references to 2 of the sessions. Even though we
// don't have a reference, MediaKeys is still around (and
// the sessions aren't closed), so the objects won't be
// collected.
mediaKeySession1 = null;
mediaKeySession2 = null;
return createGCPromise();
}).then(function(result) {
return createGCPromise();
}).then(function(result) {
// MediaKeys + 3 MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 4, 5, 'After second gc()');
// Now drop the reference to MediaKeys. It and the 2
// unreferenced sessions should be collected. Since
// MediaKeySessions remain alive as long as MediaKeys is
// around, it is possible that gc() checks one or both
// MediaKeySession objects first, and doesn't collect them
// since MediaKeys hasn't been collected yet. Thus run gc()
// twice, to ensure that the unreferenced MediaKeySession
// objects get collected.
mediaKeys = null;
return createGCPromise();
}).then(function(result) {
return createGCPromise();
}).then(function(result) {
// Only 1 MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 2, 'After mediaKeys = null');
// Drop the reference to the last session. It should get
// collected now since MediaKeys is gone.
mediaKeySession3 = null;
return createGCPromise();
}).then(function(result) {
// No MediaKeySessions should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 0, 1, 'After final gc()');
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'MediaKeySession lifetime without release()');
</script>
</body>
</html>

View file

@ -0,0 +1,129 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeySession lifetime after release() without references</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Since MediaKeySession (and MediaKeys) are ActiveDOMObjects,
// we can determine when they are garbage collected.
// MediaKeySessions remain as long as:
// JavaScript has a reference to it
// OR (MediaKeys is around
// AND the session has not received a close() event)
async_test(function(test)
{
var initDataType;
var initData;
var startingActiveDOMObjectCount = window.internals.activeDOMObjectCount(document);
function numActiveDOMObjectsCreated()
{
return window.internals.activeDOMObjectCount(document) - startingActiveDOMObjectCount;
}
// Create 2 sessions.
var mediaKeys;
var mediaKeySession1;
var mediaKeySession2;
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
// Verify MediaKeys is an ActiveDOMObject.
// In non-Oilpan, numActiveDOMObjectsCreate() == 1.
// In Oilpan, numActiveDOMObjectsCreate() <= 4.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 1 MediaKeySystemAccessInitializer (navigator.requestMediaKeySystemAccess() use above),
// 1 MediaKeySystemAccessInitializer (isInitDataSupported() (via getSupportedInitDataType())))
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 4, 'MediaKeys.create()');
mediaKeySession1 = mediaKeys.createSession();
return mediaKeySession1.generateRequest(initDataType, initData);
}).then(function() {
assert_true(mediaKeySession1.sessionId && mediaKeySession1.sessionId.length > 0);
// Should be 1 MediaKeys + 1 MediaKeySession.
// In non-Oilpan, numActiveDOMObjectsCreate() == 2.
// In Oilpan, numActiveDOMObjectsCreate() <= 6.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializer,
// 1 ContentDecryptionModuleResultPromise and
// 1 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 6, 'MediaKeys.createSession(1)');
mediaKeySession2 = mediaKeys.createSession();
return mediaKeySession2.generateRequest(initDataType, initData);
}).then(function() {
assert_true(mediaKeySession2.sessionId && mediaKeySession2.sessionId.length > 0);
// Should be 1 MediaKeys + 2 MediaKeySessions.
// In non-Oilpan, numActiveDOMObjectsCreate() == 3.
// In Oilpan, numActiveDOMObjectsCreate() <= 8.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 2 MediaKeySystemAccessInitializers,
// 2 ContentDecryptionModuleResultPromise and
// 2 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 8, 'mediaKeys.createSession(2)');
}).then(function(result) {
// Run gc(). All sessions should remain as we have a
// reference to each one.
return createGCPromise();
}).then(function(result) {
// Should be just 1 MediaKeys + 2 MediaKeySessions.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 4, 'After gc()');
// Close the sessions. Once the close() event is received,
// they should get garbage collected as there are no JS
// references to them.
var promise = mediaKeySession1.close();
mediaKeySession1 = null;
return promise;
}).then(function(result) {
// Give time so that the close event can be processed by
// MediaKeySession.
return delayToAllowEventProcessingPromise();
}).then(function(result) {
return createGCPromise();
}).then(function(result) {
// Only MediaKeys + mediaKeySession2 should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 3, 'mediaKeySession1 not collected');
var promise = mediaKeySession2.close();
mediaKeySession2 = null;
return promise;
}).then(function(result) {
// Provide time for the mediaKeySession2 close event to be
// handled.
return delayToAllowEventProcessingPromise();
}).then(function(result) {
return createGCPromise();
}).then(function(result) {
// Only MediaKeys should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 2, 'mediaKeySession2 not collected');
assert_not_equals(mediaKeys, null);
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'MediaKeySession lifetime after release() without references');
</script>
</body>
</html>

View file

@ -0,0 +1,117 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>MediaKeySession lifetime after release()</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Since MediaKeySession (and MediaKeys) are ActiveDOMObjects,
// we can determine when they are garbage collected.
// MediaKeySessions remain as long as:
// JavaScript has a reference to it
// OR (MediaKeys is around
// AND the session has not received a close() event)
async_test(function(test)
{
var mediaKeys;
var mediaKeySession1;
var mediaKeySession2;
var initDataType;
var initData;
var startingActiveDOMObjectCount = window.internals.activeDOMObjectCount(document);
function numActiveDOMObjectsCreated()
{
return window.internals.activeDOMObjectCount(document) - startingActiveDOMObjectCount;
}
// Create 2 sessions.
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
// Verify MediaKeys is an ActiveDOMObject.
// In non-Oilpan, numActiveDOMObjectsCreate() == 1.
// In Oilpan, numActiveDOMObjectsCreate() <= 4.
// (1 MediaKeys,
// 1 MediaKeysInitializer and
// 1 MediaKeySystemAccessInitializer (navigator.requestMediaKeySystemAccess() use above),
// 1 MediaKeySystemAccessInitializer (isInitDataSupported() (via getSupportedInitDataType())))
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 4, 'MediaKeys.create()');
mediaKeySession1 = mediaKeys.createSession();
return mediaKeySession1.generateRequest(initDataType, initData);
}).then(function() {
// Should be 1 MediaKeys + 1 MediaKeySession.
// In non-Oilpan, numActiveDOMObjectsCreate() == 2.
// In Oilpan, numActiveDOMObjectsCreate() <= 6.
// (1 MediaKeys,
// 1 MediaKeysInitializer,
// 2 MediaKeySystemAccessInitializers,
// 1 ContentDecryptionModuleResultPromise and
// 1 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 6, 'MediaKeys.createSession(1)');
mediaKeySession2 = mediaKeys.createSession();
return mediaKeySession2.generateRequest(initDataType, initData);
}).then(function() {
// Should be 1 MediaKeys + 2 MediaKeySessions.
// In non-Oilpan, numActiveDOMObjectsCreate() == 3.
// In Oilpan, numActiveDOMObjectsCreate() <= 8.
// (1 MediaKeys,
// 1 MediaKeysInitializer,
// 2 MediaKeySystemAccessInitializers,
// 2 ContentDecryptionModuleResultPromise and
// 2 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 8, 'mediaKeys.createSession(2)');
// Close the sessions. Once completed, only the JS
// reference to them keeps them around.
return mediaKeySession1.close();
}).then(function(result) {
return mediaKeySession2.close();
}).then(function(result) {
// Since both sessions have been closed, dropping the
// reference to them from JS will result in the session
// being garbage-collected.
// Should be 1 MediaKeys + 2 MediaKeySessions.
// In non-Oilpan, numActiveDOMObjectsCreate() == 3.
// In Oilpan, numActiveDOMObjectsCreate() <= 10.
// (1 MediaKeys,
// 1 MediaKeysInitializer,
// 2 MediaKeySystemAccessInitializers,
// 4 ContentDecryptionModuleResultPromise and
// 2 MediaKeySession).
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 10, 'after close');
mediaKeySession1 = null;
return createGCPromise();
}).then(function() {
// Only MediaKeys + mediaKeySession2 should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 3, 'mediaKeySession1 not collected');
mediaKeySession2 = null;
return createGCPromise();
}).then(function() {
// Only MediaKeys should remain.
// In non-Oilpan, there is also something from createGCPromise().
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 2, 'mediaKeySession2 not collected');
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'MediaKeySession lifetime after release()');
</script>
</body>
</html>

View file

@ -0,0 +1,130 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test multiple MediaKeys lifetimes</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// For this test, create several MediaKeys and verify lifetime.
async_test(function(test)
{
var mediaKeys;
var startingActiveDOMObjectCount = window.internals.activeDOMObjectCount(document);
function numActiveDOMObjectsCreated()
{
return window.internals.activeDOMObjectCount(document) - startingActiveDOMObjectCount;
}
// Create a MediaKeys object. Returns a promise that resolves
// with the new MediaKeys object.
function createMediaKeys()
{
return getSupportedInitDataType().then(function(type) {
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
return mediaKeys;
});
}
// Create a few MediaKeys objects. Only keep a reference to the
// last one created.
createMediaKeys().then(function(result) {
// Should be 1 MediaKeys.
// In non-Oilpan, numActiveDOMObjectsCreate() == 1.
// In Oilpan, numActiveDOMObjectsCreated() <= 4.
// (1 MediaKeysInitializer,
// 1 MediaKeySystemAccessInitializer (navigator.requestMediaKeySystemAccess() use above),
// 1 MediaKeySystemAccessInitializer (isInitDataSupported() (via getSupportedInitDataType())) and
// 1 ContentDecryptionModuleResultPromise).
assert_between_inclusive(numActiveDOMObjectsCreated(), 1, 4);
return createMediaKeys();
}).then(function(result) {
// Should be 2 MediaKeys.
// In non-Oilpan, numActiveDOMObjectsCreate() == 2.
// In Oilpan, numActiveDOMObjectsCreate() <= 8.
// (2 MediaKeysInitializer,
// 4 MediaKeySystemAccessInitializer and
// 2 ContentDecryptionModuleResultPromise).
assert_between_inclusive(numActiveDOMObjectsCreated(), 2, 8);
return createMediaKeys();
}).then(function(result) {
// Should be 3 MediaKeys.
// In non-Oilpan, numActiveDOMObjectsCreate() == 3.
// In Oilpan, numActiveDOMObjectsCreate() <= 12.
// (3 MediaKeysInitializer,
// 6 MediaKeySystemAccessInitializer and
// 3 ContentDecryptionModuleResultPromise).
assert_between_inclusive(numActiveDOMObjectsCreated(), 3, 12);
return createMediaKeys();
}).then(function(result) {
// Should be 4 MediaKeys.
// In non-Oilpan, numActiveDOMObjectsCreate() == 4.
// In Oilpan, numActiveDOMObjectsCreate() <= 16.
// (4 MediaKeysInitializer,
// 8 MediaKeySystemAccessInitializer and
// 4 ContentDecryptionModuleResultPromise).
assert_between_inclusive(numActiveDOMObjectsCreated(), 4, 16);
return createMediaKeys();
}).then(function(result) {
// Should be 5 MediaKeys.
// In non-Oilpan, numActiveDOMObjectsCreate() == 5.
// In Oilpan, numActiveDOMObjectsCreate() <= 20.
// (5 MediaKeysInitializer,
// 10 MediaKeySystemAccessInitializer and
// 5 ContentDecryptionModuleResultPromise).
assert_between_inclusive(numActiveDOMObjectsCreated(), 5, 20);
// |mediaKeys| refers to the most recently created MediaKeys
// object.
mediaKeys = result;
// In order for the MediaKey objects to be garbage
// collected, it needs time to process any pending events.
return delayToAllowEventProcessingPromise();
}).then(function(result) {
// In non-Oilpan, numActiveDOMObjectsCreated() == 5
// (5 MediaKeySession objects).
// In Oilpan, numActiveDOMObjectsCreated() <= 23
// (5 MediaKeysInitializer,
// 12 MediaKeySystemAccessInitializer,
// 5 ContentDecryptionModuleResultPromise and
// 1 DOMTimer (in delayToAllowEventProcessingPromise))
assert_between_inclusive(numActiveDOMObjectsCreated(), 5, 23);
// As we only have a reference (|mediaKeys|) to the last
// created MediaKeys object, the other 4 MediaKeys objects
// are available to be garbage collected.
return createGCPromise();
}).then(function(result) {
// Should be 1 MediaKeys and DOMTimer.
assert_less_than_equal(numActiveDOMObjectsCreated(), 2);
assert_equals(typeof mediaKeys.createSession, 'function');
// Release the last MediaKeys object created.
mediaKeys = null;
// Run gc() again to reclaim the remaining MediaKeys object.
return createGCPromise();
}).then(function(result) {
// Should be just a DOMTimer.
assert_less_than_equal(numActiveDOMObjectsCreated(), 1);
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Multiple MediaKeys lifetime');
</script>
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Reloading during encrypted media playback</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var video = document.getElementById('testVideo');
var mediaKeySession = null;
var hasSessionUpdateSucceeded = false;
var encryptedEventCount = 0;
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
function onEncrypted(event)
{
assert_equals(event.target, video);
assert_true(event instanceof window.MediaEncryptedEvent);
assert_equals(event.type, 'encrypted');
// The same decryption key is used by both the audio and
// the video streams so only create a session once. To
// avoid issues when comparing the expected.txt file
// (which logs the events in the order they occur), create
// the session on the second event. This also ensures we
// see both events.
if (++encryptedEventCount != 2)
return;
mediaKeySession = video.mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
mediaKeySession.generateRequest(event.initDataType, event.initData).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onMessage(event)
{
assert_true(event instanceof window.MediaKeyMessageEvent);
assert_equals(event.target, mediaKeySession);
assert_equals(event.type, 'message');
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
mediaKeySession.update(jwkSet).then(function(result) {
hasSessionUpdateSucceeded = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onPlaying(event)
{
// Not using waitForEventAndRunStep() to avoid too many
// EVENT(onTimeUpdate) logs.
video.addEventListener('timeupdate', onTimeUpdate, true);
}
function onTimeUpdate(event)
{
if (event.target.currentTime < 0.2 || !hasSessionUpdateSucceeded)
return;
// Reload the page to catch any possible teardown issues.
if (location.hash == '#x') {
test.done();
return;
}
location.hash += 'x';
location.reload();
}
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
waitForEventAndRunStep('playing', video, onPlaying, test);
video.src = '../content/test-encrypted.webm';
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.play();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Reloading during encrypted media playback.');
</script>
</body>
</html>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeySession not callable immediately after CreateSession().</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// After creation, the MediaKeySession object is not
// callable, and we should get a InvalidStateError.
promise_test(function()
{
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).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');
});
});
}, 'Update() immediately after CreateSession().');
promise_test(function()
{
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).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');
});
});
}, 'Close() immediately after CreateSession().');
promise_test(function()
{
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).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');
});
});
}, 'Remove() immediately after CreateSession().');
</script>
</body>
</html>

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>onencrypted</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo" controls></video>
<div id="log"></div>
<script>
var expectedInitData = stringToUint8Array('0123456789012345');
// Will get 2 identical events, one for audio, one for video.
var expectedEvents = 2;
async_test(function(test)
{
var video = document.getElementById('testVideo');
var onEncrypted = function(event)
{
assert_equals(event.target, video);
assert_true(event instanceof window.MediaEncryptedEvent);
assert_equals(event.type, 'encrypted');
assert_equals(event.initDataType, 'webm');
assert_array_equals(new Uint8Array(event.initData), expectedInitData);
if (--expectedEvents == 0)
test.done();
};
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
video.src = '../content/test-encrypted.webm';
}, 'encrypted fired on encrypted media file.');
</script>
</body>
</html>

View file

@ -0,0 +1,121 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Multiple playbacks alternating between encrypted and clear sources.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var video = document.getElementById('testVideo');
var isUpdatePromiseResolved = false;
var encryptedEventCount = 0;
var playbackCount = 0;
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
function onEncrypted(event)
{
assert_equals(event.target, video);
assert_true(event instanceof window.MediaEncryptedEvent);
assert_equals(event.type, 'encrypted');
// The same decryption key is used by both the audio and
// the video streams so only create a session once. To
// avoid issues when comparing the expected.txt file
// (which logs the events in the order they occur), create
// the session on the second event. This also ensures we
// see both events.
if (++encryptedEventCount != 2)
return;
assert_false(video.mediaKeys === null, "video.mediaKeys is null.");
var mediaKeySession = video.mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
mediaKeySession.generateRequest(event.initDataType, event.initData).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onMessage(event)
{
assert_true(event instanceof window.MediaKeyMessageEvent);
assert_equals(event.type, 'message');
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
event.target.update(jwkSet).then(function(result) {
isUpdatePromiseResolved = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onPlaying(event)
{
// Not using waitForEventAndRunStep() to avoid too many
// EVENT(onTimeUpdate) logs.
video.addEventListener('timeupdate', onTimeUpdate, true);
}
function onTimeUpdate(event)
{
if (event.target.currentTime < 0.2 || !isUpdatePromiseResolved)
return;
video.removeEventListener('timeupdate', onTimeUpdate, true);
if (playbackCount > 2) {
test.done();
return;
}
playbackCount++;
resetSrc().then(function(){
startPlayback();
});
}
function resetSrc() {
encryptedEventCount = 0;
video.removeAttribute('src');
video.load();
return video.setMediaKeys(null);
}
function startPlayback() {
if (playbackCount % 2) {
video.src = '../content/test-vp8-vorbis-webvtt.webm';
video.play();
return;
}
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.src = '../content/test-encrypted.webm';
assert_false(video.mediaKeys === null, "video.mediaKeys is null.");
video.play();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
waitForEventAndRunStep('playing', video, onPlaying, test);
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
startPlayback();
}, 'Multiple playbacks alternating between encrypted and clear sources.');
</script>
</body>
</html>

View file

@ -0,0 +1,139 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Clear Key Playback with Multiple Sessions</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var video = document.getElementById('testVideo');
var audioMediaKeySession = null;
var videoMediaKeySession = null;
var audioInitDataType = null;
var videoInitDataType = null;
var audioInitData = null;
var videoInitData = null;
var audioKeyProvided = false;
var videoKeyProvided = false;
// The 2 streams use different key ids and different keys.
var audioKeyId = '1234567890123456';
var audioKey = new Uint8Array([0x30, 0x30, 0x62, 0xF1, 0x68, 0x14, 0xD2, 0x7B,
0x68, 0xEF, 0x12, 0x2A, 0xFC, 0xE4, 0xAE, 0x0A]);
var videoKeyId = '0123456789012345';
var videoKey = new Uint8Array([0x7A, 0x7A, 0x62, 0xF1, 0x68, 0x14, 0xD2, 0x7B,
0x68, 0xEF, 0x12, 0x2A, 0xFC, 0xE4, 0xAE, 0x0A]);
function onEncrypted(event)
{
var keyId = String.fromCharCode.apply(null, new Uint8Array(event.initData));
// To avoid issues when comparing the expected.txt file
// (which logs the events in the order they occur), save
// the initData and make the calls to generateRequest()
// only after both "onencrypted" events are received.
// This prevents a "message" event from occurring before
// both "onencrypted" events are received.
var mediaKeySession = video.mediaKeys.createSession();
if (keyId == videoKeyId) {
assert_equals(videoMediaKeySession, null);
videoMediaKeySession = mediaKeySession;
videoInitDataType = event.initDataType;
videoInitData = event.initData;
// Return if audio "onencrypted" event not yet received.
if (audioMediaKeySession == null)
return;
} else {
assert_equals(keyId, audioKeyId);
assert_equals(audioMediaKeySession, null);
audioMediaKeySession = mediaKeySession;
audioInitDataType = event.initDataType;
audioInitData = event.initData;
// Return if video "onencrypted" event not yet received.
if (videoMediaKeySession == null)
return;
}
// Both sessions have been created.
assert_not_equals(videoMediaKeySession, null);
assert_not_equals(audioMediaKeySession, null);
var promises = [];
waitForEventAndRunStep('message', videoMediaKeySession, onMessage, test);
promises.push(videoMediaKeySession.generateRequest(videoInitDataType, videoInitData));
waitForEventAndRunStep('message', audioMediaKeySession, onMessage, test);
promises.push(audioMediaKeySession.generateRequest(audioInitDataType, audioInitData));
Promise.all(promises).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onMessage(event)
{
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
if (event.target == videoMediaKeySession) {
assert_equals(String.fromCharCode.apply(null, keyId), videoKeyId);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, videoKey)));
videoMediaKeySession.update(jwkSet).then(function(result) {
videoKeyProvided = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
} else {
assert_equals(event.target, audioMediaKeySession);
assert_equals(String.fromCharCode.apply(null, keyId), audioKeyId);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, audioKey)));
audioMediaKeySession.update(jwkSet).then(function(result) {
audioKeyProvided = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
}
function onPlaying(event)
{
// Video should not start playing until both keys have been
// provided.
assert_true(videoKeyProvided);
assert_true(audioKeyProvided);
// Not using waitForEventAndRunStep() to avoid too many
// EVENT(onTimeUpdate) logs.
video.addEventListener('timeupdate', onTimeUpdate, true);
}
function onTimeUpdate(event)
{
if (event.target.currentTime < 0.2)
return;
test.done();
}
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
waitForEventAndRunStep('playing', video, onPlaying, test);
video.src = '../content/test-encrypted-different-av-keys.webm';
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.play();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Playback using Clear Key key system with multiple sessions.');
</script>
</body>
</html>

View file

@ -0,0 +1,92 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Clear Key Playback</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var video = document.getElementById('testVideo');
var isUpdatePromiseResolved = false;
var encryptedEventCount = 0;
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
function onEncrypted(event)
{
assert_equals(event.target, video);
assert_true(event instanceof window.MediaEncryptedEvent);
assert_equals(event.type, 'encrypted');
// The same decryption key is used by both the audio and
// the video streams so only create a session once. To
// avoid issues when comparing the expected.txt file
// (which logs the events in the order they occur), create
// the session on the second event. This also ensures we
// see both events.
if (++encryptedEventCount != 2)
return;
var mediaKeySession = video.mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
mediaKeySession.generateRequest(event.initDataType, event.initData).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onMessage(event)
{
assert_true(event instanceof window.MediaKeyMessageEvent);
assert_equals(event.type, 'message');
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
event.target.update(jwkSet).then(function(result) {
isUpdatePromiseResolved = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onPlaying(event)
{
// Not using waitForEventAndRunStep() to avoid too many
// EVENT(onTimeUpdate) logs.
video.addEventListener('timeupdate', onTimeUpdate, true);
}
function onTimeUpdate(event)
{
if (event.target.currentTime < 0.2 || !isUpdatePromiseResolved)
return;
test.done();
}
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
waitForEventAndRunStep('playing', video, onPlaying, test);
video.src = '../content/test-encrypted.webm';
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.play();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Playback using Clear Key key system, calling setMediaKeys() after setting src attribute.');
</script>
</body>
</html>

View file

@ -0,0 +1,92 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Clear Key Playback</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var video = document.getElementById('testVideo');
var isUpdatePromiseResolved = false;
var encryptedEventCount = 0;
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
function onEncrypted(event)
{
assert_equals(event.target, video);
assert_true(event instanceof window.MediaEncryptedEvent);
assert_equals(event.type, 'encrypted');
// The same decryption key is used by both the audio and
// the video streams so only create a session once. To
// avoid issues when comparing the expected.txt file
// (which logs the events in the order they occur), create
// the session on the second event. This also ensures we
// see both events.
if (++encryptedEventCount != 2)
return;
var mediaKeySession = video.mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, onMessage, test);
mediaKeySession.generateRequest(event.initDataType, event.initData).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onMessage(event)
{
assert_true(event instanceof window.MediaKeyMessageEvent);
assert_equals(event.type, 'message');
assert_equals(event.messageType, 'license-request');
var keyId = extractSingleKeyIdFromMessage(event.message);
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
event.target.update(jwkSet).then(function(result) {
isUpdatePromiseResolved = true;
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}
function onPlaying(event)
{
// Not using waitForEventAndRunStep() to avoid too many
// EVENT(onTimeUpdate) logs.
video.addEventListener('timeupdate', onTimeUpdate, true);
}
function onTimeUpdate(event)
{
if (event.target.currentTime < 0.2 || !isUpdatePromiseResolved)
return;
test.done();
}
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
waitForEventAndRunStep('playing', video, onPlaying, test);
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.src = '../content/test-encrypted.webm';
video.play();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Playback using Clear Key key system, calling setMediaKeys() before setting src attribute.');
</script>
</body>
</html>

View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Clear Key Play Two Videos At Same Time</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<video id="secondVideo"></video>
<div id="log"></div>
<script>
// As this code doesn't wait for the 'message' event to simplify
// the code, specify the key ID and key used by the encrypted
// content.
var keyId = stringToUint8Array('0123456789012345');
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
promise_test(function(test)
{
var promises = [
play_video_as_promise(document.getElementById('testVideo'), '../content/test-encrypted.webm'),
play_video_as_promise(document.getElementById('secondVideo'), '../content/test-encrypted.webm')
];
return Promise.all(promises);
}, 'Play two videos at the same time.');
function play_video_as_promise(video, content)
{
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
video.src = content;
video.play();
return wait_for_encrypted_message(video);
}).then(function(result) {
return wait_for_timeupdate_message(video);
});
};
function wait_for_encrypted_message(video)
{
var encryptedEventCount = 0;
return new Promise(function(resolve) {
video.addEventListener('encrypted', function listener(e) {
// The same decryption key is used by both the audio
// and the video streams so only create a session once.
// Create the session on the second event. This also
// ensures we see both events.
if (++encryptedEventCount != 2)
return;
video.removeEventListener('encrypted', listener);
var mediaKeySession = video.mediaKeys.createSession();
mediaKeySession.generateRequest(e.initDataType, e.initData).then(function(result) {
// Don't bother waiting for the 'message' event.
// Just call update() since we know the keyId
// needed.
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
return mediaKeySession.update(jwkSet);
}).then(function(result) {
resolve(result);
});
});
});
};
function wait_for_timeupdate_message(video)
{
return new Promise(function(resolve) {
video.addEventListener('timeupdate', function listener(e) {
if (e.target.currentTime < 0.2)
return;
video.removeEventListener('timeupdate', listener);
resolve(e);
});
});
};
</script>
</body>
</html>

View file

@ -0,0 +1,319 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test navigator.requestMediaKeySystemAccess()</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function expect_error(keySystem, configurations, expectedError, testName) {
promise_test(function(test) {
return navigator.requestMediaKeySystemAccess(keySystem, configurations).then(function(a) {
assert_unreached('Unexpected requestMediaKeySystemAccess() success.');
}, function(e) {
assert_equals(e.name, expectedError);
});
}, testName);
}
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, 'getConfiguration()');
});
}, testName);
}
// Tests for keySystem.
expect_error('', [{}], 'InvalidAccessError', 'Empty keySystem');
expect_error('com.example.unsupported', [{}], 'NotSupportedError', 'Unsupported keySystem');
expect_error('org.w3.clearkey.', [{}], 'NotSupportedError', 'keySystem ends with "."');
expect_error('org.w3.ClearKey', [{}], 'NotSupportedError', 'Capitalized keySystem');
expect_error('org.w3.clearke\u028F', [{}], 'NotSupportedError', 'Non-ASCII keySystem');
// Parent of Clear Key not supported.
expect_error('org', [{}], 'NotSupportedError', 'Parent of Clear Key (org)');
expect_error('org.', [{}], 'NotSupportedError', 'Parent of Clear Key (org.)');
expect_error('org.w3', [{}], 'NotSupportedError', 'Parent of Clear Key (org.w3)');
expect_error('org.w3.', [{}], 'NotSupportedError', 'Parent of Clear Key (org.w3.)');
// Child of Clear Key not supported.
expect_error('org.w3.clearkey.foo', [{}], 'NotSupportedError', 'Child of Clear Key');
// Prefixed Clear Key not supported.
expect_error('webkit-org.w3.clearkey', [{}], 'NotSupportedError', 'Prefixed Clear Key');
// Incomplete names.
expect_error('org.w3.learkey', [{}], 'NotSupportedError', 'Incomplete name org.w3.learkey');
expect_error('org.w3.clearke', [{}], 'NotSupportedError', 'Incomplete name org.w3.clearke');
expect_error('or.w3.clearkey', [{}], 'NotSupportedError', 'Incomplete name or.w3.clearkey');
// Spaces in key system name not supported.
expect_error(' org.w3.clearkey', [{}], 'NotSupportedError', 'Leading space in key system name');
expect_error('org.w3. clearkey', [{}], 'NotSupportedError', 'Extra space in key system name');
expect_error('org.w3.clearkey ', [{}], 'NotSupportedError', 'Trailing space in key system name');
// Extra dots in key systems names not supported.
expect_error('.org.w3.clearkey', [{}], 'NotSupportedError', 'Leading dot in key systems name');
expect_error('org.w3.clearkey.', [{}], 'NotSupportedError', 'Trailing dot in key systems name');
expect_error('org.w3..clearkey', [{}], 'NotSupportedError', 'Double dot in key systems name');
expect_error('org.w3.clear.key', [{}], 'NotSupportedError', 'Extra dot in key systems name');
// Key system name is case sensitive.
expect_error('org.w3.Clearkey', [{}], 'NotSupportedError', 'Key system name is case sensitive');
expect_error('Org.w3.clearkey', [{}], 'NotSupportedError', 'Key system name is case sensitive');
// Tests for trivial configurations.
expect_error('org.w3.clearkey', [], 'InvalidAccessError', 'Empty supportedConfigurations');
expect_config('org.w3.clearkey', [{}], {}, 'Empty configuration');
// Various combinations of supportedConfigurations.
// TODO(jrummell): Specifying contentType without codecs is
// deprecated, so this test should fail. http://crbug.com/605661.
expect_config('org.w3.clearkey', [{
initDataTypes: ['webm'],
audioCapabilities: [{contentType: 'audio/webm'}],
videoCapabilities: [{contentType: 'video/webm'}],
}], {
initDataTypes: ['webm'],
audioCapabilities: [{contentType: 'audio/webm'}],
videoCapabilities: [{contentType: 'video/webm'}],
}, 'Basic supported configuration');
// TODO(jrummell): Specifying contentType without codecs is
// deprecated, so this test should fail. http://crbug.com/605661.
expect_config('org.w3.clearkey', [{
initDataTypes: ['fakeidt', 'webm'],
audioCapabilities: [{contentType: 'audio/fake'}, {contentType: 'audio/webm'}],
videoCapabilities: [{contentType: 'video/fake'}, {contentType: 'video/webm'}],
}], {
initDataTypes: ['webm'],
audioCapabilities: [{contentType: 'audio/webm'}],
videoCapabilities: [{contentType: 'video/webm'}],
}, 'Partially supported configuration');
expect_config('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'audio/webm; codecs=vorbis'}],
}], {
audioCapabilities: [{contentType: 'audio/webm; codecs=vorbis'}],
}, 'Supported audio codec');
expect_config('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'audio/webm; codecs="vorbis"'}],
}], {
audioCapabilities: [{contentType: 'audio/webm; codecs="vorbis"'}],
}, 'ContentType formatting must be preserved');
expect_error('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'audio/webm; codecs=fake'}],
}], 'NotSupportedError', 'Unsupported audio codec');
expect_error('org.w3.clearkey', [{
audioCapabilities: [
{contentType: 'audio/webm; codecs=mp4a'},
{contentType: 'audio/webm; codecs=mp4a.40.2'}
],
}], 'NotSupportedError', 'Mismatched audio container/codec');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs=vp8'}],
}], {
videoCapabilities: [{contentType: 'video/webm; codecs=vp8'}],
}, 'Supported video codec');
expect_error('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'video/webm; codecs=vp8'}],
}], 'NotSupportedError', 'Video codec specified in audio field');
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'audio/webm; codecs=vorbis'}],
}], 'NotSupportedError', 'Audio codec specified in video field');
expect_error('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'video/webm; codecs=fake'}],
}], 'NotSupportedError', 'Unsupported video codec');
expect_error('org.w3.clearkey', [{
audioCapabilities: [
{contentType: 'audio/webm; codecs=avc1'},
{contentType: 'audio/webm; codecs=avc1.42e01e'}
],
}], 'NotSupportedError', 'Mismatched video container/codec');
expect_config('org.w3.clearkey', [
{initDataTypes: ['fakeidt']},
{initDataTypes: ['webm']}
], {initDataTypes: ['webm']}, 'Two configurations, one supported');
expect_config('org.w3.clearkey', [
{initDataTypes: ['webm']},
{}
], {initDataTypes: ['webm']}, 'Two configurations, both supported');
// Audio MIME type does not support video codecs.
expect_error('org.w3.clearkey', [{
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.');
// Video MIME type does not support audio codecs.
expect_error('org.w3.clearkey', [{
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 does not support AVC1/AAC.
expect_error('org.w3.clearkey', [{
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.');
expect_error('org.w3.clearkey', [{
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.');
// Extra space is allowed in contentType.
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: ' video/webm; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: ' video/webm; codecs="vp8"'}],
}, 'Leading space in contentType');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm ; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/webm ; codecs="vp8"'}],
}, 'Space before ; in contentType');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/webm; codecs="vp8"'}],
}, 'Extra spaces after ; in contentType');
// TODO(jrummell): contentType should allow white space at the
// end of the string. http://crbug.com/487392
// expect_config('org.w3.clearkey', [{
// videoCapabilities: [{contentType: 'video/webm; codecs="vp8" '}],
// }], {
// videoCapabilities: [{contentType: 'video/webm; codecs="vp8" '}],
// }, 'Trailing space in contentType');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs=" vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/webm; codecs=" vp8"'}],
}, 'Space at start of codecs parameter');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs="vp8 "'}],
}], {
videoCapabilities: [{contentType: 'video/webm; codecs="vp8 "'}],
}, 'Space at end of codecs parameter');
// contentType is not case sensitive (except the codec names).
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'Video/webm; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'Video/webm; codecs="vp8"'}],
}, 'Video/webm');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/Webm; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/Webm; codecs="vp8"'}],
}, 'video/Webm');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; Codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/webm; Codecs="vp8"'}],
}, 'Codecs=');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'VIDEO/WEBM; codecs="vp8"'}],
}], {
videoCapabilities: [{contentType: 'VIDEO/WEBM; codecs="vp8"'}],
}, 'VIDEO/WEBM');
expect_config('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; CODECS="vp8"'}],
}], {
videoCapabilities: [{contentType: 'video/webm; CODECS="vp8"'}],
}, 'CODECS=');
// Unrecognized attributes are not allowed.
// TODO(jrummell): Unrecognized attributes are ignored currently.
// http://crbug.com/449690
// expect_error('org.w3.clearkey', [{
// videoCapabilities: [{contentType: 'video/webm; foo="bar"'}],
// }], 'NotSupportedError', 'Unrecognized foo');
// expect_error('org.w3.clearkey', [{
// videoCapabilities: [{contentType: 'video/webm; foo="bar"; codecs="vp8"'}],
// }], 'NotSupportedError', 'Unrecognized foo with codecs');
// Invalid contentTypes.
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'fake'}],
}], 'NotSupportedError', 'contentType fake');
expect_error('org.w3.clearkey', [{
audioCapabilities: [{contentType: 'audio/fake'}],
}], 'NotSupportedError', 'contentType audio/fake');
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/fake'}],
}], 'NotSupportedError', 'contentType video/fake');
// The actual codec names are case sensitive.
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs="Vp8"'}],
}], 'NotSupportedError', 'codecs Vp8');
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs="VP8"'}],
}], 'NotSupportedError', 'codecs VP8');
// Extra comma is not allowed in codecs.
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs=",vp8"'}],
}], 'NotSupportedError', 'Leading , in codecs');
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs="vp8,"'}],
}], 'NotSupportedError', 'Trailing , in codecs');
expect_error('org.w3.clearkey', [{
videoCapabilities: [{contentType: 'video/webm; codecs=",vp8,"'}],
}], 'NotSupportedError', 'Leading and trailing , in codecs');
</script>
</body>
</html>

View file

@ -0,0 +1,60 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Reset src after setMediaKeys()</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var mediaKeys;
var encryptedEventIndex = 0;
var video = document.getElementById('testVideo');
assert_not_equals(video, null);
var onEncrypted = function(event)
{
++encryptedEventIndex;
assert_not_equals(video.mediaKeys, null);
assert_true(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; set src to a different video.
video.src = '../content/test-encrypted-different-av-keys.webm';
} else if (encryptedEventIndex == 4) {
// Finished second video.
test.done();
}
};
// Create a MediaKeys object and assign it to video.
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}])
.then(function(access) {
assert_equals(access.keySystem, 'org.w3.clearkey');
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
assert_not_equals(mediaKeys, null);
return video.setMediaKeys(mediaKeys);
}).then(function(result) {
assert_not_equals(video.mediaKeys, null, 'not set initially');
assert_true(video.mediaKeys === mediaKeys);
// Set src to a video.
waitForEventAndRunStep('encrypted', video, onEncrypted, test);
video.src = '../content/test-encrypted.webm';
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Reset src after setMediaKeys().');
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test MediaKeySession closed event</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(test)
{
var initDataType;
var initData;
var mediaKeySession;
getSupportedInitDataType().then(function(type) {
initDataType = type;
initData = getInitData(initDataType);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest(initDataType, initData);
}).then(function() {
// Wait for the session to be closed.
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);
test.done();
});
// release() should result in the closed promise being
// fulfilled.
return mediaKeySession.close();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Test MediaKeySession closed event.');
</script>
</body>
</html>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys() again after playback</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
promise_test(function(test)
{
var video = document.getElementById('testVideo');
var keyId = stringToUint8Array('0123456789012345');
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
var content = '../content/test-encrypted.webm';
var duration = 0.2;
return createMediaKeys(keyId, rawKey).then(function(mediaKeys) {
return video.setMediaKeys(mediaKeys);
}).then(function() {
return playVideoAndWaitForTimeupdate(video, content, duration);
}).then(function() {
// Now create a second MediaKeys.
return createMediaKeys(keyId, rawKey);
}).then(function(mediaKeys) {
// video is currently playing, so should not be able to
// change MediaKeys now.
assert_false(video.ended);
return video.setMediaKeys(mediaKeys);
}).then(function() {
assert_unreached('Able to change MediaKeys while playing.');
}, function(error) {
// Error expected.
assert_equals(error.name, 'InvalidStateError');
return Promise.resolve('success');
});
}, 'setMediaKeys() again after playback');
</script>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys() again after resetting src</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
promise_test(function(test)
{
var video = document.getElementById('testVideo');
var keyId = stringToUint8Array('0123456789012345');
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
var content = '../content/test-encrypted.webm';
var duration = 0.2;
return createMediaKeys(keyId, rawKey).then(function(mediaKeys) {
return video.setMediaKeys(mediaKeys);
}).then(function() {
return playVideoAndWaitForTimeupdate(video, content, duration);
}).then(function() {
// Now create a second MediaKeys and repeat.
return createMediaKeys(keyId, rawKey);
}).then(function(mediaKeys) {
// MediaKeys is use by previous video, so clear .src
// so that MediaKeys can be assigned.
video.src = '';
return video.setMediaKeys(mediaKeys);
}).then(function() {
return playVideoAndWaitForTimeupdate(video, content, duration);
});
}, 'setMediaKeys() again after resetting src');
</script>
</body>
</html>

View file

@ -0,0 +1,105 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Set MediaKeys multiple times in parallel</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="video"></video>
<div id="log"></div>
<script>
// Wait for an 'encrypted' event as a promise.
function wait_for_encrypted_event(video)
{
return new Promise(function(resolve) {
video.addEventListener('encrypted', function listener(e) {
video.removeEventListener('encrypted', listener);
resolve();
});
});
};
// Return a promise that calls setMediaKeys() and returns 1 if
// resolved, 0 if rejected. If |must_succeed| is true, then
// setMediaKeys() should not fail.
function setMediaKeys_as_count(video, mediaKeys, must_succeed)
{
return video.setMediaKeys(mediaKeys).then(function() {
return 1;
}, function() {
assert_false(must_succeed);
return 0;
});
};
// Return the sum of the results from |promises|. Each promise
// must return a number.
function count_promise_results(promises)
{
var count = 0;
var result = Promise.resolve(null);
promises.forEach(function(promise) {
result = result.then(function() {
return promise;
}).then(function(i) {
count += i;
});
});
return result.then(function() { return count; });
};
promise_test(function(test)
{
var video = document.getElementById('video');
var access;
var mediaKeys1;
var mediaKeys2;
var mediaKeys3;
var mediaKeys4;
var mediaKeys5;
// Start a video now so that it is waiting for MediaKeys
// in order to continue.
video.src = '../content/test-encrypted.webm';
video.play();
return wait_for_encrypted_event(video).then(function() {
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(result) {
access = result;
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;
// Create 5 calls to setMediaKeys(). The first one must
// succeed, the others are optional.
var p1 = setMediaKeys_as_count(video, mediaKeys1, true);
var p2 = setMediaKeys_as_count(video, mediaKeys2, false);
var p3 = setMediaKeys_as_count(video, mediaKeys3, false);
var p4 = setMediaKeys_as_count(video, mediaKeys4, false);
var p5 = setMediaKeys_as_count(video, mediaKeys5, false);
return count_promise_results([p1, p2, p3, p4, p5]);
}).then(function(count) {
// At least one of the setMediaKeys() calls should have
// succeeded.
assert_greater_than(count, 0);
});
}, 'Set MediaKeys multiple times in parallel.');
</script>
</body>
</html>

View file

@ -0,0 +1,79 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys() multiple times with different MediaKeys.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="video"></video>
<div id="log"></div>
<script>
promise_test(function(test)
{
var video = document.getElementById('video');
var keySystemAccess;
var mediaKeys1;
var mediaKeys2;
assert_equals(video.mediaKeys, null);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
keySystemAccess = access;
// Create a mediaKeys.
return keySystemAccess.createMediaKeys();
}).then(function(result) {
mediaKeys1 = result;
assert_not_equals(mediaKeys1, null);
// Create a second mediaKeys.
return keySystemAccess.createMediaKeys();
}).then(function(result) {
mediaKeys2 = result;
assert_not_equals(mediaKeys2, null);
// Set mediaKeys1 on video.
return video.setMediaKeys(mediaKeys1);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys1);
// Set mediaKeys2 on video (switching MediaKeys).
return video.setMediaKeys(mediaKeys2);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys2);
// Clear mediaKeys from video.
return video.setMediaKeys(null);
}).then(function() {
assert_equals(video.mediaKeys, null);
// Set mediaKeys1 on video again.
return video.setMediaKeys(mediaKeys1);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys1);
// Load the media element to create the WebMediaPlayer.
video.src = '../content/test-encrypted.webm';
// Set mediaKeys2 on video (switching MediaKeys) not
// supported after WebMediaPlayer is created.
return video.setMediaKeys(mediaKeys2);
}).then(function() {
assert_unreached('Switching mediaKeys after setting src should have failed.');
}, function(error) {
assert_true(video.mediaKeys === mediaKeys1);
assert_equals(error.name, 'InvalidStateError');
assert_not_equals(error.message, '');
// Return something so the promise resolves properly.
return Promise.resolve();
}).then(function() {
// Set null mediaKeys on video (clearing MediaKeys) not
// supported after WebMediaPlayer is created.
return video.setMediaKeys(null);
}).then(function() {
assert_unreached('Clearing mediaKeys after setting src should have failed.');
}, function(error) {
assert_true(video.mediaKeys === mediaKeys1);
assert_equals(error.name, 'InvalidStateError');
assert_not_equals(error.message, '');
return Promise.resolve();
});
}, 'setMediaKeys() multiple times with different MediaKeys.');
</script>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys() multiple times with the same MediaKeys.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="video"></video>
<div id="log"></div>
<script>
promise_test(function(test)
{
var video = document.getElementById('video');
var mediaKeys;
assert_equals(video.mediaKeys, null);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
assert_not_equals(mediaKeys, null);
// Set mediaKeys on video should work.
return video.setMediaKeys(mediaKeys);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys);
// Set mediaKeys on video again should return a resolved
// promise.
return video.setMediaKeys(mediaKeys);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys);
// Load the media element to create the WebMediaPlayer.
video.src = '../content/test-encrypted.webm';
// Set mediaKeys again on video should still return a
// resolved promise.
return video.setMediaKeys(mediaKeys);
}).then(function() {
assert_true(video.mediaKeys === mediaKeys);
});
}, 'setMediaKeys() multiple times with the same MediaKeys.');
</script>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys() on multiple video elements.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="video1"></video>
<video id="video2"></video>
<div id="log"></div>
<script>
promise_test(function(test)
{
var video1 = document.getElementById('video1');
var video2 = document.getElementById('video2');
var mediaKeys;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
// Assignment to video1 should work.
return video1.setMediaKeys(mediaKeys);
}).then(function() {
// Assignment to video2 should fail.
return video2.setMediaKeys(mediaKeys);
}).then(function() {
assert_unreached('Second setMediaKeys should have failed.');
}, 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);
});
}, 'setMediaKeys() on multiple video elements.');
</script>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>setMediaKeys</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="video"></video>
<div id="log"></div>
<script>
async_test(function(test)
{
var mediaKeys;
var video = document.getElementById('video');
assert_not_equals(video, null);
// Test MediaKeys assignment.
assert_equals(video.mediaKeys, null);
assert_equals(typeof video.setMediaKeys, 'function');
// Try setting mediaKeys to null.
video.setMediaKeys(null).then(function(result) {
assert_equals(video.mediaKeys, null);
// Try setting mediaKeys to the wrong type of object.
return video.setMediaKeys(new Date());
}).then(function(result) {
assert_unreached('setMediaKeys did not fail when setting to Date()');
}, function(error) {
// TypeError expected.
assert_equals(error.name, 'TypeError');
// Create a MediaKeys object and assign it to video.
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
assert_equals(access.keySystem, 'org.w3.clearkey');
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_true(video.mediaKeys === mediaKeys);
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error);
});
}, 'Setting MediaKeys on a video object.');
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Unique origin is unable to create MediaKeys</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// 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.src = 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 = 'data:text/html,' +
'<script>' +
' window.onmessage = function(e) {' +
' navigator.requestMediaKeySystemAccess(\'org.w3.clearkey\', [{}]).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.
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
// Success, so now create the iframe and try there.
return load_iframe(script, 'allow-scripts')
}).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');
</script>
</body>
</html>

View file

@ -0,0 +1,70 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Test handling of invalid responses for update().</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// This test passes |response| to update() as a JSON Web Key Set.
// CDMs other than Clear Key won't expect |response| in this format.
async_test(function(test)
{
var initDataType;
var mediaKeySession;
function repeat(pattern, count) {
var result = '';
while (count > 1) {
if (count & 1) result += pattern;
count >>= 1;
pattern += pattern;
}
return result + pattern;
}
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 + repeat(',"test":"unknown"', 4000) + '}';
}
function processMessage(event)
{
var jwkSet = createReallyLongJWKSet();
assert_greater_than(jwkSet.length, 65536);
var jwkSetArray = stringToUint8Array(jwkSet);
mediaKeySession.update(jwkSetArray).then(function() {
forceTestFailureFromPromise(test, 'Error: update() succeeded');
}, function(error) {
assert_equals(error.name, 'InvalidAccessError');
test.done();
});
}
getSupportedInitDataType().then(function(type) {
initDataType = type;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]);
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
mediaKeySession = mediaKeys.createSession();
waitForEventAndRunStep('message', mediaKeySession, processMessage, test);
return mediaKeySession.generateRequest(initDataType, getInitData(initDataType));
});
}, 'update() with response longer than 64Kb characters.');
</script>
</body>
</html>

View file

@ -0,0 +1,300 @@
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
var consoleDiv = null;
function consoleWrite(text)
{
if (!consoleDiv && document.body) {
consoleDiv = document.createElement('div');
document.body.appendChild(consoleDiv);
}
var span = document.createElement('span');
span.appendChild(document.createTextNode(text));
span.appendChild(document.createElement('br'));
consoleDiv.appendChild(span);
}
// Returns a promise that is fulfilled with true if |initDataType| is supported,
// or false if not.
function isInitDataTypeSupported(initDataType)
{
return navigator.requestMediaKeySystemAccess(
"org.w3.clearkey", [{ initDataTypes : [initDataType] }])
.then(function() { return(true); }, function() { return(false); });
}
// Returns a promise that is fulfilled with an initDataType that is supported,
// rejected if none are supported.
function getSupportedInitDataType()
{
var configuration = [{ initDataTypes : [ 'webm', 'cenc', 'keyids' ] }];
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', configuration)
.then(function(access) {
var initDataTypes = access.getConfiguration().initDataTypes;
assert_greater_than(initDataTypes.length, 0);
return Promise.resolve(initDataTypes[0]);
}, function(error) {
return Promise.reject('No supported initDataType.');
});
}
function getInitData(initDataType)
{
if (initDataType == 'webm') {
return new Uint8Array([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
]);
}
if (initDataType == 'cenc') {
return new Uint8Array([
0x00, 0x00, 0x00, 0x00, // size = 0
0x70, 0x73, 0x73, 0x68, // 'pssh'
0x01, // version = 1
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, 0x01, // key count
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // key
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x00, 0x00, 0x00, 0x00 // datasize
]);
}
if (initDataType == 'keyids') {
var keyId = new Uint8Array([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
]);
return stringToUint8Array(createKeyIDs(keyId));
}
throw 'initDataType ' + initDataType + ' not supported.';
}
function waitForEventAndRunStep(eventName, element, func, stepTest)
{
var eventCallback = function(event) {
if (func)
func(event);
}
if (stepTest)
eventCallback = stepTest.step_func(eventCallback);
element.addEventListener(eventName, eventCallback, true);
}
// Copied from LayoutTests/resources/js-test.js.
// See it for details of why this is necessary.
function asyncGC(callback)
{
GCController.collectAll();
setTimeout(callback, 0);
}
function createGCPromise()
{
// Run gc() as a promise.
return new Promise(
function(resolve, reject) {
asyncGC(resolve);
});
}
function delayToAllowEventProcessingPromise()
{
return new Promise(
function(resolve, reject) {
setTimeout(resolve, 0);
});
}
function stringToUint8Array(str)
{
var result = new Uint8Array(str.length);
for(var i = 0; i < str.length; i++) {
result[i] = str.charCodeAt(i);
}
return result;
}
function arrayBufferAsString(buffer)
{
// MediaKeySession.keyStatuses iterators return an ArrayBuffer,
// so convert it into a printable string.
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
function dumpKeyStatuses(keyStatuses)
{
consoleWrite("for (var entry of keyStatuses)");
for (var entry of keyStatuses) {
consoleWrite(arrayBufferAsString(entry[0]) + ", " + entry[1]);
}
consoleWrite("for (var key of keyStatuses.keys())");
for (var key of keyStatuses.keys()) {
consoleWrite(arrayBufferAsString(key));
}
consoleWrite("for (var value of keyStatuses.values())");
for (var value of keyStatuses.values()) {
consoleWrite(value);
}
consoleWrite("for (var entry of keyStatuses.entries())");
for (var entry of keyStatuses.entries()) {
consoleWrite(arrayBufferAsString(entry[0]) + ", " + entry[1]);
}
consoleWrite("keyStatuses.forEach()");
keyStatuses.forEach(function(value, key, map) {
consoleWrite(arrayBufferAsString(key) + ", " + value);
});
}
// Verify that |keyStatuses| contains just the keys in |keys.expected|
// and none of the keys in |keys.unexpected|. All keys should have status
// 'usable'. Example call: verifyKeyStatuses(mediaKeySession.keyStatuses,
// { expected: [key1], unexpected: [key2] });
function verifyKeyStatuses(keyStatuses, keys)
{
var expected = keys.expected || [];
var unexpected = keys.unexpected || [];
// |keyStatuses| should have same size as number of |keys.expected|.
assert_equals(keyStatuses.size, expected.length);
// All |keys.expected| should be found.
expected.map(function(key) {
assert_true(keyStatuses.has(key));
assert_equals(keyStatuses.get(key), 'usable');
});
// All |keys.unexpected| should not be found.
unexpected.map(function(key) {
assert_false(keyStatuses.has(key));
assert_equals(keyStatuses.get(key), undefined);
});
}
// Encodes |data| into base64url string. There is no '=' padding, and the
// characters '-' and '_' must be used instead of '+' and '/', respectively.
function base64urlEncode(data)
{
var result = btoa(String.fromCharCode.apply(null, data));
return result.replace(/=+$/g, '').replace(/\+/g, "-").replace(/\//g, "_");
}
// Decode |encoded| using base64url decoding.
function base64urlDecode(encoded)
{
return atob(encoded.replace(/\-/g, "+").replace(/\_/g, "/"));
}
// For Clear Key, the License Format is a JSON Web Key (JWK) Set, which contains
// a set of cryptographic keys represented by JSON. These helper functions help
// wrap raw keys into a JWK set.
// See:
// https://w3c.github.io/encrypted-media/#clear-key-license-format
// http://tools.ietf.org/html/draft-ietf-jose-json-web-key
//
// Creates a JWK from raw key ID and key.
// |keyId| and |key| are expected to be ArrayBufferViews, not base64-encoded.
function createJWK(keyId, key)
{
var jwk = '{"kty":"oct","alg":"A128KW","kid":"';
jwk += base64urlEncode(keyId);
jwk += '","k":"';
jwk += base64urlEncode(key);
jwk += '"}';
return jwk;
}
// Creates a JWK Set from multiple JWKs.
function createJWKSet()
{
var jwkSet = '{"keys":[';
for (var i = 0; i < arguments.length; i++) {
if (i != 0)
jwkSet += ',';
jwkSet += arguments[i];
}
jwkSet += ']}';
return jwkSet;
}
// Clear Key can also support Key IDs Initialization Data.
// ref: http://w3c.github.io/encrypted-media/keyids-format.html
// Each parameter is expected to be a key id in an Uint8Array.
function createKeyIDs()
{
var keyIds = '{"kids":["';
for (var i = 0; i < arguments.length; i++) {
if (i != 0)
keyIds += '","';
keyIds += base64urlEncode(arguments[i]);
}
keyIds += '"]}';
return keyIds;
}
function forceTestFailureFromPromise(test, error, message)
{
// Promises convert exceptions into rejected Promises. Since there is
// currently no way to report a failed test in the test harness, errors
// are reported using force_timeout().
if (message)
consoleWrite(message + ': ' + error.message);
else if (error)
consoleWrite(error);
test.force_timeout();
test.done();
}
function extractSingleKeyIdFromMessage(message)
{
var json = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
// Decode the first element of 'kids'.
assert_equals(1, json.kids.length);
var decoded_key = base64urlDecode(json.kids[0]);
// Convert to an Uint8Array and return it.
return stringToUint8Array(decoded_key);
}
// Create a MediaKeys object for Clear Key with 1 session. KeyId and key
// required for the video are already known and provided. Returns a promise
// that resolves to the MediaKeys object created.
function createMediaKeys(keyId, key)
{
var mediaKeys;
var mediaKeySession;
var request = stringToUint8Array(createKeyIDs(keyId));
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, key)));
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
return access.createMediaKeys();
}).then(function(result) {
mediaKeys = result;
mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest('keyids', request);
}).then(function() {
return mediaKeySession.update(jwkSet);
}).then(function() {
return Promise.resolve(mediaKeys);
});
}
// Play the specified |content| on |video|. Returns a promise that is resolved
// after the video plays for |duration| seconds.
function playVideoAndWaitForTimeupdate(video, content, duration)
{
video.src = content;
video.play();
return new Promise(function(resolve) {
video.addEventListener('timeupdate', function listener(event) {
if (event.target.currentTime < duration)
return;
video.removeEventListener('timeupdate', listener);
resolve('success');
});
});
}

View file

@ -0,0 +1,164 @@
<!DOCTYPE html>
<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
<html>
<head>
<title>Waiting for a key.</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<video id="testVideo"></video>
<div id="log"></div>
<script>
// For debugging timeouts, keep track of the number of the
// various events received.
var debugEncryptedEventCount = 0;
var debugWaitingForKeyEventCount = 0;
var debugTimeUpdateEventCount = 0;
var debugMessage = '';
promise_test(function(test)
{
var video = document.getElementById('testVideo');
var initData;
var initDataType;
var mediaKeySession;
test.timeout = function()
{
var message = 'timeout. message = ' + debugMessage
+ ', encrypted: ' + debugEncryptedEventCount
+ ', waitingforkey: ' + debugWaitingForKeyEventCount
+ ', timeupdate: ' + debugTimeUpdateEventCount;
test.force_timeout();
test.timeout_id = null;
test.set_status(2, message);
test.done();
};
// As this code doesn't wait for the 'message' event to avoid
// race conditions with 'waitingforkey', specify the key ID and
// key used by the encrypted content.
var keyId = stringToUint8Array('0123456789012345');
var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
debugMessage = 'createMediaKeys()';
return access.createMediaKeys();
}).then(function(mediaKeys) {
debugMessage = 'setMediaKeys()';
return video.setMediaKeys(mediaKeys);
}).then(function() {
video.src = '../content/test-encrypted.webm';
video.play();
debugMessage = 'wait_for_encrypted_event()';
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.
initData = e.initData;
initDataType = e.initDataType;
// 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_equals(video.currentTime, 0);
// Create a session.
mediaKeySession = video.mediaKeys.createSession();
debugMessage = 'generateRequest()';
return mediaKeySession.generateRequest(initDataType, initData);
}).then(function() {
// generateRequest() will cause a 'message' event to
// occur specifying the keyId that is needed, but we
// ignore it since we already know what keyId is needed.
// Add the key needed to decrypt.
var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
debugMessage = 'update()';
return mediaKeySession.update(jwkSet);
}).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);
});
// Typical test duration is 6 seconds on release builds
// (12 seconds on debug). Since the test is timing out anyway,
// make the duration 5 seconds so that the timeout function
// is actually called (instead of simply aborting the test).
}, 'Waiting for a key.', { timeout: 5000 });
// Wait for a pair of 'encrypted' events. Promise resolved on
// second event.
function wait_for_encrypted_event(video)
{
var encryptedEventCount = 0;
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');
// The same decryption key is used by both the audio
// and the video streams so wait for the second event
// to ensure we see both events.
++debugEncryptedEventCount;
if (++encryptedEventCount != 2)
return;
video.removeEventListener('encrypted', listener);
resolve(e);
});
});
};
// Wait for a 'waitingforkey' event. Promise resolved when the
// event is received.
function wait_for_waitingforkey_event(video)
{
var waitingForKeyEventCount = 0;
return new Promise(function(resolve) {
video.addEventListener('waitingforkey', function listener(e) {
assert_equals(e.target, video);
assert_equals(e.type, 'waitingforkey');
++debugWaitingForKeyEventCount;
++waitingForKeyEventCount;
// TODO(jrummell): waitingforkey event should only
// occur once. http://crbug.com/461903
// assert_equals(waitingForKeyEventCount, 1, 'Multiple waitingforkey events');
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);
});
});
};
</script>
</body>
</html>

View file

@ -0,0 +1 @@
@ddorwin