async init_(variants, isLive) {
    goog.asserts.assert(this.config_,
        'DrmEngine configure() must be called before init()!');

    shaka.drm.DrmEngine.configureClearKey(this.config_.clearKeys, variants);

    const hadDrmInfo = variants.some((variant) => {
      if (variant.video && variant.video.drmInfos.length) {
        return true;
      }
      if (variant.audio && variant.audio.drmInfos.length) {
        return true;
      }
      return false;
    });

    const servers = shaka.util.MapUtils.asMap(this.config_.servers);
    const advanced = shaka.util.MapUtils.asMap(this.config_.advanced || {});

    // When preparing to play live streams, it is possible that we won't know
    // about some upcoming encrypted content. If we initialize the drm engine
    // with no key systems, we won't be able to play when the encrypted content
    // comes.
    //
    // To avoid this, we will set the drm engine up to work with as many key
    // systems as possible so that we will be ready.
    if (!hadDrmInfo && isLive) {
      shaka.drm.DrmEngine.replaceDrmInfo_(variants, servers);
    }

    const drmInfos = new WeakSet();
    for (const variant of variants) {
      const variantDrmInfos = this.getVariantDrmInfos_(variant);
      for (const info of variantDrmInfos) {
        if (!drmInfos.has(info)) {
          drmInfos.add(info);
          shaka.drm.DrmEngine.fillInDrmInfoDefaults_(
              info, servers, advanced, this.config_.keySystemsMapping);
        }
      }
    }

    /** @type {!Map<string, MediaKeySystemConfiguration>} */
    let configsByKeySystem;

    /**
     * Expand robustness into multiple drm infos if multiple video robustness
     * levels were provided.
     *
     * robustness can be either a single item as a string or multiple items as
     * an array of strings.
     *
     * @param {!Array<shaka.extern.DrmInfo>} drmInfos
     * @param {string} robustnessType
     * @return {!Array<shaka.extern.DrmInfo>}
     */
    const expandRobustness = (drmInfos, robustnessType) => {
      const newDrmInfos = [];
      for (const drmInfo of drmInfos) {
        let items = drmInfo[robustnessType] ||
            (advanced.has(drmInfo.keySystem) &&
            advanced.get(drmInfo.keySystem)[robustnessType]) || '';
        if (items == '' &&
            shaka.drm.DrmUtils.isWidevineKeySystem(drmInfo.keySystem)) {
          if (robustnessType == 'audioRobustness') {
            items = [this.config_.defaultAudioRobustnessForWidevine];
          } else if (robustnessType == 'videoRobustness') {
            items = [this.config_.defaultVideoRobustnessForWidevine];
          }
        }
        if (typeof items === 'string') {
          // if drmInfo's robustness has already been expanded,
          // use the drmInfo directly.
          newDrmInfos.push(drmInfo);
        } else if (Array.isArray(items)) {
          if (items.length === 0) {
            items = [''];
          }
          for (const item of items) {
            newDrmInfos.push(
                Object.assign({}, drmInfo, {[robustnessType]: item}),
            );
          }
        }
      }
      return newDrmInfos;
    };

    const expandedStreams = new WeakSet();

    for (const variant of variants) {
      if (variant.video && !expandedStreams.has(variant.video)) {
        variant.video.drmInfos =
            expandRobustness(variant.video.drmInfos,
                'videoRobustness');
        variant.video.drmInfos =
            expandRobustness(variant.video.drmInfos,
                'audioRobustness');
        expandedStreams.add(variant.video);
      }
      if (variant.audio && !expandedStreams.has(variant.audio)) {
        variant.audio.drmInfos =
            expandRobustness(variant.audio.drmInfos,
                'videoRobustness');
        variant.audio.drmInfos =
            expandRobustness(variant.audio.drmInfos,
                'audioRobustness');
        expandedStreams.add(variant.audio);
      }
    }

    // We should get the decodingInfo results for the variants after we filling
    // in the drm infos, and before queryMediaKeys_().
    await shaka.util.StreamUtils.getDecodingInfosForVariants(variants,
        this.usePersistentLicenses_, this.srcEquals_,
        this.config_.preferredKeySystems);
    this.destroyer_.ensureNotDestroyed();

    const hasDrmInfo = hadDrmInfo || servers.size > 0;
    // An unencrypted content is initialized.
    if (!hasDrmInfo) {
      this.initialized_ = true;
      return Promise.resolve();
    }

    const p = this.queryMediaKeys_(configsByKeySystem, variants);

    // TODO(vaage): Look into the assertion below. If we do not have any drm
    // info, we create drm info so that content can play if it has drm info
    // later.
    // However it is okay if we fail to initialize? If we fail to initialize,
    // it means we won't be able to play the later-encrypted content, which is
    // not okay.

    // If the content did not originally have any drm info, then it doesn't
    // matter if we fail to initialize the drm engine, because we won't need it
    // anyway.
    return hadDrmInfo ? p : p.catch(() => {});
  }
Negotiate for a key system and set up MediaKeys.
This will assume that both |usePersistentLicences_| and
|storedPersistentSessions_| have been properly set.

@param {!Array<shaka.extern.Variant>} variants
   The variants that we expect to operate with during the drm engine's
   lifespan of the drm engine.
@param {boolean} isLive
@return {!Promise} Resolved if/when a key system has been chosen.
@private