async reset_(streamsByType) {
    if (this.reloadingMediaSource_ || this.usingRemotePlayback_) {
      return;
    }
    const ContentType = shaka.util.ManifestParserUtils.ContentType;
    this.reloadingMediaSource_ = true;
    this.needSplitMuxedContent_ = false;
    const currentTime = this.video_.currentTime;

    // When codec switching if the user is currently paused we don't want
    // to trigger a play when switching codec.
    // Playing can also end up in a paused state after a codec switch
    // so we need to remember the current states.
    const previousAutoPlayState = this.video_.autoplay;
    if (!this.video_.paused) {
      this.playAfterReset_ = true;
    }
    if (this.playbackHasBegun_) {
      // Only set autoplay to false if the video playback has already begun.
      // When a codec switch happens before playback has begun this can cause
      // autoplay not to work as expected.
      this.video_.autoplay = false;
    }

    try {
      this.eventManager_.removeAll();

      for (const transmuxer of this.transmuxers_.values()) {
        transmuxer.destroy();
      }
      for (const sourceBuffer of this.sourceBuffers_.values()) {
        try {
          this.mediaSource_.removeSourceBuffer(sourceBuffer);
        } catch (e) {
          shaka.log.debug('Exception on removeSourceBuffer', e);
        }
      }
      this.transmuxers_.clear();
      this.sourceBuffers_.clear();

      const previousDuration = this.mediaSource_.duration;
      this.mediaSourceOpen_ = new shaka.util.PublicPromise();
      this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
      await this.mediaSourceOpen_;
      if (!isNaN(previousDuration) && previousDuration) {
        this.mediaSource_.duration = previousDuration;
      } else if (!isNaN(this.lastDuration_) && this.lastDuration_) {
        this.mediaSource_.duration = this.lastDuration_;
      }

      const sourceBufferAdded = new shaka.util.PublicPromise();
      const sourceBuffers =
        /** @type {EventTarget} */(this.mediaSource_.sourceBuffers);

      const totalOfBuffers = streamsByType.size;
      let numberOfSourceBufferAdded = 0;
      const onSourceBufferAdded = () => {
        numberOfSourceBufferAdded++;
        if (numberOfSourceBufferAdded === totalOfBuffers) {
          sourceBufferAdded.resolve();
          this.eventManager_.unlisten(sourceBuffers, 'addsourcebuffer',
              onSourceBufferAdded);
        }
      };

      this.eventManager_.listen(sourceBuffers, 'addsourcebuffer',
          onSourceBufferAdded);

      for (const contentType of streamsByType.keys()) {
        const stream = streamsByType.get(contentType);
        this.initSourceBuffer_(contentType, stream, stream.codecs);
      }
      const audio = streamsByType.get(ContentType.AUDIO);
      if (audio && audio.isAudioMuxedInVideo) {
        this.needSplitMuxedContent_ = true;
      }
      if (this.needSplitMuxedContent_ && !this.queues_.has(ContentType.AUDIO)) {
        this.queues_.set(ContentType.AUDIO, []);
      }

      // Fake a seek to catchup the playhead.
      this.video_.currentTime = currentTime;

      await sourceBufferAdded;
    } finally {
      this.reloadingMediaSource_ = false;

      this.destroyer_.ensureNotDestroyed();

      this.eventManager_.listenOnce(this.video_, 'canplaythrough', () => {
        // Don't use ensureNotDestroyed() from this event listener, because
        // that results in an uncaught exception.  Instead, just check the
        // flag.
        if (this.destroyer_.destroyed()) {
          return;
        }

        this.video_.autoplay = previousAutoPlayState;
        if (this.playAfterReset_) {
          this.playAfterReset_ = false;
          this.video_.play();
        }
      });
    }
  }
Resets the MediaSource and re-adds source buffers due to codec mismatch

@param {!Map<shaka.util.ManifestParserUtils.ContentType,
              shaka.extern.Stream>} streamsByType
@private