diff options
Diffstat (limited to '')
-rw-r--r-- | testing/web-platform/tests/encrypted-media/polyfill/edge-persistent-usage-record.js | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/testing/web-platform/tests/encrypted-media/polyfill/edge-persistent-usage-record.js b/testing/web-platform/tests/encrypted-media/polyfill/edge-persistent-usage-record.js new file mode 100644 index 0000000000..7f86f0c058 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/polyfill/edge-persistent-usage-record.js @@ -0,0 +1,193 @@ +(function() { + + // This polyfill fixes the following problems with Edge browser + // (1) To retrieve a persisted usage record, you must use session type 'persistent-release-message' instead of 'persistent-usage-record' + // (2) To retrieve a persisted usage record, you must call remove() after calling load() + // (3) On providing a license release acknowledgement, the session does not automatically close as is should + // (4) Retrieval of the usage record at the end of an active session is not supported + + if ( navigator.userAgent.toLowerCase().indexOf('edge') > -1 ) { + + var _mediaKeySystemAccessCreateMediaKeys = MediaKeySystemAccess.prototype.createMediaKeys; + _mediaKeysCreateSession = MediaKeys.prototype.createSession; + + // MediaKeySession proxy + function MediaKeySession( mediaKeys, session ) + { + EventTarget.call( this ); + + this._mediaKeys = mediaKeys; + this._session = session; + this._sessionId = undefined; + this._removing = false; + + session.addEventListener( 'message', this.dispatchEvent.bind( this ) ); + session.addEventListener( 'keystatuseschange', this.dispatchEvent.bind( this ) ); + session.closed.then( function() { if ( !this._removing ) this._resolveClosed(); }.bind ( this ) ); + + this._closed = new Promise( function( resolve ) { this._resolveClosed = resolve; }.bind( this ) ); + } + + MediaKeySession.prototype = Object.create( EventTarget.prototype ); + + Object.defineProperties( MediaKeySession.prototype, { + sessionId: { get: function() { return this._sessionId ? this._sessionId : this._session.sessionId; } }, + expiration: { get: function() { return this._session.expiration; } }, + closed: { get: function() { return this._closed; } }, + keyStatuses:{ get: function() { return this._session.keyStatuses; } } + }); + + // load() + // + // Use a surrogate 'persistent-release-message' session to obtain the release message + // + MediaKeySession.prototype.load = function load( sessionId ) + { + if ( this.sessionId ) return Promise.reject( new DOMException('InvalidAccessError') ); + + this._surrogate = this._mediaKeys.createSession( 'persistent-release-message' ); + this._surrogate.addEventListener( 'message', this.dispatchEvent.bind( this ) ); + + return this._surrogate.load( sessionId ).then( function( success ) { + if (!success) return false; + + this._sessionId = sessionId; + this._removing = true; + this._session.close(); + + return this._surrogate.remove().then( function() { return true; } ); + }.bind( this ) ); + }; + + // remove() + // + // On an existing session, use a surrogate 'persistent-release-message' session to obtain the release message + // + MediaKeySession.prototype.remove = function remove() + { + if ( this._sessionId !== undefined ) return Promise.reject( new DOMException('InvalidAccessError') ); + if ( this.sessionId === undefined ) return Promise.reject( new DOMException('InvalidAccessError') ); + + this._surrogate = this._mediaKeys.createSession( 'persistent-release-message' ); + this._surrogate.addEventListener( 'message', this.dispatchEvent.bind( this ) ); + this._removing = true; + this._sessionId = this._session.sessionId; + + var self = this; + + return Promise.all( [ self._session.close(), self._session.closed ] ).then( function() { + return self._surrogate.load( self._sessionId ); + }).then( function( success ) { + if ( !success ) { + throw new DOMException('InvalidAccessError'); + } + + return self._surrogate.remove(); + }).then( function() { return true; } ); + } + + // update() + // + // For a normal session, pass through, otherwise update the surrogate and close the proxy + MediaKeySession.prototype.update = function update( message ) + { + if ( !this._removing ) return this._session.update( message ); + + return this._surrogate.update( message ).then( function() { + this._sessionId = undefined; + this._resolveClosed(); + }.bind( this ) ); + }; + + // close() - pass through + // + MediaKeySession.prototype.close = function close() + { + if ( !this._removing ) return this._session.close(); + this._resolveClosed(); + return Promise.resolve(); + }; + + // generateRequest() - pass through + // + MediaKeySession.prototype.generateRequest = function generateRequest( initDataType, initData ) + { + if ( this.sessionId ) Promise.reject( new DOMException('InvalidAccessError') ); + return this._session.generateRequest( initDataType, initData ); + }; + + // Wrap PlayReady persistent-usage-record sessions in our Proxy + MediaKeys.prototype.createSession = function createSession( sessionType ) { + + var session = _mediaKeysCreateSession.call( this, sessionType ); + if ( this._keySystem !== 'com.microsoft.playready' || sessionType !== 'persistent-usage-record' ) + { + return session; + } + + return new MediaKeySession( this, session ); + + }; + + // + // Annotation polyfills - annotate not otherwise available data + // + + // Annotate MediaKeys with the keysystem + MediaKeySystemAccess.prototype.createMediaKeys = function createMediaKeys() + { + return _mediaKeySystemAccessCreateMediaKeys.call( this ).then( function( mediaKeys ) { + mediaKeys._keySystem = this.keySystem; + return mediaKeys; + }.bind( this ) ); + }; + + // + // Utilities + // + + // Allow us to modify the target of Events + Object.defineProperties( Event.prototype, { + target: { get: function() { return this._target || this.currentTarget; }, + set: function( newtarget ) { this._target = newtarget; } } + } ); + + // Make an EventTarget base class + function EventTarget(){ + this.listeners = {}; + }; + + EventTarget.prototype.listeners = null; + + EventTarget.prototype.addEventListener = function(type, callback){ + if(!(type in this.listeners)) { + this.listeners[type] = []; + } + this.listeners[type].push(callback); + }; + + EventTarget.prototype.removeEventListener = function(type, callback){ + if(!(type in this.listeners)) { + return; + } + var stack = this.listeners[type]; + for(var i = 0, l = stack.length; i < l; i++){ + if(stack[i] === callback){ + stack.splice(i, 1); + return this.removeEventListener(type, callback); + } + } + }; + + EventTarget.prototype.dispatchEvent = function(event){ + if(!(event.type in this.listeners)) { + return; + } + var stack = this.listeners[event.type]; + event.target = this; + for(var i = 0, l = stack.length; i < l; i++) { + stack[i].call(this, event); + } + }; + } +})(); |