Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: chrome/test/data/media/encrypted_media_utils.js

Issue 182113005: Update EME browser tests to include EME WD (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 var keySystem = QueryString.keySystem; 5 var keySystem = QueryString.keySystem;
6 var mediaFile = QueryString.mediaFile; 6 var mediaFile = QueryString.mediaFile;
7 var mediaType = QueryString.mediaType || 'video/webm; codecs="vorbis, vp8"'; 7 var mediaType = QueryString.mediaType || 'video/webm; codecs="vorbis, vp8"';
8 var useMSE = QueryString.useMSE == 1; 8 var useMSE = QueryString.useMSE == 1;
9 var usePrefixedEME = QueryString.usePrefixedEME == 1;
9 var forceInvalidResponse = QueryString.forceInvalidResponse == 1; 10 var forceInvalidResponse = QueryString.forceInvalidResponse == 1;
10 var sessionToLoad = QueryString.sessionToLoad; 11 var sessionToLoad = QueryString.sessionToLoad;
11 var licenseServerURL = QueryString.licenseServerURL; 12 var licenseServerURL = QueryString.licenseServerURL;
12 // Number of possible retries used to get a license from license server. 13 // Number of possible retries used to get a license from license server.
13 // This is used to avoid server boot up delays since there is no direct way 14 // This is used to avoid server boot up delays since there is no direct way
14 // to know if it is ready crbug.com/339289. 15 // to know if it is ready crbug.com/339289.
15 var requestLicenseTries = 3; 16 var requestLicenseTries = 3;
16 // Delay in ms between retries to get a license from license server. 17 // Delay in ms between retries to get a license from license server.
17 var licenseRequestRetryDelayMs = 3000; 18 var licenseRequestRetryDelayMs = 3000;
18 19
(...skipping 23 matching lines...) Expand all
42 43
43 function hasPrefix(msg, prefix) { 44 function hasPrefix(msg, prefix) {
44 if (msg.length < prefix.length) 45 if (msg.length < prefix.length)
45 return false; 46 return false;
46 for (var i = 0; i < prefix.length; ++i) { 47 for (var i = 0; i < prefix.length; ++i) {
47 if (String.fromCharCode(msg[i]) != prefix[i]) 48 if (String.fromCharCode(msg[i]) != prefix[i])
48 return false; 49 return false;
49 } 50 }
50 return true; 51 return true;
51 } 52 }
52 53
ddorwin 2014/03/04 21:18:48 Can we say that these are copied from the layout t
jrummell 2014/03/04 23:55:49 They are. Updated.
54 // Encodes data into base64 string without trailing '='.
ddorwin 2014/03/04 21:18:48 What you really want is a base64url encoding (thou
jrummell 2014/03/04 23:55:49 Done.
55 function base64Encode(data)
ddorwin 2014/03/04 21:18:48 |dataString|?
jrummell 2014/03/04 23:55:49 This is a Uint8Array, not a string. Updated commen
56 {
57 var result = btoa(String.fromCharCode.apply(null, data));
ddorwin 2014/03/04 21:18:48 What is the apply() call doing/solving?
jrummell 2014/03/04 23:55:49 It appears to be converting the Uint8Array to a st
58 return result.replace(/=+$/g, '');
59 }
60
61 // Creates a JWK from raw key ID and key.
62 function createJWK(keyId, key)
63 {
64 var jwk = "{\"kty\":\"oct\",\"kid\":\"";
65 jwk += base64Encode(keyId);
66 jwk += "\",\"k\":\"";
67 jwk += base64Encode(key);
68 jwk += "\"}";
69 return jwk;
70 }
71
72 // Creates a JWK Set from multiple JWKs.
ddorwin 2014/03/04 21:18:48 ... from an array of JWK(s).
jrummell 2014/03/04 23:55:49 Done.
73 function createJWKSet()
74 {
75 var jwkSet = "{\"keys\":[";
76 for (var i = 0; i < arguments.length; i++) {
77 if (i != 0)
78 jwkSet += ",";
79 jwkSet += arguments[i];
80 }
81 jwkSet += "]}";
82 return jwkSet;
83 }
84
53 function isHeartbeatMessage(msg) { 85 function isHeartbeatMessage(msg) {
54 return hasPrefix(msg, HEART_BEAT_HEADER); 86 return hasPrefix(msg, HEART_BEAT_HEADER);
55 } 87 }
56 88
57 function isFileIOTestMessage(msg) { 89 function isFileIOTestMessage(msg) {
58 return hasPrefix(msg, FILE_IO_TEST_RESULT_HEADER); 90 return hasPrefix(msg, FILE_IO_TEST_RESULT_HEADER);
59 } 91 }
60 92
61 function loadEncryptedMediaFromURL(video) { 93 function loadEncryptedMediaFromURL(video) {
62 return loadEncryptedMedia(video, mediaFile, keySystem, KEY, useMSE); 94 return loadEncryptedMedia(video, mediaFile, keySystem, KEY, useMSE,
95 usePrefixedEME);
63 } 96 }
64 97
65 function loadEncryptedMedia(video, mediaFile, keySystem, key, useMSE, 98 function loadEncryptedMedia(video, mediaFile, keySystem, key, useMSE,
66 appendSourceCallbackFn) { 99 usePrefixedEME, appendSourceCallbackFn) {
67 var keyRequested = false; 100 var keyRequested = false;
68 var sourceOpened = false; 101 var sourceOpened = false;
102 var mediaKeys;
103 var mediaKeySession;
69 // Add properties to enable verification that events occurred. 104 // Add properties to enable verification that events occurred.
70 video.receivedKeyAdded = false; 105 video.receivedKeyAdded = false;
71 video.receivedHeartbeat = false; 106 video.receivedHeartbeat = false;
72 video.isHeartbeatExpected = keySystem === EXTERNAL_CLEAR_KEY_KEY_SYSTEM; 107 video.isHeartbeatExpected = keySystem === EXTERNAL_CLEAR_KEY_KEY_SYSTEM;
73 video.receivedKeyMessage = false; 108 video.receivedKeyMessage = false;
74 109
75 if (!(video && mediaFile && keySystem && key)) { 110 if (!(video && mediaFile && keySystem && key)) {
76 failTest('Missing parameters in loadEncryptedMedia().'); 111 failTest('Missing parameters in loadEncryptedMedia().');
77 return; 112 return;
78 } 113 }
79 114
115 // Shared by prefixed EME and EME WD
ddorwin 2014/03/04 21:18:48 ditto on "WD" in this file.
jrummell 2014/03/04 23:55:49 Done.
80 function onNeedKey(e) { 116 function onNeedKey(e) {
81 if (keyRequested) 117 if (keyRequested)
82 return; 118 return;
83 keyRequested = true; 119 keyRequested = true;
84 console.log('onNeedKey', e); 120 console.log('onNeedKey', e);
85 121
86 var initData = sessionToLoad ? stringToUint8Array( 122 var initData = sessionToLoad ? stringToUint8Array(
87 PREFIXED_API_LOAD_SESSION_HEADER + sessionToLoad) : e.initData; 123 PREFIXED_API_LOAD_SESSION_HEADER + sessionToLoad) : e.initData;
88 try { 124 try {
89 video.webkitGenerateKeyRequest(keySystem, initData); 125 if (usePrefixedEME) {
126 video.webkitGenerateKeyRequest(keySystem, initData);
127 } else {
128 mediaKeySession = mediaKeys.createSession(e.contentType, initData);
129 mediaKeySession.addEventListener('message', onMessage);
130 mediaKeySession.addEventListener('error', function() {
131 setResultInTitle("KeyError");
132 });
133 mediaKeySession.addEventListener('ready', onReady);
134 }
90 } 135 }
91 catch(error) { 136 catch(error) {
92 setResultInTitle(error.name); 137 setResultInTitle(error.name);
93 } 138 }
94 } 139 }
95 140
141 // Prefixed EME callbacks
96 function onKeyAdded(e) { 142 function onKeyAdded(e) {
97 e.target.receivedKeyAdded = true; 143 e.target.receivedKeyAdded = true;
98 } 144 }
99 145
100 function onKeyMessage(message) { 146 function onKeyMessage(message) {
101 video.receivedKeyMessage = true; 147 video.receivedKeyMessage = true;
102 if (!message.keySystem || message.keySystem != keySystem) { 148 if (!message.keySystem || message.keySystem != keySystem) {
103 failTest('Message with unexpected keySystem: ' + message.keySystem); 149 failTest('Message with unexpected keySystem: ' + message.keySystem);
104 return; 150 return;
105 } 151 }
106 152
107 if (!message.sessionId) { 153 if (!message.sessionId) {
108 failTest('Message without a sessionId: ' + message.sessionId); 154 failTest('Message without a sessionId: ' + message.sessionId);
109 return; 155 return;
110 } 156 }
111 157
112 if (!message.message) { 158 if (!message.message) {
113 failTest('Message without a message content: ' + message.message); 159 failTest('Message without a message content: ' + message.message);
114 return; 160 return;
115 } 161 }
116 162
117 if (isHeartbeatMessage(message.message)) { 163 if (isHeartbeatMessage(message.message)) {
118 console.log('onKeyMessage - heartbeat', message); 164 console.log('onKeyMessage - heartbeat', message);
119 message.target.receivedHeartbeat = true; 165 message.target.receivedHeartbeat = true;
120 verifyHeartbeatMessage(message); 166 verifyHeartbeatMessage(message.keySystem, message.defaultURL);
121 return; 167 return;
122 } 168 }
123 169
124 if (isFileIOTestMessage(message.message)) { 170 if (isFileIOTestMessage(message.message)) {
125 var success = getFileIOTestResult(message); 171 var success = getFileIOTestResult(message.keySystem, message);
126 console.log('onKeyMessage - CDM file IO test: ' + 172 console.log('onKeyMessage - CDM file IO test: ' +
127 (success ? 'Success' : 'Fail')); 173 (success ? 'Success' : 'Fail'));
128 if (success) 174 if (success)
129 setResultInTitle("FILEIOTESTSUCCESS"); 175 setResultInTitle("FILEIOTESTSUCCESS");
130 else 176 else
131 setResultInTitle("FAILED"); 177 setResultInTitle("FAILED");
132 return; 178 return;
133 } 179 }
134 180
135 // For FileIOTest key system, no need to start playback. 181 // For FileIOTest key system, no need to start playback.
(...skipping 22 matching lines...) Expand all
158 requestLicense(message); 204 requestLicense(message);
159 return; 205 return;
160 } 206 }
161 console.log('Respond to onKeyMessage with test key.'); 207 console.log('Respond to onKeyMessage with test key.');
162 var initData = message.message; 208 var initData = message.message;
163 if (mediaType.indexOf('mp4') != -1) 209 if (mediaType.indexOf('mp4') != -1)
164 initData = KEY_ID; // Temporary hack for Clear Key in v0.1. 210 initData = KEY_ID; // Temporary hack for Clear Key in v0.1.
165 video.webkitAddKey(keySystem, key, initData); 211 video.webkitAddKey(keySystem, key, initData);
166 } 212 }
167 213
168 function verifyHeartbeatMessage(message) { 214 // EME WD callbacks
215 function onReady(e) {
216 video.receivedKeyAdded = true;
ddorwin 2014/03/04 21:18:48 Note: This will break when we remove ready. Maybe
jrummell 2014/03/04 23:55:49 encrypted_media_player.html checks for the flag be
217 }
218
219 function onMessage(message) {
ddorwin 2014/03/04 21:18:48 This function has a lot of duplicate code. How muc
jrummell 2014/03/04 23:55:49 Also keySystem, update()/webKitAddkey(), using vid
220 video.receivedKeyMessage = true;
221
222 if (!message.message) {
223 failTest('Message without a message content: ' + message.message);
224 return;
225 }
226
227 if (isHeartbeatMessage(message.message)) {
228 console.log('onMessage - heartbeat', message);
229 video.receivedHeartbeat = true;
230 verifyHeartbeatMessage(keySystem, message.destinationURL);
231 return;
232 }
233
234 if (isFileIOTestMessage(message.message)) {
235 var success = getFileIOTestResult(keySystem, message);
236 console.log('onMessage - CDM file IO test: ' +
237 (success ? 'Success' : 'Fail'));
238 if (success)
239 setResultInTitle("FILEIOTESTSUCCESS");
240 else
241 setResultInTitle("FAILED");
242 return;
243 }
244
245 // For FileIOTest key system, no need to start playback.
246 if (mediaKeySession.keySystem == EXTERNAL_CLEAR_KEY_FILE_IO_TEST_KEY_SYSTEM)
247 return;
248
249 // No tested key system returns destinationURL in for key request messages.
250 if (message.destinationURL) {
251 failTest('Message unexpectedly has destinationURL: ' +
252 message.destinationURL);
253 return;
254 }
255
256 // When loading a session, no need to call update().
257 if (sessionToLoad)
258 return;
259
260 console.log('onMessage - key request', message);
261 if (forceInvalidResponse) {
262 console.log('Forcing an invalid onMessage response.');
263 var invalidData = new Uint8Array([0xAA]);
264 var jwkSet = stringToUint8Array(
265 createJWKSet(createJWK(invalidData, invalidData)));
266 mediaKeySession.update(jwkSet);
267 return;
268 }
269 // Check if should send request to locally running license server.
270 if (licenseServerURL) {
271 requestLicense(message);
272 return;
273 }
274 console.log('Respond to onMessage with test key.');
275 var initData = message.message;
276 if (mediaType.indexOf('mp4') != -1)
277 initData = KEY_ID; // Temporary hack for Clear Key in v0.1.
278 var jwkSet = stringToUint8Array(createJWKSet(createJWK(initData, key)));
279 mediaKeySession.update(jwkSet);
280 }
281
ddorwin 2014/03/04 21:18:48 I skipped to here.
282 function verifyHeartbeatMessage(keySystem, url) {
169 String.prototype.startsWith = function(prefix) { 283 String.prototype.startsWith = function(prefix) {
170 return this.indexOf(prefix) === 0; 284 return this.indexOf(prefix) === 0;
171 } 285 }
172 286
173 function isExternalClearKey(keySystem) { 287 function isExternalClearKey(keySystem) {
174 return keySystem == EXTERNAL_CLEAR_KEY_KEY_SYSTEM || 288 return keySystem == EXTERNAL_CLEAR_KEY_KEY_SYSTEM ||
175 keySystem.startsWith(EXTERNAL_CLEAR_KEY_KEY_SYSTEM + '.'); 289 keySystem.startsWith(EXTERNAL_CLEAR_KEY_KEY_SYSTEM + '.');
176 } 290 }
177 291
178 // Only External Clear Key sends a HEARTBEAT message. 292 // Only External Clear Key sends a HEARTBEAT message.
179 if (!isExternalClearKey(message.keySystem)) { 293 if (!isExternalClearKey(keySystem)) {
180 failTest('Unexpected heartbeat from ' + message.keySystem); 294 failTest('Unexpected heartbeat from ' + keySystem);
181 return; 295 return;
182 } 296 }
183 297
184 if (message.defaultURL != EXTERNAL_CLEAR_KEY_HEARTBEAT_URL) { 298 if (url != EXTERNAL_CLEAR_KEY_HEARTBEAT_URL) {
185 failTest('Heartbeat message with unexpected defaultURL: ' + 299 failTest('Heartbeat message with unexpected URL: ' + url);
186 message.defaultURL);
187 return; 300 return;
188 } 301 }
189 } 302 }
190 303
191 function getFileIOTestResult(e) { 304 function getFileIOTestResult(keySystem, e) {
192 // Only External Clear Key sends a FILEIOTESTRESULT message. 305 // Only External Clear Key sends a FILEIOTESTRESULT message.
193 if (e.keySystem != EXTERNAL_CLEAR_KEY_FILE_IO_TEST_KEY_SYSTEM) { 306 if (keySystem != EXTERNAL_CLEAR_KEY_FILE_IO_TEST_KEY_SYSTEM) {
194 failTest('Unexpected CDM file IO test result from ' + e.keySystem); 307 failTest('Unexpected CDM file IO test result from ' + keySystem);
195 return false; 308 return false;
196 } 309 }
197 310
198 // The test result is either '0' or '1' appended to the header. 311 // The test result is either '0' or '1' appended to the header.
199 if (e.message.length != FILE_IO_TEST_RESULT_HEADER.length + 1) 312 if (e.message.length != FILE_IO_TEST_RESULT_HEADER.length + 1)
200 return false; 313 return false;
201 314
202 var result_index = FILE_IO_TEST_RESULT_HEADER.length; 315 var result_index = FILE_IO_TEST_RESULT_HEADER.length;
203 return String.fromCharCode(e.message[result_index]) == 1; 316 return String.fromCharCode(e.message[result_index]) == 1;
204 } 317 }
205 318
206 video.addEventListener('webkitneedkey', onNeedKey); 319 if (usePrefixedEME) {
207 video.addEventListener('webkitkeymessage', onKeyMessage); 320 video.addEventListener('webkitneedkey', onNeedKey);
208 video.addEventListener('webkitkeyerror', function() { 321 video.addEventListener('webkitkeymessage', onKeyMessage);
209 setResultInTitle("KeyError"); 322 video.addEventListener('webkitkeyerror', function() {
210 }); 323 setResultInTitle("KeyError");
211 video.addEventListener('webkitkeyadded', onKeyAdded); 324 });
325 video.addEventListener('webkitkeyadded', onKeyAdded);
326 } else {
327 video.addEventListener('needkey', onNeedKey);
328 }
212 installTitleEventHandler(video, 'error'); 329 installTitleEventHandler(video, 'error');
213 330
214 if (useMSE) { 331 if (useMSE) {
215 var mediaSource = loadMediaSource(mediaFile, mediaType, 332 var mediaSource = loadMediaSource(mediaFile, mediaType,
216 appendSourceCallbackFn); 333 appendSourceCallbackFn);
217 video.src = window.URL.createObjectURL(mediaSource); 334 video.src = window.URL.createObjectURL(mediaSource);
218 } else { 335 } else {
219 video.src = mediaFile; 336 video.src = mediaFile;
220 } 337 }
338 if (!usePrefixedEME) {
339 mediaKeys = new MediaKeys(keySystem);
ddorwin 2014/03/04 21:18:48 nit: Any reason not to do this at 328?
jrummell 2014/03/04 23:55:49 Unprefixed tests timeout if done at 328.
ddorwin 2014/03/05 19:04:36 Bug! Please file. I assume it is the setMediaKeys
jrummell 2014/03/05 23:13:23 Opened http://crbug.com/349546
340 video.setMediaKeys(mediaKeys);
341 }
221 } 342 }
222 343
223 function getInitDataFromKeyId(keyID) { 344 function getInitDataFromKeyId(keyID) {
224 var init_key_id = new Uint8Array(keyID.length); 345 var init_key_id = new Uint8Array(keyID.length);
225 for(var i = 0; i < keyID.length; i++) { 346 for(var i = 0; i < keyID.length; i++) {
226 init_key_id[i] = keyID.charCodeAt(i); 347 init_key_id[i] = keyID.charCodeAt(i);
227 } 348 }
228 return init_key_id; 349 return init_key_id;
229 } 350 }
230 351
(...skipping 19 matching lines...) Expand all
250 licenseRequestRetryDelayMs + 'ms.'); 371 licenseRequestRetryDelayMs + 'ms.');
251 setTimeout(requestLicense, licenseRequestRetryDelayMs, message); 372 setTimeout(requestLicense, licenseRequestRetryDelayMs, message);
252 } 373 }
253 else 374 else
254 failTest('Bad license server response: ' + this.response); 375 failTest('Bad license server response: ' + this.response);
255 } 376 }
256 } 377 }
257 console.log('license request message', message.message); 378 console.log('license request message', message.message);
258 xmlhttp.send(message.message); 379 xmlhttp.send(message.message);
259 } 380 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698