(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);
}
};
}
})();