UNPKG

videojs-contrib-eme

Version:

Supports Encrypted Media Extensions for playback of encrypted content in Video.js

2,176 lines 75.7 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){

},{}],2:[function(require,module,exports){
(function (global){
var topLevel = typeof global !== 'undefined' ? global :
    typeof window !== 'undefined' ? window : {}
var minDoc = require('min-document');

if (typeof document !== 'undefined') {
    module.exports = document;
} else {
    var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];

    if (!doccy) {
        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
    }

    module.exports = doccy;
}

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"min-document":1}],3:[function(require,module,exports){
(function (global){
if (typeof window !== "undefined") {
    module.exports = window;
} else if (typeof global !== "undefined") {
    module.exports = global;
} else if (typeof self !== "undefined"){
    module.exports = self;
} else {
    module.exports = {};
}

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],4:[function(require,module,exports){
(function (global){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _playready = require('./playready');

var getSupportedKeySystem = function getSupportedKeySystem(_ref) {
  var video = _ref.video;
  var keySystems = _ref.keySystems;

  // As this happens after the src is set on the video, we rely only on the set src (we
  // do not change src based on capabilities of the browser in this plugin).

  var promise = undefined;

  Object.keys(keySystems).forEach(function (keySystem) {
    // TODO use initDataTypes when appropriate
    var systemOptions = {};
    var audioContentType = keySystems[keySystem].audioContentType;
    var videoContentType = keySystems[keySystem].videoContentType;

    if (audioContentType) {
      systemOptions.audioCapabilities = [{
        contentType: audioContentType
      }];
    }
    if (videoContentType) {
      systemOptions.videoCapabilities = [{
        contentType: videoContentType
      }];
    }

    if (!promise) {
      promise = navigator.requestMediaKeySystemAccess(keySystem, [systemOptions]);
    } else {
      promise = promise['catch'](function (e) {
        return navigator.requestMediaKeySystemAccess(keySystem, [systemOptions]);
      });
    }
  });

  return promise;
};

var makeNewRequest = function makeNewRequest(_ref2) {
  var mediaKeys = _ref2.mediaKeys;
  var initDataType = _ref2.initDataType;
  var initData = _ref2.initData;
  var options = _ref2.options;
  var getLicense = _ref2.getLicense;

  var keySession = mediaKeys.createSession();

  keySession.addEventListener('message', function (event) {
    getLicense(options, event.message).then(function (license) {
      return keySession.update(license);
    })['catch'](_videoJs2['default'].log.error.bind(_videoJs2['default'].log.error, 'failed to get and set license'));
  }, false);

  keySession.generateRequest(initDataType, initData)['catch'](_videoJs2['default'].log.error.bind(_videoJs2['default'].log.error, 'Unable to create or initialize key session'));
};

var addSession = function addSession(_ref3) {
  var video = _ref3.video;
  var initDataType = _ref3.initDataType;
  var initData = _ref3.initData;
  var options = _ref3.options;
  var getLicense = _ref3.getLicense;

  if (video.mediaKeysObject) {
    makeNewRequest({
      mediaKeys: video.mediaKeysObject,
      initDataType: initDataType,
      initData: initData,
      options: options,
      getLicense: getLicense
    });
  } else {
    video.pendingSessionData.push({ initDataType: initDataType, initData: initData });
  }
};

var setMediaKeys = function setMediaKeys(_ref4) {
  var video = _ref4.video;
  var certificate = _ref4.certificate;
  var createdMediaKeys = _ref4.createdMediaKeys;
  var options = _ref4.options;
  var getLicense = _ref4.getLicense;

  video.mediaKeysObject = createdMediaKeys;

  if (certificate) {
    createdMediaKeys.setServerCertificate(certificate);
  }

  for (var i = 0; i < video.pendingSessionData.length; i++) {
    var data = video.pendingSessionData[i];

    makeNewRequest({
      mediaKeys: video.mediaKeysObject,
      initDataType: data.initDataType,
      initData: data.initData,
      options: options,
      getLicense: getLicense
    });
  }

  video.pendingSessionData = [];

  return video.setMediaKeys(createdMediaKeys);
};

var defaultPlayreadyGetLicense = function defaultPlayreadyGetLicense(url) {
  return function (emeOptions, keyMessage, callback) {
    (0, _playready.requestPlayreadyLicense)(url, keyMessage, function (err, response, responseBody) {
      if (err) {
        callback(err);
        return;
      }

      callback(null, responseBody);
    });
  };
};

var defaultGetLicense = function defaultGetLicense(url) {
  return function (emeOptions, keyMessage, callback) {
    _videoJs2['default'].xhr({
      uri: url,
      method: 'POST',
      responseType: 'arraybuffer',
      body: keyMessage,
      headers: {
        'Content-type': 'application/octet-stream'
      }
    }, function (err, response, responseBody) {
      if (err) {
        callback(err);
        return;
      }

      callback(null, responseBody);
    });
  };
};

var promisifyGetLicense = function promisifyGetLicense(getLicenseFn) {
  return function (emeOptions, keyMessage) {
    return new Promise(function (resolve, reject) {
      getLicenseFn(emeOptions, keyMessage, function (err, license) {
        if (err) {
          reject(err);
        }

        resolve(license);
      });
    });
  };
};

var standardizeKeySystemOptions = function standardizeKeySystemOptions(keySystem, keySystemOptions) {
  if (typeof keySystemOptions === 'string') {
    keySystemOptions = { url: keySystemOptions };
  }

  if (!keySystemOptions.url && !keySystemOptions.getLicense) {
    throw new Error('Neither URL nor getLicense function provided to get license');
  }

  if (keySystemOptions.url && !keySystemOptions.getLicense) {
    keySystemOptions.getLicense = keySystem === 'com.microsoft.playready' ? defaultPlayreadyGetLicense(keySystemOptions.url) : defaultGetLicense(keySystemOptions.url);
  }

  return keySystemOptions;
};

var standard5July2016 = function standard5July2016(_ref5) {
  var video = _ref5.video;
  var initDataType = _ref5.initDataType;
  var initData = _ref5.initData;
  var options = _ref5.options;

  if (typeof video.mediaKeysObject === 'undefined') {
    var _ret = (function () {
      // Prevent entering this path again.
      video.mediaKeysObject = null;

      // Will store all initData until the MediaKeys is ready.
      video.pendingSessionData = [];

      var certificate = undefined;
      var keySystemOptions = undefined;

      var keySystemPromise = getSupportedKeySystem({
        video: video,
        keySystems: options.keySystems
      });

      if (!keySystemPromise) {
        _videoJs2['default'].log.error('No supported key system found');
        return {
          v: undefined
        };
      }

      keySystemPromise.then(function (keySystemAccess) {
        return new Promise(function (resolve, reject) {
          // save key system for adding sessions
          video.keySystem = keySystemAccess.keySystem;

          keySystemOptions = standardizeKeySystemOptions(keySystemAccess.keySystem, options.keySystems[keySystemAccess.keySystem]);

          if (!keySystemOptions.getCertificate) {
            resolve(keySystemAccess);
            return;
          }

          keySystemOptions.getCertificate(options, function (err, cert) {
            if (err) {
              reject(err);
              return;
            }

            certificate = cert;

            resolve(keySystemAccess);
          });
        });
      }).then(function (keySystemAccess) {
        return keySystemAccess.createMediaKeys();
      }).then(function (createdMediaKeys) {
        return setMediaKeys({
          video: video,
          certificate: certificate,
          createdMediaKeys: createdMediaKeys,
          options: options,
          getLicense: promisifyGetLicense(keySystemOptions.getLicense)
        });
      })['catch'](_videoJs2['default'].log.error.bind(_videoJs2['default'].log.error, 'Failed to create and initialize a MediaKeys object'));
    })();

    if (typeof _ret === 'object') return _ret.v;
  }

  addSession({
    video: video,
    initDataType: initDataType,
    initData: initData,
    options: options,
    // if key system has not been determined then addSession doesn't need getLicense
    getLicense: video.keySystem ? promisifyGetLicense(standardizeKeySystemOptions(video.keySystem, options.keySystems[video.keySystem]).getLicense) : null
  });
};
exports.standard5July2016 = standard5July2016;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./playready":7}],5:[function(require,module,exports){
(function (global){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _globalWindow = require('global/window');

var _globalWindow2 = _interopRequireDefault(_globalWindow);

var _utils = require('./utils');

var FAIRPLAY_KEY_SYSTEM = 'com.apple.fps.1_0';

exports.FAIRPLAY_KEY_SYSTEM = FAIRPLAY_KEY_SYSTEM;
var concatInitDataIdAndCertificate = function concatInitDataIdAndCertificate(_ref) {
  var initData = _ref.initData;
  var id = _ref.id;
  var cert = _ref.cert;

  if (typeof id === 'string') {
    id = (0, _utils.stringToUint16Array)(id);
  }

  // layout:
  //   [initData]
  //   [4 byte: idLength]
  //   [idLength byte: id]
  //   [4 byte:certLength]
  //   [certLength byte: cert]
  var offset = 0;
  var buffer = new ArrayBuffer(initData.byteLength + 4 + id.byteLength + 4 + cert.byteLength);
  var dataView = new DataView(buffer);
  var initDataArray = new Uint8Array(buffer, offset, initData.byteLength);

  initDataArray.set(initData);
  offset += initData.byteLength;

  dataView.setUint32(offset, id.byteLength, true);
  offset += 4;

  var idArray = new Uint16Array(buffer, offset, id.length);

  idArray.set(id);
  offset += idArray.byteLength;

  dataView.setUint32(offset, cert.byteLength, true);
  offset += 4;

  var certArray = new Uint8Array(buffer, offset, cert.byteLength);

  certArray.set(cert);

  return new Uint8Array(buffer, 0, buffer.byteLength);
};

var addKey = function addKey(_ref2) {
  var video = _ref2.video;
  var contentId = _ref2.contentId;
  var initData = _ref2.initData;
  var cert = _ref2.cert;
  var options = _ref2.options;
  var getLicense = _ref2.getLicense;

  return new Promise(function (resolve, reject) {
    if (!video.webkitKeys) {
      video.webkitSetMediaKeys(new _globalWindow2['default'].WebKitMediaKeys(FAIRPLAY_KEY_SYSTEM));
    }

    if (!video.webkitKeys) {
      reject('Could not create MediaKeys');
      return;
    }

    var keySession = video.webkitKeys.createSession('video/mp4', concatInitDataIdAndCertificate({ id: contentId, initData: initData, cert: cert }));

    if (!keySession) {
      reject('Could not create key session');
      return;
    }

    keySession.contentId = contentId;

    keySession.addEventListener('webkitkeymessage', function (event) {
      getLicense(options, contentId, event.message, function (err, license) {
        if (err) {
          reject(err);
          return;
        }

        keySession.update(new Uint8Array(license));
      });
    });

    keySession.addEventListener('webkitkeyadded', function (event) {
      resolve(event);
    });

    // for testing purposes, adding webkitkeyerror must be the last item in this method
    keySession.addEventListener('webkitkeyerror', function (event) {
      reject(event);
    });
  });
};

var defaultGetCertificate = function defaultGetCertificate(certificateUri) {
  return function (emeOptions, callback) {
    _videoJs2['default'].xhr({
      uri: certificateUri,
      responseType: 'arraybuffer'
    }, function (err, response, responseBody) {
      if (err) {
        callback(err);
        return;
      }

      callback(null, new Uint8Array(responseBody));
    });
  };
};

var defaultGetContentId = function defaultGetContentId(emeOptions, initData) {
  return (0, _utils.getHostnameFromUri)((0, _utils.uint8ArrayToString)(initData));
};

var defaultGetLicense = function defaultGetLicense(licenseUri) {
  return function (emeOptions, contentId, keyMessage, callback) {
    _videoJs2['default'].xhr({
      uri: licenseUri,
      method: 'POST',
      responseType: 'arraybuffer',
      body: keyMessage,
      headers: {
        'Content-type': 'application/octet-stream'
      }
    }, function (err, response, responseBody) {
      if (err) {
        callback(err);
        return;
      }

      callback(null, responseBody);
    });
  };
};

var fairplay = function fairplay(_ref3) {
  var video = _ref3.video;
  var initData = _ref3.initData;
  var options = _ref3.options;

  var fairplayOptions = options.keySystems[FAIRPLAY_KEY_SYSTEM];
  var getCertificate = fairplayOptions.getCertificate || defaultGetCertificate(fairplayOptions.certificateUri);
  var getContentId = fairplayOptions.getContentId || defaultGetContentId;
  var getLicense = fairplayOptions.getLicense || defaultGetLicense(fairplayOptions.licenseUri);

  return new Promise(function (resolve, reject) {
    getCertificate(options, function (err, cert) {
      if (err) {
        reject(err);
        return;
      }

      resolve(cert);
    });
  }).then(function (cert) {
    return addKey({
      video: video,
      cert: cert,
      initData: initData,
      getLicense: getLicense,
      options: options,
      contentId: getContentId(options, initData)
    });
  })['catch'](_videoJs2['default'].log.error.bind(_videoJs2['default'].log.error));
};

exports['default'] = fairplay;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./utils":9,"global/window":3}],6:[function(require,module,exports){
(function (global){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _globalWindow = require('global/window');

var _globalWindow2 = _interopRequireDefault(_globalWindow);

var _playready = require('./playready');

var PLAYREADY_KEY_SYSTEM = 'com.microsoft.playready';

exports.PLAYREADY_KEY_SYSTEM = PLAYREADY_KEY_SYSTEM;
var addKeyToSession = function addKeyToSession(options, session, event) {
  var playreadyOptions = options.keySystems[PLAYREADY_KEY_SYSTEM];

  if (typeof playreadyOptions.getKey === 'function') {
    playreadyOptions.getKey(options, event.destinationURL, event.message.buffer, function (err, key) {
      if (err) {
        _videoJs2['default'].log.error('Unable to get key: ' + err);
        return;
      }

      session.update(key);
    });
    return;
  }

  if (typeof playreadyOptions === 'string') {
    playreadyOptions = { url: playreadyOptions };
  }

  var url = playreadyOptions.url || event.destinationURL;

  (0, _playready.requestPlayreadyLicense)(url, event.message.buffer, function (err, response) {
    if (err) {
      _videoJs2['default'].log.error('Unable to request key from url: ' + url);
      return;
    }

    session.update(new Uint8Array(response.body));
  });
};

exports.addKeyToSession = addKeyToSession;
var createSession = function createSession(video, initData, options) {
  var session = video.msKeys.createSession('video/mp4', initData);

  if (!session) {
    _videoJs2['default'].log.error('Could not create key session.');
    return;
  }

  // Note that mskeymessage may not always be called for PlayReady:
  //
  // "If initData contains a PlayReady object that contains an OnDemand header, only a
  // keyAdded event is returned (as opposed to a keyMessage event as described in the
  // Encrypted Media Extension draft). Similarly, if initData contains a PlayReady object
  // that contains a key identifier in the hashed data storage (HDS), only a keyAdded
  // event is returned."
  // eslint-disable-next-line max-len
  // @see [PlayReady License Acquisition]{@link https://msdn.microsoft.com/en-us/library/dn468979.aspx}
  session.addEventListener('mskeymessage', function (event) {
    addKeyToSession(options, session, event);
  });

  session.addEventListener('mskeyerror', function (event) {
    _videoJs2['default'].log.error('Unexpected key error from key session with ' + ('code: ' + session.error.code + ' and systemCode: ' + session.error.systemCode));
  });
};

exports.createSession = createSession;

exports['default'] = function (_ref) {
  var video = _ref.video;
  var initData = _ref.initData;
  var options = _ref.options;

  // Although by the standard examples the presence of video.msKeys is checked first to
  // verify that we aren't trying to create a new session when one already exists, here
  // sessions are managed earlier (on the player.eme object), meaning that at this point
  // any existing keys should be cleaned up.
  if (video.msKeys) {
    delete video.msKeys;
  }

  try {
    video.msSetMediaKeys(new _globalWindow2['default'].MSMediaKeys(PLAYREADY_KEY_SYSTEM));
  } catch (e) {
    _videoJs2['default'].log.error('Unable to create media keys for PlayReady key system. Error: ' + e.message);
    return;
  }

  createSession(video, initData, options);
};

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./playready":7,"global/window":3}],7:[function(require,module,exports){
(function (global){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _globalWindow = require('global/window');

var _globalWindow2 = _interopRequireDefault(_globalWindow);

/**
 * Parses the EME key message XML to extract HTTP headers and the Challenge element to use
 * in the PlayReady license request.
 *
 * @param {ArrayBuffer} message key message from EME
 * @return {Object} an object containing headers and the message body to use in the
 * license request
 */
var getMessageContents = function getMessageContents(message) {
  var xml = new DOMParser().parseFromString(
  // TODO do we want to support UTF-8?
  String.fromCharCode.apply(null, new Uint16Array(message)), 'application/xml');
  var headersElement = xml.getElementsByTagName('HttpHeaders')[0];
  var headers = {};

  if (headersElement) {
    var headerNames = headersElement.getElementsByTagName('name');
    var headerValues = headersElement.getElementsByTagName('value');

    for (var i = 0; i < headerNames.length; i++) {
      headers[headerNames[i].childNodes[0].nodeValue] = headerValues[i].childNodes[0].nodeValue;
    }
  }

  var challengeElement = xml.getElementsByTagName('Challenge')[0];
  var challenge = undefined;

  if (challengeElement) {
    challenge = _globalWindow2['default'].atob(challengeElement.childNodes[0].nodeValue);
  }

  return {
    headers: headers,
    message: challenge
  };
};

exports.getMessageContents = getMessageContents;
var requestPlayreadyLicense = function requestPlayreadyLicense(url, messageBuffer, callback) {
  var _getMessageContents = getMessageContents(messageBuffer);

  var headers = _getMessageContents.headers;
  var message = _getMessageContents.message;

  _videoJs2['default'].xhr({
    uri: url,
    method: 'post',
    headers: headers,
    body: message,
    responseType: 'arraybuffer'
  }, callback);
};
exports.requestPlayreadyLicense = requestPlayreadyLicense;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"global/window":3}],8:[function(require,module,exports){
(function (global){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _eme = require('./eme');

var _fairplay = require('./fairplay');

var _fairplay2 = _interopRequireDefault(_fairplay);

var _msPrefixed = require('./ms-prefixed');

var _msPrefixed2 = _interopRequireDefault(_msPrefixed);

var _utils = require('./utils');

var hasSession = function hasSession(sessions, initData) {
  for (var i = 0; i < sessions.length; i++) {
    // Other types of sessions may be in the sessions array that don't store the initData
    // (for instance, PlayReady sessions on IE11).
    if (!sessions[i].initData) {
      continue;
    }

    // initData should be an ArrayBuffer by the spec:
    // eslint-disable-next-line max-len
    // @see [Media Encrypted Event initData Spec]{@link https://www.w3.org/TR/encrypted-media/#mediaencryptedeventinit}
    //
    // However, on some browsers it may come back with a typed array view of the buffer.
    // This is the case for IE11, however, since IE11 sessions are handled differently
    // (following the msneedkey PlayReady path), this coversion may not be important. It
    // is safe though, and might be a good idea to retain in the short term (until we have
    // catalogued the full range of browsers and their implementations).
    if ((0, _utils.arrayBuffersEqual)((0, _utils.arrayBufferFrom)(sessions[i].initData), (0, _utils.arrayBufferFrom)(initData))) {
      return true;
    }
  }

  return false;
};

exports.hasSession = hasSession;
var handleEncryptedEvent = function handleEncryptedEvent(event, sourceOptions, sessions) {
  if (!sourceOptions || !sourceOptions.keySystems) {
    // return silently since it may be handled by a different system
    return;
  }

  // "Initialization Data must be a fixed value for a given set of stream(s) or media
  // data. It must only contain information related to the keys required to play a given
  // set of stream(s) or media data."
  // eslint-disable-next-line max-len
  // @see [Initialization Data Spec]{@link https://www.w3.org/TR/encrypted-media/#initialization-data}
  if (hasSession(sessions, event.initData)) {
    // TODO convert to videojs.log.debug and add back in
    // https://github.com/videojs/video.js/pull/4780
    // videojs.log('eme',
    //             'Already have a configured session for init data, ignoring event.');
    return;
  }

  sessions.push({ initData: event.initData });

  (0, _eme.standard5July2016)({
    video: event.target,
    initDataType: event.initDataType,
    initData: event.initData,
    options: sourceOptions
  });
};

exports.handleEncryptedEvent = handleEncryptedEvent;
var handleWebKitNeedKeyEvent = function handleWebKitNeedKeyEvent(event, sourceOptions) {
  if (!sourceOptions.keySystems || !sourceOptions.keySystems[_fairplay.FAIRPLAY_KEY_SYSTEM]) {
    // return silently since it may be handled by a different system
    return;
  }

  // From Apple's example Safari FairPlay integration code, webkitneedkey is not repeated
  // for the same content. Unless documentation is found to present the opposite, handle
  // all webkitneedkey events the same (even if they are repeated).

  return (0, _fairplay2['default'])({
    video: event.target,
    initData: event.initData,
    options: sourceOptions
  });
};

exports.handleWebKitNeedKeyEvent = handleWebKitNeedKeyEvent;
var handleMsNeedKeyEvent = function handleMsNeedKeyEvent(event, sourceOptions, sessions) {
  if (!sourceOptions.keySystems || !sourceOptions.keySystems[_msPrefixed.PLAYREADY_KEY_SYSTEM]) {
    // return silently since it may be handled by a different system
    return;
  }

  // "With PlayReady content protection, your Web app must handle the first needKey event,
  // but it must then ignore any other needKey event that occurs."
  // eslint-disable-next-line max-len
  // @see [PlayReady License Acquisition]{@link https://msdn.microsoft.com/en-us/library/dn468979.aspx}
  //
  // Usually (and as per the example in the link above) this is determined by checking for
  // the existence of video.msKeys. However, since the video element may be reused, it's
  // easier to directly manage the session.
  if (sessions.reduce(function (acc, session) {
    return acc || session.playready;
  }, false)) {
    // TODO convert to videojs.log.debug and add back in
    // https://github.com/videojs/video.js/pull/4780
    // videojs.log('eme',
    //             'An \'msneedkey\' event was receieved earlier, ignoring event.');
    return;
  }

  sessions.push({ playready: true });

  (0, _msPrefixed2['default'])({
    video: event.target,
    initData: event.initData,
    options: sourceOptions
  });
};

exports.handleMsNeedKeyEvent = handleMsNeedKeyEvent;
/**
 * Configure a persistent sessions array and activeSrc property to ensure we properly
 * handle each independent source's events. Should be run on any encrypted or needkey
 * style event to ensure that the sessions reflect the active source.
 *
 * @function setupSessions
 * @param    {Player} player
 */
var setupSessions = function setupSessions(player) {
  var src = player.src();

  if (src !== player.eme.activeSrc) {
    player.eme.activeSrc = src;
    player.eme.sessions = [];
  }
};

exports.setupSessions = setupSessions;
/**
 * Function to invoke when the player is ready.
 *
 * This is a great place for your plugin to initialize itself. When this
 * function is called, the player will have its DOM and child components
 * in place.
 *
 * @function onPlayerReady
 * @param    {Player} player
 * @param    {Object} [options={}]
 */
var onPlayerReady = function onPlayerReady(player, options) {
  if (player.$('.vjs-tech').tagName.toLowerCase() !== 'video') {
    return;
  }

  setupSessions(player);

  // Support EME 05 July 2016
  // Chrome 42+, Firefox 47+, Edge
  player.tech_.el_.addEventListener('encrypted', function (event) {
    // TODO convert to videojs.log.debug and add back in
    // https://github.com/videojs/video.js/pull/4780
    // videojs.log('eme', 'Received an \'encrypted\' event');
    setupSessions(player);
    handleEncryptedEvent(event, _videoJs2['default'].mergeOptions(options, player.currentSource()), player.eme.sessions);
  });
  // Support Safari EME with FairPlay
  // (also used in early Chrome or Chrome with EME disabled flag)
  player.tech_.el_.addEventListener('webkitneedkey', function (event) {
    // TODO convert to videojs.log.debug and add back in
    // https://github.com/videojs/video.js/pull/4780
    // videojs.log('eme', 'Received a \'webkitneedkey\' event');

    // TODO it's possible that the video state must be cleared if reusing the same video
    // element between sources
    setupSessions(player);
    handleWebKitNeedKeyEvent(event, _videoJs2['default'].mergeOptions(options, player.currentSource()));
  });

  // EDGE still fires msneedkey, but should use encrypted instead
  if (_videoJs2['default'].browser.IS_EDGE) {
    return;
  }

  // IE11 Windows 8.1+
  player.tech_.el_.addEventListener('msneedkey', function (event) {
    // TODO convert to videojs.log.debug and add back in
    // https://github.com/videojs/video.js/pull/4780
    // videojs.log('eme', 'Received an \'msneedkey\' event');
    setupSessions(player);
    handleMsNeedKeyEvent(event, _videoJs2['default'].mergeOptions(options, player.currentSource()), player.eme.sessions);
  });
};

/**
 * A video.js plugin.
 *
 * In the plugin function, the value of `this` is a video.js `Player`
 * instance. You cannot rely on the player being in a "ready" state here,
 * depending on how the plugin is invoked. This may or may not be important
 * to you; if not, remove the wait for "ready"!
 *
 * @function eme
 * @param    {Object} [options={}]
 *           An object of options left to the plugin author to define.
 */
var eme = function eme() {
  var _this = this;

  var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  this.ready(function () {
    onPlayerReady(_this, _videoJs2['default'].mergeOptions({}, options));
  });

  this.eme.options = options;
};

// Register the plugin with video.js.
var registerPlugin = _videoJs2['default'].registerPlugin || _videoJs2['default'].plugin;

registerPlugin('eme', eme);

exports['default'] = eme;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./eme":4,"./fairplay":5,"./ms-prefixed":6,"./utils":9}],9:[function(require,module,exports){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});
var stringToUint16Array = function stringToUint16Array(string) {
  // 2 bytes for each char
  var buffer = new ArrayBuffer(string.length * 2);
  var array = new Uint16Array(buffer);

  for (var i = 0; i < string.length; i++) {
    array[i] = string.charCodeAt(i);
  }

  return array;
};

exports.stringToUint16Array = stringToUint16Array;
var uint8ArrayToString = function uint8ArrayToString(array) {
  return String.fromCharCode.apply(null, new Uint16Array(array.buffer));
};

exports.uint8ArrayToString = uint8ArrayToString;
var getHostnameFromUri = function getHostnameFromUri(uri) {
  var link = document.createElement('a');

  link.href = uri;
  return link.hostname;
};

exports.getHostnameFromUri = getHostnameFromUri;
var arrayBuffersEqual = function arrayBuffersEqual(arrayBuffer1, arrayBuffer2) {
  if (arrayBuffer1 === arrayBuffer2) {
    return true;
  }

  if (arrayBuffer1.byteLength !== arrayBuffer2.byteLength) {
    return false;
  }

  var dataView1 = new DataView(arrayBuffer1);
  var dataView2 = new DataView(arrayBuffer2);

  for (var i = 0; i < dataView1.byteLength; i++) {
    if (dataView1.getUint8(i) !== dataView2.getUint8(i)) {
      return false;
    }
  }

  return true;
};

exports.arrayBuffersEqual = arrayBuffersEqual;
var arrayBufferFrom = function arrayBufferFrom(bufferOrTypedArray) {
  if (bufferOrTypedArray instanceof Uint8Array || bufferOrTypedArray instanceof Uint16Array) {
    return bufferOrTypedArray.buffer;
  }

  return bufferOrTypedArray;
};
exports.arrayBufferFrom = arrayBufferFrom;

},{}],10:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _srcEme = require('../src/eme');

_qunit2['default'].module('videojs-contrib-eme eme');

_qunit2['default'].test('accepts a license URL as an option', function (assert) {
  var done = assert.async();
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];
  var callbacks = {};

  _videoJs2['default'].xhr = function (options) {
    xhrCalls.push(options);
  };

  navigator.requestMediaKeySystemAccess = function (keySystem, options) {
    return new Promise(function (resolve, reject) {
      callbacks.requestMediaKeySystemAccess = resolve;
    });
  };

  (0, _srcEme.standard5July2016)({
    video: {},
    initDataType: '',
    initData: '',
    options: {
      keySystems: {
        'com.widevine.alpha': 'some-url'
      }
    }
  });

  var session = new _videoJs2['default'].EventTarget();

  callbacks.requestMediaKeySystemAccess({
    keySystem: 'com.widevine.alpha',
    createMediaKeys: function createMediaKeys() {
      return {
        createSession: function createSession() {
          return session;
        }
      };
    }
  });

  setTimeout(function () {
    session.trigger({
      type: 'message',
      message: 'the-message'
    });

    assert.equal(xhrCalls.length, 1, 'made one XHR');
    assert.deepEqual(xhrCalls[0], {
      uri: 'some-url',
      method: 'POST',
      responseType: 'arraybuffer',
      body: 'the-message',
      headers: {
        'Content-type': 'application/octet-stream'
      }
    }, 'made request with proper options');

    _videoJs2['default'].xhr = origXhr;

    done();
  });
});

_qunit2['default'].test('accepts a license URL as property', function (assert) {
  var done = assert.async();
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];
  var callbacks = {};

  _videoJs2['default'].xhr = function (options) {
    xhrCalls.push(options);
  };

  navigator.requestMediaKeySystemAccess = function (keySystem, options) {
    return new Promise(function (resolve, reject) {
      callbacks.requestMediaKeySystemAccess = resolve;
    });
  };

  (0, _srcEme.standard5July2016)({
    video: {},
    initDataType: '',
    initData: '',
    options: {
      keySystems: {
        'com.widevine.alpha': {
          url: 'some-url'
        }
      }
    }
  });

  var session = new _videoJs2['default'].EventTarget();

  callbacks.requestMediaKeySystemAccess({
    keySystem: 'com.widevine.alpha',
    createMediaKeys: function createMediaKeys() {
      return {
        createSession: function createSession() {
          return session;
        }
      };
    }
  });

  setTimeout(function () {
    session.trigger({
      type: 'message',
      message: 'the-message'
    });

    assert.equal(xhrCalls.length, 1, 'made one XHR');
    assert.deepEqual(xhrCalls[0], {
      uri: 'some-url',
      method: 'POST',
      responseType: 'arraybuffer',
      body: 'the-message',
      headers: {
        'Content-type': 'application/octet-stream'
      }
    }, 'made request with proper options');

    _videoJs2['default'].xhr = origXhr;

    done();
  });
});

_qunit2['default'].test('5 July 2016 lifecycle', function (assert) {
  assert.expect(40);

  var done = assert.async();
  var callbacks = {};
  var callCounts = {
    requestMediaKeySystemAccess: 0,
    getCertificate: 0,
    getLicense: 0,
    createSession: 0,
    keySessionGenerateRequest: 0,
    keySessionUpdate: 0,
    createMediaKeys: 0
  };

  navigator.requestMediaKeySystemAccess = function (keySystem, options) {
    callCounts.requestMediaKeySystemAccess++;
    return new Promise(function (resolve, reject) {
      callbacks.requestMediaKeySystemAccess = resolve;
    });
  };

  var getCertificate = function getCertificate(emeOptions, callback) {
    callCounts.getCertificate++;
    callbacks.getCertificate = callback;
  };
  var getLicense = function getLicense(emeOptions, keyMessage, callback) {
    callCounts.getLicense++;
    callbacks.getLicense = callback;
  };

  var _setMediaKeys = undefined;
  var video = {
    setMediaKeys: function setMediaKeys(mediaKeys) {
      _setMediaKeys = mediaKeys;
    }
  };

  var options = {
    keySystems: {
      'org.w3.clearkey': {
        getCertificate: getCertificate,
        getLicense: getLicense
      }
    }
  };

  var keySessionEventListeners = {};
  var mediaKeys = {
    createSession: function createSession() {
      callCounts.createSession++;
      return {
        addEventListener: function addEventListener(name, callback) {
          keySessionEventListeners[name] = callback;
        },
        generateRequest: function generateRequest() {
          callCounts.keySessionGenerateRequest++;
          return new Promise(function () {});
        },
        update: function update() {
          callCounts.keySessionUpdate++;
        }
      };
    }
  };

  var keySystemAccess = {
    keySystem: 'org.w3.clearkey',
    createMediaKeys: function createMediaKeys() {
      callCounts.createMediaKeys++;
      return mediaKeys;
    }
  };

  (0, _srcEme.standard5July2016)({
    video: video,
    initDataType: '',
    initData: '',
    options: options
  });

  // Step 1: get key system
  assert.equal(callCounts.requestMediaKeySystemAccess, 1, 'access requested');
  assert.equal(callCounts.getCertificate, 0, 'certificate not requested');
  assert.equal(callCounts.createMediaKeys, 0, 'media keys not created');
  assert.notEqual(mediaKeys, _setMediaKeys, 'media keys not yet set');
  assert.equal(callCounts.createSession, 0, 'key session not created');
  assert.equal(callCounts.keySessionGenerateRequest, 0, 'key session request not made');
  assert.equal(callCounts.getLicense, 0, 'license not requested');
  assert.equal(callCounts.keySessionUpdate, 0, 'key session not updated');

  callbacks.requestMediaKeySystemAccess(keySystemAccess);

  // requestMediaKeySystemAccess promise resolution
  setTimeout(function () {
    // Step 2: get certificate
    assert.equal(callCounts.requestMediaKeySystemAccess, 1, 'access requested');
    assert.equal(callCounts.getCertificate, 1, 'certificate requested');
    assert.equal(callCounts.createMediaKeys, 0, 'media keys not created');
    assert.notEqual(mediaKeys, _setMediaKeys, 'media keys not yet set');
    assert.equal(callCounts.createSession, 0, 'key session not created');
    assert.equal(callCounts.keySessionGenerateRequest, 0, 'key session request not made');
    assert.equal(callCounts.getLicense, 0, 'license not requested');
    assert.equal(callCounts.keySessionUpdate, 0, 'key session not updated');

    callbacks.getCertificate(null, '');

    // getCertificate promise resolution
    setTimeout(function () {
      // Step 3: create media keys, set them, and generate key session request
      assert.equal(callCounts.requestMediaKeySystemAccess, 1, 'access requested');
      assert.equal(callCounts.getCertificate, 1, 'certificate requested');
      assert.equal(callCounts.createMediaKeys, 1, 'media keys created');
      assert.equal(mediaKeys, _setMediaKeys, 'media keys set');
      assert.equal(callCounts.createSession, 1, 'key session created');
      assert.equal(callCounts.keySessionGenerateRequest, 1, 'key session request made');
      assert.equal(callCounts.getLicense, 0, 'license not requested');
      assert.equal(callCounts.keySessionUpdate, 0, 'key session not updated');

      keySessionEventListeners.message({});

      // Step 4: get license
      assert.equal(callCounts.requestMediaKeySystemAccess, 1, 'access requested');
      assert.equal(callCounts.getCertificate, 1, 'certificate requested');
      assert.equal(callCounts.createMediaKeys, 1, 'media keys created');
      assert.equal(mediaKeys, _setMediaKeys, 'media keys set');
      assert.equal(callCounts.createSession, 1, 'key session created');
      assert.equal(callCounts.keySessionGenerateRequest, 1, 'key session request made');
      assert.equal(callCounts.getLicense, 1, 'license requested');
      assert.equal(callCounts.keySessionUpdate, 0, 'key session not updated');

      callbacks.getLicense();

      // getLicense promise resolution
      setTimeout(function () {
        // Step 5: update key session
        assert.equal(callCounts.requestMediaKeySystemAccess, 1, 'access requested');
        assert.equal(callCounts.getCertificate, 1, 'certificate requested');
        assert.equal(callCounts.createMediaKeys, 1, 'media keys created');
        assert.equal(mediaKeys, _setMediaKeys, 'media keys set');
        assert.equal(callCounts.createSession, 1, 'key session created');
        assert.equal(callCounts.keySessionGenerateRequest, 1, 'key session request made');
        assert.equal(callCounts.getLicense, 1, 'license requested');
        assert.equal(callCounts.keySessionUpdate, 1, 'key session updated');

        done();
      });
    });
  });
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/eme":4}],11:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _srcFairplay = require('../src/fairplay');

var _srcFairplay2 = _interopRequireDefault(_srcFairplay);

_qunit2['default'].module('videojs-contrib-eme fairplay');

_qunit2['default'].test('lifecycle', function (assert) {
  assert.expect(19);

  var done = assert.async();
  var initData = new Uint8Array([1, 2, 3, 4]).buffer;
  var callbacks = {};
  var callCounts = {
    getCertificate: 0,
    getLicense: 0,
    updateKeySession: 0,
    createSession: 0
  };

  var getCertificate = function getCertificate(emeOptions, callback) {
    callCounts.getCertificate++;
    callbacks.getCertificate = callback;
  };
  var getLicense = function getLicense(emeOptions, contentId, keyMessage, callback) {
    callCounts.getLicense++;
    callbacks.getLicense = callback;
  };

  var options = {
    keySystems: {
      'com.apple.fps.1_0': {
        getCertificate: getCertificate,
        getLicense: getLicense,
        // not needed due to mocking
        getContentId: function getContentId() {
          return 'some content id';
        }
      }
    }
  };

  // trap event listeners
  var keySessionEventListeners = {};

  var updateKeySession = function updateKeySession(key) {
    callCounts.updateKeySession++;
  };

  var onKeySessionCreated = undefined;

  var createSession = function createSession(type, concatenatedData) {
    callCounts.createSession++;
    return {
      addEventListener: function addEventListener(name, callback) {
        keySessionEventListeners[name] = callback;

        if (name === 'webkitkeyerror') {
          // Since we don't have a way of executing code at the end of addKey's promise,
          // we assume that adding the listener for webkitkeyerror is the last run code
          // within the promise.
          onKeySessionCreated();
        }
      },
      update: updateKeySession
    };
  };

  // mock webkitKeys to avoid browser specific calls and enable us to verify ordering
  var video = {
    webkitKeys: {
      createSession: createSession
    }
  };

  (0, _srcFairplay2['default'])({ video: video, initData: initData, options: options }).then(function () {
    done();
  });

  // Step 1: getCertificate
  assert.equal(callCounts.getCertificate, 1, 'getCertificate has been called');
  assert.equal(callCounts.createSession, 0, 'a key session has not been created');
  assert.equal(callCounts.getLicense, 0, 'getLicense has not been called');
  assert.equal(callCounts.updateKeySession, 0, 'updateKeySession has not been called');

  callbacks.getCertificate(null, new Uint16Array([4, 5, 6, 7]).buffer);

  onKeySessionCreated = function () {
    // Step 2: create a key session
    assert.equal(callCounts.getCertificate, 1, 'getCertificate has been called');
    assert.equal(callCounts.createSession, 1, 'a key session has been created');
    assert.equal(callCounts.getLicense, 0, 'getLicense has not been called');
    assert.equal(callCounts.updateKeySession, 0, 'updateKeySession has not been called');

    assert.ok(keySessionEventListeners.webkitkeymessage, 'added an event listener for webkitkeymessage');
    assert.ok(keySessionEventListeners.webkitkeyadded, 'added an event listener for webkitkeyadded');
    assert.ok(keySessionEventListeners.webkitkeyerror, 'added an event listener for webkitkeyerror');

    keySessionEventListeners.webkitkeymessage({});

    // Step 3: get the key on webkitkeymessage
    assert.equal(callCounts.getCertificate, 1, 'getCertificate has been called');
    assert.equal(callCounts.createSession, 1, 'a key session has been created');
    assert.equal(callCounts.getLicense, 1, 'getLicense has been called');
    assert.equal(callCounts.updateKeySession, 0, 'updateKeySession has not been called');

    callbacks.getLicense(null, []);

    // Step 4: update the key session with the key
    assert.equal(callCounts.getCertificate, 1, 'getCertificate has been called');
    assert.equal(callCounts.createSession, 1, 'a key session has been created');
    assert.equal(callCounts.getLicense, 1, 'getLicense has been called');
    assert.equal(callCounts.updateKeySession, 1, 'updateKeySession has been called');

    keySessionEventListeners.webkitkeyadded();
  };
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/fairplay":5}],12:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _globalWindow = require('global/window');

var _globalWindow2 = _interopRequireDefault(_globalWindow);

var _playreadyMessage = require('./playready-message');

var _srcMsPrefixed = require('../src/ms-prefixed');

var _srcMsPrefixed2 = _interopRequireDefault(_srcMsPrefixed);

var _utils = require('./utils');

var _utils2 = _interopRequireDefault(_utils);

_qunit2['default'].module('videojs-contrib-eme ms-prefixed', {
  beforeEach: function beforeEach() {
    var _this = this;

    this.origMSMediaKeys = _globalWindow2['default'].MSMediaKeys;
    _globalWindow2['default'].MSMediaKeys = function () {};

    var session = new _videoJs2['default'].EventTarget();

    session.keys = [];
    session.update = function (key) {
      return session.keys.push(key);
    };

    // mock the video since the APIs won't be available on non IE11 browsers
    var video = {
      msSetMediaKeys: function msSetMediaKeys() {
        video.msKeys = {
          createSession: function createSession() {
            return _this.session;
          }
        };
      }
    };

    this.session = session;
    this.video = video;
  },
  afterEach: function afterEach() {
    _globalWindow2['default'].MSMediaKeys = this.origMSMediaKeys;
  }
});

_qunit2['default'].test('overwrites msKeys', function (assert) {
  var origMsKeys = {};

  this.video.msKeys = origMsKeys;

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': true
      }
    }
  });

  assert.notEqual(this.video.msKeys, origMsKeys, 'overwrote msKeys');
});

_qunit2['default'].test('logs error when on key error', function (assert) {
  var origErrorLog = _videoJs2['default'].log.error;
  var errorMessage = undefined;

  _videoJs2['default'].log.error = function (message) {
    errorMessage = message;
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': true
      }
    }
  });

  this.session.error = {
    code: 5,
    systemCode: 9
  };

  this.session.trigger('mskeyerror');

  assert.equal(errorMessage, 'Unexpected key error from key session with code: 5 and systemCode: 9', 'logged error message');

  _videoJs2['default'].log.error = origErrorLog;
});

_qunit2['default'].test('calls getKey when provided on key message', function (assert) {
  var passedOptions = null;
  var passedDestinationURL = null;
  var passedBuffer = null;
  var passedCallback = null;
  var getKeyCallback = function getKeyCallback(callback) {
    callback(null, 'a key');
  };

  var emeOptions = {
    keySystems: {
      'com.microsoft.playready': {
        getKey: function getKey(options, destinationURL, buffer, callback) {
          passedOptions = options;
          passedDestinationURL = destinationURL;
          passedBuffer = buffer;
          passedCallback = callback;
          getKeyCallback(callback);
        }
      }
    }
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: emeOptions
  });

  assert.notOk(passedOptions, 'getKey not called');

  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'url',
    message: {
      buffer: 'buffer'
    }
  });

  assert.equal(passedOptions, emeOptions, 'getKey called with options');
  assert.equal(passedDestinationURL, 'url', 'getKey called with destinationURL');
  assert.equal(passedBuffer, 'buffer', 'getKey called with buffer');
  assert.equal(typeof passedCallback, 'function', 'getKey called with callback');
  assert.equal(this.session.keys.length, 1, 'added key to session');
  assert.equal(this.session.keys[0], 'a key', 'added correct key to session');

  var origErrorLog = _videoJs2['default'].log.error;
  var errorMessage = undefined;

  _videoJs2['default'].log.error = function (message) {
    errorMessage = message;
  };

  getKeyCallback = function (callback) {
    callback('an error', 'an errored key');
  };

  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'url',
    message: {
      buffer: 'buffer'
    }
  });

  assert.equal(errorMessage, 'Unable to get key: an error', 'logs error when callback has an error');
  assert.equal(this.session.keys.length, 1, 'did not add a new key');

  _videoJs2['default'].log.error = origErrorLog;
});

_qunit2['default'].test('makes request when nothing provided on key message', function (assert) {
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];

  _videoJs2['default'].xhr = function (config, callback) {
    return xhrCalls.push({ config: config, callback: callback });
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': true
      }
    }
  });
  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'destination-url',
    message: {
      buffer: (0, _playreadyMessage.createMessageBuffer)()
    }
  });

  assert.equal(xhrCalls.length, 1, 'one xhr request');
  assert.equal(xhrCalls[0].config.uri, 'destination-url', 'made request to destinationURL');
  assert.deepEqual(xhrCalls[0].config.headers, {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
  }, 'uses headers from message');
  assert.equal(xhrCalls[0].config.body, _playreadyMessage.challengeElement, 'sends the challenge element');
  assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
  assert.equal(xhrCalls[0].config.responseType, 'arraybuffer', 'responseType is an arraybuffer');

  var origErrorLog = _videoJs2['default'].log.error;
  var errorMessage = undefined;

  _videoJs2['default'].log.error = function (message) {
    errorMessage = message;
  };

  var response = {
    body: _utils2['default'].stringToArrayBuffer('key value')
  };

  xhrCalls[0].callback('an error', response);

  assert.equal(errorMessage, 'Unable to request key from url: destination-url', 'logs error when callback has an error');
  assert.equal(this.session.keys.length, 0, 'no key added to session');

  xhrCalls[0].callback(null, response);

  assert.equal(this.session.keys.length, 1, 'key added to session');
  assert.deepEqual(this.session.keys[0], new Uint8Array(response.body), 'correct key added to session');

  _videoJs2['default'].log.error = origErrorLog;
  _videoJs2['default'].xhr = origXhr;
});

