async unload(initializeMediaSource = true, keepAdManager = false) {
    // Set the load mode to unload right away so that all the public methods
    // will stop using the internal components. We need to make sure that we
    // are not overriding the destroyed state because we will unload when we are
    // destroying the player.
    if (this.loadMode_ != shaka.Player.LoadMode.DESTROYED) {
      this.loadMode_ = shaka.Player.LoadMode.NOT_LOADED;
    }

    if (await this.atomicOperationAcquireMutex_('unload')) {
      return;
    }

    try {
      this.fullyLoaded_ = false;
      this.makeStateChangeEvent_('unload');

      // If LCEVC Decoder exists close it.
      this.closeLcevcDec_();

      // Run any general cleanup tasks now.  This should be here at the top,
      // right after setting loadMode_, so that internal components still exist
      // as they did when the cleanup tasks were registered in the array.
      const cleanupTasks = this.cleanupOnUnload_.map((cb) => cb());
      this.cleanupOnUnload_ = [];
      await Promise.all(cleanupTasks);

      // Dispatch the unloading event.
      this.dispatchEvent(
          shaka.Player.makeEvent_(shaka.util.FakeEvent.EventName.Unloading));

      // Release the region timeline, which is created when parsing the
      // manifest.
      if (this.regionTimeline_) {
        this.regionTimeline_.release();
        this.regionTimeline_ = null;
      }
      if (this.metadataRegionTimeline_) {
        this.metadataRegionTimeline_.release();
        this.metadataRegionTimeline_ = null;
      }
      if (this.emsgRegionTimeline_) {
        this.emsgRegionTimeline_.release();
        this.emsgRegionTimeline_ = null;
      }

      // In most cases we should have a media element. The one exception would
      // be if there was an error and we, by chance, did not have a media
      // element.
      if (this.video_) {
        this.loadEventManager_.removeAll();
        this.trickPlayEventManager_.removeAll();
      }

      // Stop the variant checker timer
      this.checkVariantsTimer_.stop();

      // Some observers use some playback components, shutting down the
      // observers first ensures that they don't try to use the playback
      // components mid-destroy.
      if (this.playheadObservers_) {
        this.playheadObservers_.release();
        this.playheadObservers_ = null;
      }

      if (this.bufferPoller_) {
        this.bufferPoller_.stop();
        this.bufferPoller_ = null;
      }

      // Stop the parser early. Since it is at the start of the pipeline, it
      // should be start early to avoid is pushing new data downstream.
      if (this.parser_) {
        await this.parser_.stop();
        this.parser_ = null;
        this.parserFactory_ = null;
      }

      // Abr Manager will tell streaming engine what to do, so we need to stop
      // it before we destroy streaming engine. Unlike with the other
      // components, we do not release the instance, we will reuse it in later
      // loads.
      if (this.abrManager_) {
        await this.abrManager_.stop();
      }

      // Streaming engine will push new data to media source engine, so we need
      // to shut it down before destroy media source engine.
      if (this.streamingEngine_) {
        await this.streamingEngine_.destroy();
        this.streamingEngine_ = null;
      }

      if (this.playRateController_) {
        this.playRateController_.release();
        this.playRateController_ = null;
      }

      // Playhead is used by StreamingEngine, so we can't destroy this until
      // after StreamingEngine has stopped.
      if (this.playhead_) {
        this.playhead_.release();
        this.playhead_ = null;
      }

      // EME v0.1b requires the media element to clear the MediaKeys
      if (shaka.drm.DrmUtils.isMediaKeysPolyfilled('webkit') &&
          this.drmEngine_) {
        await this.drmEngine_.destroy();
        this.drmEngine_ = null;
      }

      // Media source engine holds onto the media element, and in order to
      // detach the media keys (with drm engine), we need to break the
      // connection between media source engine and the media element.
      if (this.mediaSourceEngine_) {
        await this.mediaSourceEngine_.destroy();
        this.mediaSourceEngine_ = null;
      }

      if (this.adManager_ && !keepAdManager) {
        this.adManager_.onAssetUnload();
      }

      if (this.preloadDueAdManager_ && !keepAdManager) {
        this.preloadDueAdManager_.destroy();
        this.preloadDueAdManager_ = null;
      }

      if (!keepAdManager) {
        this.preloadDueAdManagerTimer_.stop();
      }

      if (this.cmcdManager_) {
        this.cmcdManager_.reset();
      }

      if (this.cmsdManager_) {
        this.cmsdManager_.reset();
      }

      if (this.textDisplayer_) {
        await this.textDisplayer_.destroy();
        this.textDisplayer_ = null;
      }

      if (this.video_) {
        // The life cycle of tracks that created by addTextTrackAsync() and
        // their associated resources should be the same as the loaded video.
        for (const trackNode of this.externalSrcEqualsTextTracks_) {
          if (trackNode.src.startsWith('blob:')) {
            URL.revokeObjectURL(trackNode.src);
          }
          trackNode.remove();
        }
        this.externalSrcEqualsTextTracks_ = [];

        // In order to unload a media element, we need to remove the src
        // attribute and then load again. When we destroy media source engine,
        // this will be done for us, but for src=, we need to do it here.
        //
        // DrmEngine requires this to be done before we destroy DrmEngine
        // itself.
        if (shaka.util.Dom.clearSourceFromVideo(this.video_)) {
          this.video_.load();
        }
      }

      if (this.drmEngine_) {
        await this.drmEngine_.destroy();
        this.drmEngine_ = null;
      }

      if (this.preloadNextUrl_ &&
          this.assetUri_ != this.preloadNextUrl_.getAssetUri()) {
        if (!this.preloadNextUrl_.isDestroyed()) {
          this.preloadNextUrl_.destroy();
        }
        this.preloadNextUrl_ = null;
      }

      this.assetUri_ = null;
      this.mimeType_ = null;
      this.bufferObserver_ = null;

      if (this.manifest_) {
        for (const variant of this.manifest_.variants) {
          for (const stream of [variant.audio, variant.video]) {
            if (stream && stream.segmentIndex) {
              stream.segmentIndex.release();
            }
          }
        }
        for (const stream of this.manifest_.textStreams) {
          if (stream.segmentIndex) {
            stream.segmentIndex.release();
          }
        }
      }

      // On some devices, cached MediaKeySystemAccess objects may corrupt
      // after several playbacks, and they are not able anymore to properly
      // create MediaKeys objects. To prevent it, clear the cache after
      // each playback.
      if (this.config_ && this.config_.streaming.clearDecodingCache) {
        shaka.util.StreamUtils.clearDecodingConfigCache();
        shaka.drm.DrmUtils.clearMediaKeySystemAccessMap();
      }

      this.manifest_ = null;
      this.stats_ = new shaka.util.Stats(); // Replace with a clean object.
      this.lastTextFactory_ = null;

      this.targetLatencyReached_ = null;
      this.currentTargetLatency_ = null;
      this.rebufferingCount_ = -1;

      this.externalSrcEqualsThumbnailsStreams_ = [];
      this.externalChaptersStreams_ = [];

      this.completionPercent_ = -1;

      if (this.networkingEngine_) {
        this.networkingEngine_.clearCommonAccessTokenMap();
      }

      // Make sure that the app knows of the new buffering state.
      this.updateBufferState_();
    } finally {
      this.mutex_.release();
    }

    const device = shaka.device.DeviceFactory.getDevice();
    if (initializeMediaSource && device.supportsMediaSource() &&
        !this.mediaSourceEngine_ && this.video_) {
      await this.initializeMediaSourceEngineInner_();
    }
  }
Unloads the currently playing stream, if any.

@param {boolean=} initializeMediaSource
@param {boolean=} keepAdManager
@return {!Promise}
@export