OLD | NEW |
(Empty) | |
| 1 function testnamePrefix( qualifier, keysystem ) { |
| 2 return ( qualifier || '' ) + ( keysystem === 'org.w3.clearkey' ? keysystem :
'drm' ); |
| 3 } |
| 4 |
| 5 function getInitData(initDataType) { |
| 6 |
| 7 // FIXME: This is messed up, because here we are hard coding the key ids for
the different content |
| 8 // that we use for clearkey testing: webm and mp4. For keyids we retu
rn the mp4 one |
| 9 // |
| 10 // The content used with the DRM today servers has a different key id
altogether |
| 11 |
| 12 if (initDataType == 'webm') { |
| 13 return new Uint8Array([ |
| 14 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 15 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F |
| 16 ]); |
| 17 } |
| 18 |
| 19 if (initDataType == 'cenc') { |
| 20 return new Uint8Array([ |
| 21 0x00, 0x00, 0x00, 0x34, // size |
| 22 0x70, 0x73, 0x73, 0x68, // 'pssh' |
| 23 0x01, // version = 1 |
| 24 0x00, 0x00, 0x00, // flags |
| 25 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID |
| 26 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B, |
| 27 0x00, 0x00, 0x00, 0x01, // key count |
| 28 0x00, 0x00, 0x00, 0x00, 0x03, 0xd2, 0xfc, 0x41, // key id |
| 29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 30 0x00, 0x00, 0x00, 0x00 // datasize |
| 31 ]); |
| 32 } |
| 33 if (initDataType == 'keyids') { |
| 34 var keyId = new Uint8Array([ |
| 35 0x00, 0x00, 0x00, 0x00, 0x03, 0xd2, 0xfc, 0x41, |
| 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 37 ]); |
| 38 return stringToUint8Array(createKeyIDs(keyId)); |
| 39 } |
| 40 throw 'initDataType ' + initDataType + ' not supported.'; |
| 41 } |
| 42 |
| 43 function stringToUint8Array(str) |
| 44 { |
| 45 var result = new Uint8Array(str.length); |
| 46 for(var i = 0; i < str.length; i++) { |
| 47 result[i] = str.charCodeAt(i); |
| 48 } |
| 49 return result; |
| 50 } |
| 51 // Encodes |data| into base64url string. There is no '=' padding, and the |
| 52 // characters '-' and '_' must be used instead of '+' and '/', respectively. |
| 53 function base64urlEncode(data) { |
| 54 var result = btoa(String.fromCharCode.apply(null, data)); |
| 55 return result.replace(/=+$/g, '').replace(/\+/g, "-").replace(/\//g, "_"); |
| 56 } |
| 57 // Decode |encoded| using base64url decoding. |
| 58 function base64urlDecode(encoded) { |
| 59 return atob(encoded.replace(/\-/g, "+").replace(/\_/g, "/")); |
| 60 } |
| 61 // Decode |encoded| using base64 to a Uint8Array |
| 62 function base64DecodeToUnit8Array(encoded) { |
| 63 return new Uint8Array( atob( encoded ).split('').map( function(c){return c.c
harCodeAt(0);} ) ); |
| 64 } |
| 65 // Clear Key can also support Key IDs Initialization Data. |
| 66 // ref: http://w3c.github.io/encrypted-media/keyids-format.html |
| 67 // Each parameter is expected to be a key id in an Uint8Array. |
| 68 function createKeyIDs() { |
| 69 var keyIds = '{"kids":["'; |
| 70 for (var i = 0; i < arguments.length; i++) { |
| 71 if (i != 0) keyIds += '","'; |
| 72 keyIds += base64urlEncode(arguments[i]); |
| 73 } |
| 74 keyIds += '"]}'; |
| 75 return keyIds; |
| 76 } |
| 77 |
| 78 function getSupportedKeySystem() { |
| 79 var userAgent = navigator.userAgent.toLowerCase(); |
| 80 var keysystem = undefined; |
| 81 if (userAgent.indexOf('edge') > -1 ) { |
| 82 keysystem = 'com.microsoft.playready'; |
| 83 } else if ( userAgent.indexOf('chrome') > -1 || userAgent.indexOf('firefox')
> -1 ) { |
| 84 keysystem = 'com.widevine.alpha'; |
| 85 } |
| 86 return keysystem; |
| 87 } |
| 88 |
| 89 function waitForEventAndRunStep(eventName, element, func, stepTest) |
| 90 { |
| 91 var eventCallback = function(event) { |
| 92 if (func) |
| 93 func(event); |
| 94 } |
| 95 |
| 96 element.addEventListener(eventName, stepTest.step_func(eventCallback), true)
; |
| 97 } |
| 98 |
| 99 function waitForEvent(eventName, element) { |
| 100 return new Promise(function(resolve) { |
| 101 element.addEventListener(eventName, resolve, true); |
| 102 }) |
| 103 } |
| 104 |
| 105 var consoleDiv = null; |
| 106 |
| 107 function consoleWrite(text) |
| 108 { |
| 109 if (!consoleDiv && document.body) { |
| 110 consoleDiv = document.createElement('div'); |
| 111 document.body.appendChild(consoleDiv); |
| 112 } |
| 113 var span = document.createElement('span'); |
| 114 span.appendChild(document.createTextNode(text)); |
| 115 span.appendChild(document.createElement('br')); |
| 116 consoleDiv.appendChild(span); |
| 117 } |
| 118 |
| 119 function forceTestFailureFromPromise(test, error, message) |
| 120 { |
| 121 test.step_func(assert_unreached)(message ? message + ': ' + error.message :
error); |
| 122 } |
| 123 |
| 124 // Returns an array of audioCapabilities that includes entries for a set of |
| 125 // codecs that should cover all user agents. |
| 126 function getPossibleAudioCapabilities() |
| 127 { |
| 128 return [ |
| 129 { contentType: 'audio/mp4; codecs="mp4a.40.2"' }, |
| 130 { contentType: 'audio/webm; codecs="opus"' }, |
| 131 ]; |
| 132 } |
| 133 |
| 134 // Returns a trivial MediaKeySystemConfiguration that should be accepted, |
| 135 // possibly as a subset of the specified capabilities, by all user agents. |
| 136 function getSimpleConfiguration() |
| 137 { |
| 138 return [ { |
| 139 initDataTypes : [ 'webm', 'cenc', 'keyids' ], |
| 140 audioCapabilities: getPossibleAudioCapabilities() |
| 141 } ]; |
| 142 } |
| 143 |
| 144 // Returns a MediaKeySystemConfiguration for |initDataType| that should be |
| 145 // accepted, possibly as a subset of the specified capabilities, by all |
| 146 // user agents. |
| 147 function getSimpleConfigurationForInitDataType(initDataType) |
| 148 { |
| 149 return [ { |
| 150 initDataTypes: [ initDataType ], |
| 151 audioCapabilities: getPossibleAudioCapabilities() |
| 152 } ]; |
| 153 } |
| 154 |
| 155 // Returns a promise that is fulfilled with true if |initDataType| is supported, |
| 156 // by keysystem or false if not. |
| 157 function isInitDataTypeSupported(keysystem,initDataType) |
| 158 { |
| 159 return navigator.requestMediaKeySystemAccess( |
| 160 keysystem, getSimpleConfigurationForInitDataType(initDat
aType)) |
| 161 .then(function() { return true; }, function() { return false; }); |
| 162 } |
| 163 |
| 164 function getSupportedInitDataTypes( keysystem ) |
| 165 { |
| 166 return [ 'cenc', 'keyids', 'webm' ].filter( isInitDataTypeSupported.bind( nu
ll, keysystem ) ); |
| 167 } |
| 168 |
| 169 function arrayBufferAsString(buffer) |
| 170 { |
| 171 var array = []; |
| 172 Array.prototype.push.apply( array, new Uint8Array( buffer ) ); |
| 173 return '0x' + array.map( function( x ) { return x < 16 ? '0'+x.toString(16)
: x.toString(16); } ).join(''); |
| 174 } |
| 175 |
| 176 function dumpKeyStatuses(keyStatuses) |
| 177 { |
| 178 var userAgent = navigator.userAgent.toLowerCase(); |
| 179 if (userAgent.indexOf('edge') === -1) { |
| 180 consoleWrite("for (var entry of keyStatuses)"); |
| 181 for (var entry of keyStatuses) { |
| 182 consoleWrite(arrayBufferAsString(entry[0]) + ": " + entry[1]); |
| 183 } |
| 184 consoleWrite("for (var keyId of keyStatuses.keys())"); |
| 185 for (var keyId of keyStatuses.keys()) { |
| 186 consoleWrite(arrayBufferAsString(keyId)); |
| 187 } |
| 188 consoleWrite("for (var status of keyStatuses.values())"); |
| 189 for (var status of keyStatuses.values()) { |
| 190 consoleWrite(status); |
| 191 } |
| 192 consoleWrite("for (var entry of keyStatuses.entries())"); |
| 193 for (var entry of keyStatuses.entries()) { |
| 194 consoleWrite(arrayBufferAsString(entry[0]) + ": " + entry[1]); |
| 195 } |
| 196 consoleWrite("keyStatuses.forEach()"); |
| 197 keyStatuses.forEach(function(status, keyId) { |
| 198 consoleWrite(arrayBufferAsString(keyId) + ": " + status); |
| 199 }); |
| 200 } else { |
| 201 consoleWrite("keyStatuses.forEach()"); |
| 202 keyStatuses.forEach(function(keyId, status) { |
| 203 consoleWrite(arrayBufferAsString(keyId) + ": " + status); |
| 204 }); |
| 205 } |
| 206 } |
| 207 |
| 208 // Verify that |keyStatuses| contains just the keys in |keys.expected| |
| 209 // and none of the keys in |keys.unexpected|. All keys should have status |
| 210 // 'usable'. Example call: verifyKeyStatuses(mediaKeySession.keyStatuses, |
| 211 // { expected: [key1], unexpected: [key2] }); |
| 212 function verifyKeyStatuses(keyStatuses, keys) |
| 213 { |
| 214 var expected = keys.expected || []; |
| 215 var unexpected = keys.unexpected || []; |
| 216 |
| 217 // |keyStatuses| should have same size as number of |keys.expected|. |
| 218 assert_equals(keyStatuses.size, expected.length, "keystatuses should have ex
pected size"); |
| 219 |
| 220 // All |keys.expected| should be found. |
| 221 expected.map(function(key) { |
| 222 assert_true(keyStatuses.has(key), "keystatuses should have the expected
keys"); |
| 223 assert_equals(keyStatuses.get(key), 'usable', "keystatus value should be
'usable'"); |
| 224 }); |
| 225 |
| 226 // All |keys.unexpected| should not be found. |
| 227 unexpected.map(function(key) { |
| 228 assert_false(keyStatuses.has(key), "keystatuses should not have unexpect
ed keys"); |
| 229 assert_equals(keyStatuses.get(key), undefined, "keystatus for unexpected
key should be undefined"); |
| 230 }); |
| 231 } |
| 232 |
| 233 // This function checks that calling |testCase.func| returns a |
| 234 // rejected Promise with the error.name equal to |
| 235 // |testCase.exception|. |
| 236 function test_exception(testCase /*...*/) { |
| 237 var func = testCase.func; |
| 238 var exception = testCase.exception; |
| 239 var args = Array.prototype.slice.call(arguments, 1); |
| 240 |
| 241 // Currently blink throws for TypeErrors rather than returning |
| 242 // a rejected promise (http://crbug.com/359386). |
| 243 // FIXME: Remove try/catch once they become failed promises. |
| 244 try { |
| 245 return func.apply(null, args).then( |
| 246 function (result) { |
| 247 assert_unreached(format_value(func)); |
| 248 }, |
| 249 function (error) { |
| 250 assert_equals(error.name, exception, format_value(func)); |
| 251 assert_not_equals(error.message, "", format_value(func)); |
| 252 } |
| 253 ); |
| 254 } catch (e) { |
| 255 // Only allow 'TypeError' exceptions to be thrown. |
| 256 // Everything else should be a failed promise. |
| 257 assert_equals('TypeError', exception, format_value(func)); |
| 258 assert_equals(e.name, exception, format_value(func)); |
| 259 } |
| 260 } |
| 261 |
| 262 // Check that the events sequence (array of strings) matches the pattern (array
of either strings, or |
| 263 // arrays of strings, with the latter representing a possibly repeating sub-sequ
ence) |
| 264 function checkEventSequence(events,pattern) { |
| 265 function th(i) { return i + (i < 4 ? ["th", "st", "nd", "rd"][i] : "th"); } |
| 266 var i = 0, j=0, k=0; |
| 267 while(i < events.length && j < pattern.length) { |
| 268 if (!Array.isArray(pattern[j])) { |
| 269 assert_equals(events[i], pattern[j], "Expected " + th(i+1) + " event
to be '" + pattern[j] + "'"); |
| 270 ++i; |
| 271 ++j; |
| 272 } else { |
| 273 assert_equals(events[i], pattern[j][k], "Expected " + th(i+1) + " ev
ent to be '" + pattern[j][k] + "'"); |
| 274 ++i; |
| 275 k = (k+1)%pattern[j].length; |
| 276 if (k === 0 && events[i] !== pattern[j][0]) { |
| 277 ++j; |
| 278 } |
| 279 } |
| 280 } |
| 281 assert_equals(i,events.length,"Received more events than expected"); |
| 282 assert_equals(j,pattern.length,"Expected more events than received"); |
| 283 } |
| 284 |
| 285 |
OLD | NEW |