async destroyNow_() {
    // |eventManager_| should only be |null| after we call |destroy|. Destroy it
    // first so that we will stop responding to events.
    this.eventManager_.release();
    this.eventManager_ = null;

    // Since we are destroying ourselves, we don't want to react to the "all
    // sessions loaded" event.
    this.allSessionsLoaded_.reject();

    // Stop all timers. This will ensure that they do not start any new work
    // while we are destroying ourselves.
    this.expirationTimer_.stop();
    this.expirationTimer_ = null;

    this.keyStatusTimer_.stop();
    this.keyStatusTimer_ = null;

    // Close all open sessions.
    await this.closeOpenSessions_();

    // |video_| will be |null| if we never attached to a video element.
    if (this.video_) {
      // Webkit EME implementation requires the src to be defined to clear
      // the MediaKeys.
      if (!shaka.drm.DrmUtils.isMediaKeysPolyfilled('webkit')) {
        goog.asserts.assert(
            !this.video_.src &&
            !this.video_.getElementsByTagName('source').length,
            'video src must be removed first!');
      }

      try {
        await this.video_.setMediaKeys(null);
      } catch (error) {
        // Ignore any failures while removing media keys from the video element.
        shaka.log.debug(`DrmEngine.destroyNow_ exception`, error);
      }

      this.video_ = null;
    }

    // Break references to everything else we hold internally.
    this.currentDrmInfo_ = null;
    this.mediaKeys_ = null;
    this.storedPersistentSessions_ = new Map();
    this.config_ = null;
    this.onError_ = () => {};
    this.playerInterface_ = null;
    this.srcEquals_ = false;
    this.mediaKeysAttached_ = null;
  }
Destroy this instance of DrmEngine. This assumes that all other checks
about "if it should" have passed.

@private