_qunit2['default'].test('makes request on key message when empty object provided in options', function (assert) {
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];

  _videoJs2['default'].xhr = function (config, callback) {
    return xhrCalls.push({ config: config, callback: callback });
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': {}
      }
    }
  });
  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'destination-url',
    message: {
      buffer: (0, _playreadyMessage.createMessageBuffer)()
    }
  });

  assert.equal(xhrCalls.length, 1, 'one xhr request');
  assert.equal(xhrCalls[0].config.uri, 'destination-url', 'made request to destinationURL');
  assert.deepEqual(xhrCalls[0].config.headers, {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
  }, 'uses headers from message');
  assert.equal(xhrCalls[0].config.body, _playreadyMessage.challengeElement, 'sends the challenge element');
  assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
  assert.equal(xhrCalls[0].config.responseType, 'arraybuffer', 'responseType is an arraybuffer');

  _videoJs2['default'].xhr = origXhr;
});

_qunit2['default'].test('makes request with provided url string on key message', function (assert) {
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];

  _videoJs2['default'].xhr = function (config, callback) {
    return xhrCalls.push({ config: config, callback: callback });
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': 'provided-url'
      }
    }
  });
  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'destination-url',
    message: {
      buffer: (0, _playreadyMessage.createMessageBuffer)([{
        name: 'Content-Type',
        value: 'text/xml; charset=utf-8'
      }, {
        name: 'SOAPAction',
        value: '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
      }])
    }
  });

  assert.equal(xhrCalls.length, 1, 'one xhr request');
  assert.equal(xhrCalls[0].config.uri, 'provided-url', 'made request to provided-url');
  assert.deepEqual(xhrCalls[0].config.headers, {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
  }, 'uses headers from message');
  assert.equal(xhrCalls[0].config.body, _playreadyMessage.challengeElement, 'sends the challenge element');
  assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
  assert.equal(xhrCalls[0].config.responseType, 'arraybuffer', 'responseType is an arraybuffer');

  var origErrorLog = _videoJs2['default'].log.error;
  var errorMessage = undefined;

  _videoJs2['default'].log.error = function (message) {
    errorMessage = message;
  };

  var response = {
    body: _utils2['default'].stringToArrayBuffer('key value')
  };

  xhrCalls[0].callback('an error', response);

  assert.equal(errorMessage, 'Unable to request key from url: provided-url', 'logs error when callback has an error');
  assert.equal(this.session.keys.length, 0, 'no key added to session');

  xhrCalls[0].callback(null, response);

  assert.equal(this.session.keys.length, 1, 'key added to session');
  assert.deepEqual(this.session.keys[0], new Uint8Array(response.body), 'correct key added to session');

  _videoJs2['default'].log.error = origErrorLog;
  _videoJs2['default'].xhr = origXhr;
});

