Source: lib/mss/content_protection.js

/*! @license
 * Shaka Player
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

goog.provide('shaka.mss.ContentProtection');

goog.require('shaka.drm.PlayReady');
goog.require('shaka.util.ManifestParserUtils');
goog.require('shaka.util.Pssh');
goog.require('shaka.util.TXml');
goog.require('shaka.util.Uint8ArrayUtils');


/**
 * @summary A set of functions for parsing and interpreting Protection
 *   elements.
 */
shaka.mss.ContentProtection = class {
  /**
   * Parses info from the Protection elements.
   *
   * @param {!Array.<!shaka.extern.xml.Node>} elements
   * @param {!Object.<string, string>} keySystemsBySystemId
   * @return {!Array.<shaka.extern.DrmInfo>}
   */
  static parseFromProtection(elements, keySystemsBySystemId) {
    const ContentProtection = shaka.mss.ContentProtection;
    const TXml = shaka.util.TXml;

    /** @type {!Array.<!shaka.extern.xml.Node>} */
    let protectionHeader = [];
    for (const element of elements) {
      protectionHeader = protectionHeader.concat(
          TXml.findChildren(element, 'ProtectionHeader'));
    }
    if (!protectionHeader.length) {
      return [];
    }
    return ContentProtection.convertElements_(
        protectionHeader, keySystemsBySystemId);
  }

  /**
   * Gets a PlayReady license URL from a protection element
   * containing a PlayReady Header Object
   *
   * @param {!shaka.extern.xml.Node} element
   * @return {string}
   */
  static getPlayReadyLicenseUrl(element) {
    return shaka.drm.PlayReady.getLicenseUrl(element);
  }

  /**
   * Gets a PlayReady KID from a protection element
   * containing a PlayReady Header Object
   *
   * @param {!shaka.extern.xml.Node} element
   * @return {?string}
   * @private
   */
  static getPlayReadyKID_(element) {
    return shaka.drm.PlayReady.getPlayReadyKID(element);
  }

  /**
   * Gets a initData from a protection element.
   *
   * @param {!shaka.extern.xml.Node} element
   * @param {string} systemID
   * @param {?string} keyId
   * @return {?Array.<shaka.extern.InitDataOverride>}
   * @private
   */
  static getInitDataFromPro_(element, systemID, keyId) {
    const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
    const data = Uint8ArrayUtils.fromBase64(
        /** @type{string} */ (shaka.util.TXml.getTextContents(element)));
    const systemId = Uint8ArrayUtils.fromHex(systemID.replace(/-/g, ''));
    const keyIds = new Set();
    const psshVersion = 0;
    const pssh =
        shaka.util.Pssh.createPssh(data, systemId, keyIds, psshVersion);
    return [
      {
        initData: pssh,
        initDataType: 'cenc',
        keyId: keyId,
      },
    ];
  }

  /**
   * Creates DrmInfo objects from an array of elements.
   *
   * @param {!Array.<!shaka.extern.xml.Node>} elements
   * @param {!Object.<string, string>} keySystemsBySystemId
   * @return {!Array.<shaka.extern.DrmInfo>}
   * @private
   */
  static convertElements_(elements, keySystemsBySystemId) {
    const ContentProtection = shaka.mss.ContentProtection;
    const ManifestParserUtils = shaka.util.ManifestParserUtils;
    const licenseUrlParsers = ContentProtection.licenseUrlParsers_;

    /** @type {!Array.<shaka.extern.DrmInfo>} */
    const out = [];

    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      const systemID = element.attributes['SystemID'].toLowerCase();
      const keySystem = keySystemsBySystemId[systemID];
      if (keySystem) {
        const KID = ContentProtection.getPlayReadyKID_(element);
        const initData = ContentProtection.getInitDataFromPro_(
            element, systemID, KID);

        const info = ManifestParserUtils.createDrmInfo(
            keySystem, /* encryptionScheme= */ 'cenc', initData);
        if (KID) {
          info.keyIds.add(KID);
        }

        const licenseParser = licenseUrlParsers.get(keySystem);
        if (licenseParser) {
          info.licenseServerUri = licenseParser(element);
        }

        out.push(info);
      }
    }

    return out;
  }
};

/**
 * A map of key system name to license server url parser.
 *
 * @const {!Map.<string, function(!shaka.extern.xml.Node)>}
 * @private
 */
shaka.mss.ContentProtection.licenseUrlParsers_ = new Map()
    .set('com.microsoft.playready',
        shaka.mss.ContentProtection.getPlayReadyLicenseUrl)
    .set('com.microsoft.playready.recommendation',
        shaka.mss.ContentProtection.getPlayReadyLicenseUrl)
    .set('com.microsoft.playready.software',
        shaka.mss.ContentProtection.getPlayReadyLicenseUrl)
    .set('com.microsoft.playready.hardware',
        shaka.mss.ContentProtection.getPlayReadyLicenseUrl);