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

Side by Side Diff: third_party/WebKit/LayoutTests/imported/wpt/encrypted-media/polyfill/clearkey-polyfill.js

Issue 2546853003: Add W3C encrypted-media tests (Closed)
Patch Set: rebase now that content files landed Created 4 years 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
(Empty)
1 (function(){
2
3 // Save platform functions that will be modified
4 var _requestMediaKeySystemAccess = navigator.requestMediaKeySystemAccess.bin d( navigator ),
5 _setMediaKeys = HTMLMediaElement.prototype.setMediaKeys;
6
7 // Allow us to modify the target of Events
8 Object.defineProperties( Event.prototype, {
9 target: { get: function() { return this._target || this.currentTarget; },
10 set: function( newtarget ) { this._target = newtarget; } }
11 } );
12
13 var EventTarget = function(){
14 this.listeners = {};
15 };
16
17 EventTarget.prototype.listeners = null;
18
19 EventTarget.prototype.addEventListener = function(type, callback){
20 if(!(type in this.listeners)) {
21 this.listeners[type] = [];
22 }
23 this.listeners[type].push(callback);
24 };
25
26 EventTarget.prototype.removeEventListener = function(type, callback){
27 if(!(type in this.listeners)) {
28 return;
29 }
30 var stack = this.listeners[type];
31 for(var i = 0, l = stack.length; i < l; i++){
32 if(stack[i] === callback){
33 stack.splice(i, 1);
34 return this.removeEventListener(type, callback);
35 }
36 }
37 };
38
39 EventTarget.prototype.dispatchEvent = function(event){
40 if(!(event.type in this.listeners)) {
41 return;
42 }
43 var stack = this.listeners[event.type];
44 event.target = this;
45 for(var i = 0, l = stack.length; i < l; i++) {
46 stack[i].call(this, event);
47 }
48 };
49
50 function MediaKeySystemAccessProxy( keysystem, access, configuration )
51 {
52 this._keysystem = keysystem;
53 this._access = access;
54 this._configuration = configuration;
55 }
56
57 Object.defineProperties( MediaKeySystemAccessProxy.prototype, {
58 keysystem: { get: function() { return this._keysystem; } }
59 });
60
61 MediaKeySystemAccessProxy.prototype.getConfiguration = function getConfigura tion()
62 {
63 return this._configuration;
64 };
65
66 MediaKeySystemAccessProxy.prototype.createMediaKeys = function createMediaKe ys()
67 {
68 return new Promise( function( resolve, reject ) {
69
70 this._access.createMediaKeys()
71 .then( function( mediaKeys ) { resolve( new MediaKeysProxy( mediaKey s ) ); })
72 .catch( function( error ) { reject( error ); } );
73
74 }.bind( this ) );
75 };
76
77 function MediaKeysProxy( mediaKeys )
78 {
79 this._mediaKeys = mediaKeys;
80 this._sessions = [ ];
81 this._videoelement = undefined;
82 this._onTimeUpdateListener = MediaKeysProxy.prototype._onTimeUpdate.bind ( this );
83 }
84
85 MediaKeysProxy.prototype._setVideoElement = function _setVideoElement( video Element )
86 {
87 if ( videoElement !== this._videoelement )
88 {
89 if ( this._videoelement )
90 {
91 this._videoelement.removeEventListener( 'timeupdate', this._onTi meUpdateListener );
92 }
93
94 this._videoelement = videoElement;
95
96 if ( this._videoelement )
97 {
98 this._videoelement.addEventListener( 'timeupdate', this._onTimeU pdateListener );
99 }
100 }
101 };
102
103 MediaKeysProxy.prototype._onTimeUpdate = function( event )
104 {
105 this._sessions.forEach( function( session ) {
106
107 if ( session._sessionType === 'persistent-usage-record' )
108 {
109 session._onTimeUpdate( event );
110 }
111
112 } );
113 };
114
115 MediaKeysProxy.prototype._removeSession = function _removeSession( session )
116 {
117 var index = this._sessions.indexOf( session );
118 if ( index !== -1 ) this._sessions.splice( index, 1 );
119 };
120
121 MediaKeysProxy.prototype.createSession = function createSession( sessionType )
122 {
123 if ( !sessionType || sessionType === 'temporary' ) return this._mediaKey s.createSession();
124
125 var session = new MediaKeySessionProxy( this, sessionType );
126 this._sessions.push( session );
127
128 return session;
129 };
130
131 MediaKeysProxy.prototype.setServerCertificate = function setServerCertificat e( certificate )
132 {
133 return this._mediaKeys.setServerCertificate( certificate );
134 };
135
136 function MediaKeySessionProxy( mediaKeysProxy, sessionType )
137 {
138 EventTarget.call( this );
139
140 this._mediaKeysProxy = mediaKeysProxy
141 this._sessionType = sessionType;
142 this._sessionId = "";
143
144 // MediaKeySessionProxy states
145 // 'created' - After initial creation
146 // 'loading' - Persistent license session waiting for key message to loa d stored keys
147 // 'active' - Normal active state - proxy all key messages
148 // 'removing' - Release message generated, waiting for ack
149 // 'closed' - Session closed
150 this._state = 'created';
151
152 this._closed = new Promise( function( resolve ) { this._resolveClosed = resolve; }.bind( this ) );
153 }
154
155 MediaKeySessionProxy.prototype = Object.create( EventTarget.prototype );
156
157 Object.defineProperties( MediaKeySessionProxy.prototype, {
158
159 sessionId: { get: function() { return this._sessionId; } },
160 expiration: { get: function() { return NaN; } },
161 closed: { get: function() { return this._closed; } },
162 keyStatuses:{ get: function() { return this._session.keyStatuses; } }, // TODO this will fail if examined too early
163 _kids: { get: function() { return this._keys.map( function( key ) { return key.kid; } ); } },
164 });
165
166 MediaKeySessionProxy.prototype._createSession = function _createSession()
167 {
168 this._session = this._mediaKeysProxy._mediaKeys.createSession();
169
170 this._session.addEventListener( 'message', MediaKeySessionProxy.prototyp e._onMessage.bind( this ) );
171 this._session.addEventListener( 'keystatuseschange', MediaKeySessionProx y.prototype._onKeyStatusesChange.bind( this ) );
172 };
173
174 MediaKeySessionProxy.prototype._onMessage = function _onMessage( event )
175 {
176 switch( this._state )
177 {
178 case 'loading':
179 this._session.update( toUtf8( { keys: this._keys } ) )
180 .then( function() {
181 this._state = 'active';
182 this._loaded( true );
183 }.bind(this)).catch( this._loadfailed );
184
185 break;
186
187 case 'active':
188 this.dispatchEvent( event );
189 break;
190
191 default:
192 // Swallow the event
193 break;
194 }
195 };
196
197 MediaKeySessionProxy.prototype._onKeyStatusesChange = function _onKeyStatuse sChange( event )
198 {
199 switch( this._state )
200 {
201 case 'active' :
202 case 'removing' :
203 this.dispatchEvent( event );
204 break;
205
206 default:
207 // Swallow the event
208 break;
209 }
210 };
211
212 MediaKeySessionProxy.prototype._onTimeUpdate = function _onTimeUpdate( event )
213 {
214 if ( !this._firstTime ) this._firstTime = Date.now();
215 this._latestTime = Date.now();
216 this._store();
217 };
218
219 MediaKeySessionProxy.prototype._queueMessage = function _queueMessage( messa geType, message )
220 {
221 setTimeout( function() {
222
223 var messageAsArray = toUtf8( message ).buffer;
224
225 this.dispatchEvent( new MediaKeyMessageEvent( 'message', { messageTy pe: messageType, message: messageAsArray } ) );
226
227 }.bind( this ) );
228 };
229
230 function _storageKey( sessionId )
231 {
232 return sessionId;
233 }
234
235 MediaKeySessionProxy.prototype._store = function _store()
236 {
237 var data;
238
239 if ( this._sessionType === 'persistent-usage-record' )
240 {
241 data = { kids: this._kids };
242 if ( this._firstTime ) data.firstTime = this._firstTime;
243 if ( this._latestTime ) data.latestTime = this._latestTime;
244 }
245 else
246 {
247 data = { keys: this._keys };
248 }
249
250 window.localStorage.setItem( _storageKey( this._sessionId ), JSON.string ify( data ) );
251 };
252
253 MediaKeySessionProxy.prototype._load = function _load( sessionId )
254 {
255 var store = window.localStorage.getItem( _storageKey( sessionId ) );
256 if ( store === null ) return false;
257
258 var data;
259 try { data = JSON.parse( store ) } catch( error ) {
260 return false;
261 }
262
263 if ( data.kids )
264 {
265 this._sessionType = 'persistent-usage-record';
266 this._keys = data.kids.map( function( kid ) { return { kid: kid }; } );
267 if ( data.firstTime ) this._firstTime = data.firstTime;
268 if ( data.latestTime ) this._latestTime = data.latestTime;
269 }
270 else
271 {
272 this._sessionType = 'persistent-license';
273 this._keys = data.keys;
274 }
275
276 return true;
277 };
278
279 MediaKeySessionProxy.prototype._clear = function _clear()
280 {
281 window.localStorage.removeItem( _storageKey( this._sessionId ) );
282 };
283
284 MediaKeySessionProxy.prototype.generateRequest = function generateRequest( i nitDataType, initData )
285 {
286 if ( this._state !== 'created' ) return Promise.reject( new InvalidState Error() );
287
288 this._createSession();
289
290 this._state = 'active';
291
292 return this._session.generateRequest( initDataType, initData )
293 .then( function() {
294 this._sessionId = Math.random().toString(36).slice(2);
295 }.bind( this ) );
296 };
297
298 MediaKeySessionProxy.prototype.load = function load( sessionId )
299 {
300 if ( this._state !== 'created' ) return Promise.reject( new InvalidState Error() );
301
302 return new Promise( function( resolve, reject ) {
303
304 try
305 {
306 if ( !this._load( sessionId ) )
307 {
308 resolve( false );
309
310 return;
311 }
312
313 this._sessionId = sessionId;
314
315 if ( this._sessionType === 'persistent-usage-record' )
316 {
317 var msg = { kids: this._kids };
318 if ( this._firstTime ) msg.firstTime = this._firstTime;
319 if ( this._latestTime ) msg.latestTime = this._latestTime;
320
321 this._queueMessage( 'license-release', msg );
322
323 this._state = 'removing';
324
325 resolve( true );
326 }
327 else
328 {
329 this._createSession();
330
331 this._state = 'loading';
332 this._loaded = resolve;
333 this._loadfailed = reject;
334
335 var initData = { kids: this._kids };
336
337 this._session.generateRequest( 'keyids', toUtf8( initData ) );
338 }
339 }
340 catch( error )
341 {
342 reject( error );
343 }
344 }.bind( this ) );
345 };
346
347 MediaKeySessionProxy.prototype.update = function update( response )
348 {
349 return new Promise( function( resolve, reject ) {
350
351 switch( this._state ) {
352
353 case 'active' :
354
355 var message = fromUtf8( response );
356
357 // JSON Web Key Set
358 this._keys = message.keys;
359
360 this._store();
361
362 resolve( this._session.update( response ) );
363
364 break;
365
366 case 'removing' :
367
368 this._state = 'closed';
369
370 this._clear();
371
372 this._mediaKeysProxy._removeSession( this );
373
374 this._resolveClosed();
375
376 delete this._session;
377
378 resolve();
379
380 break;
381
382 default:
383 reject( new InvalidStateError() );
384 }
385
386 }.bind( this ) );
387 };
388
389 MediaKeySessionProxy.prototype.close = function close()
390 {
391 if ( this._state === 'closed' ) return Promise.resolve();
392
393 this._state = 'closed';
394
395 this._mediaKeysProxy._removeSession( this );
396
397 this._resolveClosed();
398
399 var session = this._session;
400 if ( !session ) return Promise.resolve();
401
402 this._session = undefined;
403
404 return session.close();
405 };
406
407 MediaKeySessionProxy.prototype.remove = function remove()
408 {
409 if ( this._state !== 'active' || !this._session ) return Promise.reject( new DOMException('InvalidStateError('+this._state+')') );
410
411 this._state = 'removing';
412
413 this._mediaKeysProxy._removeSession( this );
414
415 return this._session.close()
416 .then( function() {
417
418 var msg = { kids: this._kids };
419
420 if ( this._sessionType === 'persistent-usage-record' )
421 {
422 if ( this._firstTime ) msg.firstTime = this._firstTime;
423 if ( this._latestTime ) msg.latestTime = this._latestTime;
424 }
425
426 this._queueMessage( 'license-release', msg );
427
428 }.bind( this ) )
429 };
430
431 HTMLMediaElement.prototype.setMediaKeys = function setMediaKeys( mediaKeys )
432 {
433 if ( mediaKeys instanceof MediaKeysProxy )
434 {
435 mediaKeys._setVideoElement( this );
436 return _setMediaKeys.call( this, mediaKeys._mediaKeys );
437 }
438 else
439 {
440 return _setMediaKeys.call( this, mediaKeys );
441 }
442 };
443
444 navigator.requestMediaKeySystemAccess = function( keysystem, configurations )
445 {
446 // First, see if this is supported by the platform
447 return new Promise( function( resolve, reject ) {
448
449 _requestMediaKeySystemAccess( keysystem, configurations )
450 .then( function( access ) { resolve( access ); } )
451 .catch( function( error ) {
452
453 if ( error instanceof TypeError ) reject( error );
454
455 if ( keysystem !== 'org.w3.clearkey' ) reject( error );
456
457 if ( !configurations.some( is_persistent_configuration ) ) rejec t( error );
458
459 // Shallow copy the configurations, swapping out the labels and omitting the sessiontypes
460 var configurations_copy = configurations.map( function( config, index ) {
461
462 var config_copy = copy_configuration( config );
463 config_copy.label = index.toString();
464 return config_copy;
465
466 } );
467
468 // And try again with these configurations
469 _requestMediaKeySystemAccess( keysystem, configurations_copy )
470 .then( function( access ) {
471
472 // Create the supported configuration based on the original request
473 var configuration = access.getConfiguration(),
474 original_configuration = configurations[ configuration.l abel ];
475
476 // If the original configuration did not need persistent ses sion types, then we're done
477 if ( !is_persistent_configuration( original_configuration ) ) resolve( access );
478
479 // Create the configuration that we will return
480 var returned_configuration = copy_configuration( configurati on );
481
482 if ( original_configuration.label )
483 returned_configuration.label = original_configuration;
484 else
485 delete returned_configuration.label;
486
487 returned_configuration.sessionTypes = original_configuration .sessionTypes;
488
489 resolve( new MediaKeySystemAccessProxy( keysystem, access, r eturned_configuration ) );
490 } )
491 .catch( function( error ) { reject( error ); } );
492 } );
493 } );
494 };
495
496 function is_persistent_configuration( configuration )
497 {
498 return configuration.sessionTypes &&
499 ( configuration.sessionTypes.indexOf( 'persistent-usage-record' ) !== -1
500 || configuration.sessionTypes.indexOf( 'persistent-license' ) != = -1 );
501 }
502
503 function copy_configuration( src )
504 {
505 var dst = {};
506 [ 'label', 'initDataTypes', 'audioCapabilities', 'videoCapabilities', 'd istinctiveIdenfifier', 'persistentState' ]
507 .forEach( function( item ) { if ( src[item] ) dst[item] = src[item]; } ) ;
508 return dst;
509 }
510 }());
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698