_qunit2['default'].test('makes request with provided url on key message', function (assert) {
  var origXhr = _videoJs2['default'].xhr;
  var xhrCalls = [];

  _videoJs2['default'].xhr = function (config, callback) {
    return xhrCalls.push({ config: config, callback: callback });
  };

  (0, _srcMsPrefixed2['default'])({
    video: this.video,
    initData: '',
    options: {
      keySystems: {
        'com.microsoft.playready': {
          url: 'provided-url'
        }
      }
    }
  });
  this.session.trigger({
    type: 'mskeymessage',
    destinationURL: 'destination-url',
    message: {
      buffer: (0, _playreadyMessage.createMessageBuffer)([{
        name: 'Content-Type',
        value: 'text/xml; charset=utf-8'
      }, {
        name: 'SOAPAction',
        value: '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
      }])
    }
  });

  assert.equal(xhrCalls.length, 1, 'one xhr request');
  assert.equal(xhrCalls[0].config.uri, 'provided-url', 'made request to provided-url');
  assert.deepEqual(xhrCalls[0].config.headers, {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
  }, 'uses headers from message');
  assert.equal(xhrCalls[0].config.body, _playreadyMessage.challengeElement, 'sends the challenge element');
  assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
  assert.equal(xhrCalls[0].config.responseType, 'arraybuffer', 'responseType is an arraybuffer');

  var origErrorLog = _videoJs2['default'].log.error;
  var errorMessage = undefined;

  _videoJs2['default'].log.error = function (message) {
    errorMessage = message;
  };

  var response = {
    body: _utils2['default'].stringToArrayBuffer('key value')
  };

  xhrCalls[0].callback('an error', response);

  assert.equal(errorMessage, 'Unable to request key from url: provided-url', 'logs error when callback has an error');
  assert.equal(this.session.keys.length, 0, 'no key added to session');

  xhrCalls[0].callback(null, response);

  assert.equal(this.session.keys.length, 1, 'key added to session');
  assert.deepEqual(this.session.keys[0], new Uint8Array(response.body), 'correct key added to session');

  _videoJs2['default'].log.error = origErrorLog;
  _videoJs2['default'].xhr = origXhr;
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/ms-prefixed":6,"./playready-message":13,"./utils":16,"global/window":3}],13:[function(require,module,exports){
'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _globalWindow = require('global/window');

var _globalWindow2 = _interopRequireDefault(_globalWindow);

var _utils = require('./utils');

var _utils2 = _interopRequireDefault(_utils);

var license = 'this is a license';

exports.license = license;
var challengeElement = '\n  <?xml version="1.0" encoding="utf-8"?>\n  <soap:Envelope\n    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"\n    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n    xmlns:xsd="http://www.w3.org/2001/XMLSchema">\n    <soap:Body>\n      <AcquireLicenseResponse xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols">\n        <AcquireLicenseResult>\n          <Response xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols/messages">\n            <LicenseResponse xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols">\n              <Version>1</Version>\n              <Licenses>\n                <License>' + license + '</License>\n              </Licenses>\n            </LicenseResponse>\n          </Response>\n        </AcquireLicenseResult>\n      </AcquireLicenseResponse>\n    </soap:Body>\n  </soap:Envelope>';

exports.challengeElement = challengeElement;
var defaultHeaders = [{
  name: 'Content-Type',
  value: 'text/xml; charset=utf-8'
}, {
  name: 'SOAPAction',
  value: '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
}];

var createHeaders = function createHeaders(headers) {
  return headers.reduce(function (acc, header) {
    return acc + ('\n      <HttpHeader>\n        <name>' + header.name + '</name>\n        <value>' + header.value + '</value>\n      </HttpHeader>\n    ');
  }, '');
};

var createMessageBuffer = function createMessageBuffer(headers) {
  headers = headers || defaultHeaders;

  // can't use TextEncoder because Safari doesn't support it
  return _utils2['default'].stringToArrayBuffer('\n    <PlayReadyKeyMessage type="LicenseAcquisition">\n      <LicenseAcquisition Version="1">\n        <Challenge encoding="base64encoded">' + _globalWindow2['default'].btoa(challengeElement) + '</Challenge>\n        <HttpHeaders>' + createHeaders(headers) + '</HttpHeaders>\n      </LicenseAcquisition>\n    </PlayReadyKeyMessage>');
};
exports.createMessageBuffer = createMessageBuffer;

},{"./utils":16,"global/window":3}],14:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _srcPlayready = require('../src/playready');

var _playreadyMessage = require('./playready-message');

_qunit2['default'].module('playready');

_qunit2['default'].test('getMessageContents parses message contents', function (assert) {
  var _getMessageContents = (0, _srcPlayready.getMessageContents)((0, _playreadyMessage.createMessageBuffer)());

  var headers = _getMessageContents.headers;
  var message = _getMessageContents.message;

  assert.deepEqual(headers, {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
  }, 'parses headers');
  assert.deepEqual(message, _playreadyMessage.challengeElement, 'parses challenge element');
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/playready":7,"./playready-message":13}],15:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _globalDocument = require('global/document');

var _globalDocument2 = _interopRequireDefault(_globalDocument);

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _sinon = (typeof window !== "undefined" ? window['sinon'] : typeof global !== "undefined" ? global['sinon'] : null);

var _sinon2 = _interopRequireDefault(_sinon);

var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);

var _videoJs2 = _interopRequireDefault(_videoJs);

var _srcPlugin = require('../src/plugin');

var _srcPlugin2 = _interopRequireDefault(_srcPlugin);

var Player = _videoJs2['default'].getComponent('Player');

_qunit2['default'].test('the environment is sane', function (assert) {
  assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists');
  assert.strictEqual(typeof _sinon2['default'], 'object', 'sinon exists');
  assert.strictEqual(typeof _videoJs2['default'], 'function', 'videojs exists');
  assert.strictEqual(typeof _srcPlugin2['default'], 'function', 'plugin is a function');
});

_qunit2['default'].module('videojs-contrib-eme', {
  beforeEach: function beforeEach() {
    // Mock the environment's timers because certain things - particularly
    // player readiness - are asynchronous in video.js 5. This MUST come
    // before any player is created; otherwise, timers could get created
    // with the actual timer methods!
    this.clock = _sinon2['default'].useFakeTimers();

    this.fixture = _globalDocument2['default'].getElementById('qunit-fixture');
    this.video = _globalDocument2['default'].createElement('video');
    this.fixture.appendChild(this.video);
    this.player = (0, _videoJs2['default'])(this.video);
  },

  afterEach: function afterEach() {
    this.player.dispose();
    this.clock.restore();
  }
});

_qunit2['default'].test('registers itself with video.js', function (assert) {
  assert.strictEqual(typeof Player.prototype.eme, 'function', 'videojs-contrib-eme plugin was registered');
});

_qunit2['default'].test('exposes options', function (assert) {
  assert.notOk(this.player.eme.options, 'options is unavailable at start');

  this.player.eme();
  assert.deepEqual(this.player.eme.options, {}, 'options defaults to empty object once initialized');

  this.video = _globalDocument2['default'].createElement('video');
  this.video.setAttribute('data-setup', JSON.stringify({
    plugins: {
      eme: {
        applicationId: 'application-id',
        publisherId: 'publisher-id'
      }
    }
  }));
  this.fixture.appendChild(this.video);
  this.player = (0, _videoJs2['default'])(this.video);

  assert.ok(this.player.eme.options, 'exposes options');
  assert.strictEqual(this.player.eme.options.applicationId, 'application-id', 'exposes applicationId');
  assert.strictEqual(this.player.eme.options.publisherId, 'publisher-id', 'exposes publisherId');
});

_qunit2['default'].module('plugin guard functions');

_qunit2['default'].test('handleEncryptedEvent checks for required options', function (assert) {
  var initData1 = new Uint8Array([1, 2, 3]).buffer;
  var event = {
    // mock video target to prevent errors since it's a pain to mock out the continuation
    // of functionality on a successful pass through of the guards
    target: {},
    initData: initData1
  };
  var options = {};
  var sessions = [];

  (0, _srcPlugin.handleEncryptedEvent)(event, options, sessions);
  assert.equal(sessions.length, 0, 'did not create a session when no options');

  options = { keySystems: {} };
  (0, _srcPlugin.handleEncryptedEvent)(event, options, sessions);
  assert.equal(sessions.length, 1, 'created a session when keySystems in options');
  assert.equal(sessions[0].initData, initData1, 'captured initData in the session');

  var initData2 = new Uint8Array([4, 5, 6]).buffer;

  event.initData = initData2;

  (0, _srcPlugin.handleEncryptedEvent)(event, options, sessions);
  assert.equal(sessions.length, 2, 'created a new session when new init data');
  assert.equal(sessions[0].initData, initData1, 'retained session init data');
  assert.equal(sessions[1].initData, initData2, 'added new session init data');

  event.initData = new Uint8Array([1, 2, 3]).buffer;

  (0, _srcPlugin.handleEncryptedEvent)(event, options, sessions);
  assert.equal(sessions.length, 2, 'no new session when same init data');
  assert.equal(sessions[0].initData, initData1, 'retained session init data');
  assert.equal(sessions[1].initData, initData2, 'retained session init data');
});

_qunit2['default'].test('handleMsNeedKeyEvent checks for required options', function (assert) {
  var event = {
    // mock video target to prevent errors since it's a pain to mock out the continuation
    // of functionality on a successful pass through of the guards
    target: {},
    initData: new Uint8Array([1, 2, 3])
  };
  var options = {};
  var sessions = [];

  (0, _srcPlugin.handleMsNeedKeyEvent)(event, options, sessions);
  assert.equal(sessions.length, 0, 'no session created when no options');

  options = { keySystems: {} };
  (0, _srcPlugin.handleMsNeedKeyEvent)(event, options, sessions);
  assert.equal(sessions.length, 0, 'no session created when no PlayReady key system');

  options = { keySystems: { 'com.microsoft.notplayready': true } };
  (0, _srcPlugin.handleMsNeedKeyEvent)(event, options, sessions);
  assert.equal(sessions.length, 0, 'no session created when no proper PlayReady key system');

  options = { keySystems: { 'com.microsoft.playready': true } };
  (0, _srcPlugin.handleMsNeedKeyEvent)(event, options, sessions);
  assert.equal(sessions.length, 1, 'session created');
  assert.ok(sessions[0].playready, 'created a PlayReady session');

  var createdSession = sessions[0];

  // even when there's new init data, we should not create a new session
  event.initData = new Uint8Array([4, 5, 6]);

  (0, _srcPlugin.handleMsNeedKeyEvent)(event, options, sessions);
  assert.equal(sessions.length, 1, 'no new session created');
  assert.equal(sessions[0], createdSession, 'did not replace session');
});

_qunit2['default'].test('handleWebKitNeedKeyEvent checks for required options', function (assert) {
  var event = {};
  var options = {};

  assert.notOk((0, _srcPlugin.handleWebKitNeedKeyEvent)(event, options), 'no return when no options');

  options = { keySystems: {} };
  assert.notOk((0, _srcPlugin.handleWebKitNeedKeyEvent)(event, options), 'no return when no FairPlay key system');

  options = { keySystems: { 'com.apple.notfps.1_0': {} } };
  assert.notOk((0, _srcPlugin.handleWebKitNeedKeyEvent)(event, options), 'no return when no proper FairPlay key system');

  options = { keySystems: { 'com.apple.fps.1_0': {} } };
  assert.ok((0, _srcPlugin.handleWebKitNeedKeyEvent)(event, options), 'valid return when proper FairPlay key system');
});

_qunit2['default'].module('plugin isolated functions');

_qunit2['default'].test('hasSession determines if a session exists', function (assert) {
  // cases in spec (where initData should always be an ArrayBuffer)
  var initData = new Uint8Array([1, 2, 3]).buffer;

  assert.notOk((0, _srcPlugin.hasSession)([], initData), 'false when no sessions');
  assert.ok((0, _srcPlugin.hasSession)([{ initData: initData }], initData), 'true when initData is present in a session');
  assert.ok((0, _srcPlugin.hasSession)([{}, { initData: new Uint8Array([1, 2, 3]).buffer }], initData), 'true when same initData contents present in a session');
  assert.notOk((0, _srcPlugin.hasSession)([{ initData: new Uint8Array([1, 2]).buffer }], initData), 'false when initData contents not present in a session');

  // cases outside of spec (where initData is not always an ArrayBuffer)
  assert.ok((0, _srcPlugin.hasSession)([{ initData: new Uint8Array([1, 2, 3]) }], initData), 'true even if session initData is a typed array and initData is an ArrayBuffer');
  assert.ok((0, _srcPlugin.hasSession)([{ initData: new Uint8Array([1, 2, 3]).buffer }], new Uint8Array([1, 2, 3])), 'true even if session initData is an ArrayBuffer and initData is a typed array');
  assert.ok((0, _srcPlugin.hasSession)([{ initData: new Uint8Array([1, 2, 3]) }], new Uint8Array([1, 2, 3])), 'true even if both session initData and initData are typed arrays');
});

_qunit2['default'].test('setupSessions sets up sessions for new sources', function (assert) {
  // mock the player with an eme plugin object attached to it
  var _src = 'some-src';
  var player = { eme: {}, src: function src() {
      return _src;
    } };

  (0, _srcPlugin.setupSessions)(player);

  assert.ok(Array.isArray(player.eme.sessions), 'creates a sessions array when none exist');
  assert.equal(player.eme.sessions.length, 0, 'sessions array is empty');
  assert.equal(player.eme.activeSrc, 'some-src', 'set activeSrc property');

  (0, _srcPlugin.setupSessions)(player);

  assert.equal(player.eme.sessions.length, 0, 'sessions array is still empty');
  assert.equal(player.eme.activeSrc, 'some-src', 'activeSrc property did not change');

  player.eme.sessions.push({});
  _src = 'other-src';
  (0, _srcPlugin.setupSessions)(player);

  assert.equal(player.eme.sessions.length, 0, 'sessions array reset');
  assert.equal(player.eme.activeSrc, 'other-src', 'activeSrc property changed');

  player.eme.sessions.push({});
  (0, _srcPlugin.setupSessions)(player);

  assert.equal(player.eme.sessions.length, 1, 'sessions array unchanged');
  assert.equal(player.eme.activeSrc, 'other-src', 'activeSrc property unchanged');
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/plugin":8,"global/document":2}],16:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
var stringToArrayBuffer = function stringToArrayBuffer(string) {
  var buffer = new ArrayBuffer(string.length * 2);
  var typedArray = new Uint16Array(buffer);

  for (var i = 0; i < string.length; i++) {
    typedArray[i] = string.charCodeAt(i);
  }

  return buffer;
};

exports["default"] = {
  stringToArrayBuffer: stringToArrayBuffer
};
module.exports = exports["default"];

},{}],17:[function(require,module,exports){
(function (global){
'use strict';

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _qunit = (typeof window !== "undefined" ? window['QUnit'] : typeof global !== "undefined" ? global['QUnit'] : null);

var _qunit2 = _interopRequireDefault(_qunit);

var _srcUtils = require('../src/utils');

_qunit2['default'].module('utils');

_qunit2['default'].test('arrayBuffersEqual checks if two array buffers are equal', function (assert) {
  assert.ok((0, _srcUtils.arrayBuffersEqual)(new ArrayBuffer(3), new ArrayBuffer(3)), 'same size empty array buffers are equal');
  assert.notOk((0, _srcUtils.arrayBuffersEqual)(new ArrayBuffer(2), new ArrayBuffer(3)), 'different size empty array buffers are not equal');

  var arrayBuffer = new ArrayBuffer(10);

  assert.ok((0, _srcUtils.arrayBuffersEqual)(arrayBuffer, arrayBuffer), 'same array buffer is equal');

  assert.ok((0, _srcUtils.arrayBuffersEqual)(new Uint8Array([1, 2, 3]).buffer, new Uint8Array([1, 2, 3]).buffer), 'array buffers with same content are equal');
  assert.notOk((0, _srcUtils.arrayBuffersEqual)(new Uint8Array([1, 2, 3]).buffer, new Uint8Array([1, 2, 4]).buffer), 'array buffers with different content are not equal');
  assert.notOk((0, _srcUtils.arrayBuffersEqual)(new Uint8Array([1, 2, 3]).buffer, new Uint8Array([1, 2]).buffer), 'array buffers with different content lengths are not equal');
});

_qunit2['default'].test('arrayBufferFrom returns buffer from typed arrays', function (assert) {
  var uint8Array = new Uint8Array([1, 2, 3]);
  var buffer = (0, _srcUtils.arrayBufferFrom)(uint8Array);

  assert.ok(buffer instanceof ArrayBuffer, 'returned an ArrayBuffer');
  assert.equal(buffer, uint8Array.buffer, 'buffer is the Uint8Array\'s buffer');

  var uint16Array = new Uint16Array([4, 5, 6]);

  buffer = (0, _srcUtils.arrayBufferFrom)(uint16Array);
  assert.ok(buffer instanceof ArrayBuffer, 'returned an ArrayBuffer');
  assert.equal(buffer, uint16Array.buffer, 'buffer is the Uint16Array\'s buffer');

  buffer = (0, _srcUtils.arrayBufferFrom)(buffer);
  assert.ok(buffer instanceof ArrayBuffer, 'buffer is still an ArrayBuffer');
  assert.equal(buffer, uint16Array.buffer, 'buffer is the same buffer');
});

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../src/utils":9}]},{},[10,11,12,14,15,17]);