async loadInner_(startTimeOfLoad, prefetchedVariant, segmentPrefetchById) {
    goog.asserts.assert(
        this.video_, 'We should have a media element by now.');
    goog.asserts.assert(
        this.manifest_, 'The manifest should already be parsed.');
    goog.asserts.assert(
        this.assetUri_, 'We should have an asset uri by now.');
    goog.asserts.assert(
        this.abrManager_, 'We should have an abr manager by now.');

    this.makeStateChangeEvent_('load');

    const mediaElement = this.video_;
    this.playRateController_ = new shaka.media.PlayRateController({
      getRate: () => mediaElement.playbackRate,
      getDefaultRate: () => mediaElement.defaultPlaybackRate,
      setRate: (rate) => { mediaElement.playbackRate = rate; },
      movePlayhead: (delta) => { mediaElement.currentTime += delta; },
    });

    // Add all media element listeners.
    this.addBasicMediaListeners_(mediaElement, startTimeOfLoad);

    if ('onchange' in window.screen) {
      this.loadEventManager_.listen(
          /** @type {EventTarget} */(window.screen), 'change', () => {
            if (this.currentAdaptationSetCriteria_.getConfiguration) {
              const config =
                  this.currentAdaptationSetCriteria_.getConfiguration();
              if (config.hdrLevel == 'AUTO') {
                this.updateAbrManagerVariants_();
              } else if (this.config_.preferredVideoHdrLevel == 'AUTO' &&
                  this.config_.abr.enabled) {
                config.hdrLevel = 'AUTO';
                this.currentAdaptationSetCriteria_.configure(config);
                this.updateAbrManagerVariants_();
              }
            }
          });
    }

    let isLcevcDualTrack = false;
    for (const variant of this.manifest_.variants) {
      const dependencyStream = variant.video && variant.video.dependencyStream;
      if (dependencyStream) {
        isLcevcDualTrack = shaka.lcevc.Dec.isStreamSupported(dependencyStream);
      }
    }

    // Check the status of the LCEVC Dec Object. Reset, create, or close
    // depending on the config.
    this.setupLcevc_(this.config_, isLcevcDualTrack);

    this.currentTextLanguage_ = this.config_.preferredTextLanguage;
    this.currentTextRole_ = this.config_.preferredTextRole;
    this.currentTextForced_ = this.config_.preferForcedSubs;

    shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
        this.config_.playRangeStart,
        this.config_.playRangeEnd);

    this.abrManager_.init((variant, clearBuffer, safeMargin) => {
      return this.switch_(variant, clearBuffer, safeMargin);
    });
    this.abrManager_.setMediaElement(mediaElement);
    this.abrManager_.setCmsdManager(this.cmsdManager_);

    this.streamingEngine_ = this.createStreamingEngine();
    this.streamingEngine_.configure(this.config_.streaming);

    // Set the load mode to "loaded with media source" as late as possible so
    // that public methods won't try to access internal components until
    // they're all initialized. We MUST switch to loaded before calling
    // "streaming" so that they can access internal information.
    this.loadMode_ = shaka.Player.LoadMode.MEDIA_SOURCE;

    // The event must be fired after we filter by restrictions but before the
    // active stream is picked to allow those listening for the "streaming"
    // event to make changes before streaming starts.
    this.dispatchEvent(shaka.Player.makeEvent_(
        shaka.util.FakeEvent.EventName.Streaming));

    // Pick the initial streams to play.
    // Unless the user has already picked a variant, anyway, by calling
    // selectVariantTrack before this loading stage.
    let initialVariant = prefetchedVariant;
    let toLazyLoad;
    let activeVariant;
    do {
      activeVariant = this.streamingEngine_.getCurrentVariant();
      if (!activeVariant && !initialVariant) {
        initialVariant = this.chooseVariant_();
        goog.asserts.assert(initialVariant, 'Must choose an initial variant!');
      }

      // Lazy-load the stream, so we will have enough info to make the playhead.
      const createSegmentIndexPromises = [];
      toLazyLoad = activeVariant || initialVariant;
      for (const stream of [toLazyLoad.video, toLazyLoad.audio]) {
        if (stream && !stream.segmentIndex) {
          createSegmentIndexPromises.push(stream.createSegmentIndex());
          if (stream.dependencyStream) {
            createSegmentIndexPromises.push(
                stream.dependencyStream.createSegmentIndex());
          }
        }
      }
      if (createSegmentIndexPromises.length > 0) {
        // eslint-disable-next-line no-await-in-loop
        await Promise.all(createSegmentIndexPromises);
      }
    } while (!toLazyLoad || toLazyLoad.disabledUntilTime != 0);

    if (this.parser_ && this.parser_.onInitialVariantChosen) {
      this.parser_.onInitialVariantChosen(toLazyLoad);
    }

    if (this.manifest_.isLowLatency) {
      if (this.config_.streaming.lowLatencyMode) {
        this.configure(this.lowLatencyConfig_);
      } else {
        shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
            'low-latency streaming mode is not enabled in Shaka Player. ' +
            'Set streaming.lowLatencyMode configuration to true, and see ' +
            'https://bit.ly/3clctcj for details.');
      }
    }

    if (this.cmcdManager_) {
      this.cmcdManager_.setLowLatency(
          this.manifest_.isLowLatency && this.config_.streaming.lowLatencyMode);
      this.cmcdManager_.setStartTimeOfLoad(startTimeOfLoad * 1000);
    }

    shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
        this.config_.playRangeStart,
        this.config_.playRangeEnd);

    this.streamingEngine_.applyPlayRange(
        this.config_.playRangeStart, this.config_.playRangeEnd);

    this.fullyLoaded_ = true;

    this.dispatchEvent(shaka.Player.makeEvent_(
        shaka.util.FakeEvent.EventName.CanUpdateStartTime));

    const setupPlayhead = (startTime) => {
      this.playhead_ = this.createPlayhead(startTime);
      this.playheadObservers_ =
          this.createPlayheadObserversForMSE_(startTime);

      this.startBufferManagement_(mediaElement, /* srcEquals= */ false);
    };

    if (!this.config_.streaming.startAtSegmentBoundary) {
      let startTime = this.startTime_;
      if (startTime == null && this.manifest_.startTime) {
        startTime = this.manifest_.startTime;
      }
      setupPlayhead(startTime);
    }

    // Now we can switch to the initial variant.
    if (!activeVariant) {
      goog.asserts.assert(initialVariant,
          'Must have chosen an initial variant!');

      // Now that we have initial streams, we may adjust the start time to
      // align to a segment boundary.
      if (this.config_.streaming.startAtSegmentBoundary) {
        const timeline = this.manifest_.presentationTimeline;
        let initialTime;
        if (this.startTime_ instanceof Date) {
          const presentationStartTime = timeline.getInitialProgramDateTime() ||
              timeline.getPresentationStartTime();
          goog.asserts.assert(presentationStartTime != null,
              'Presentation start time should not be null!');
          const time = (this.startTime_.getTime() / 1000.0) -
              presentationStartTime;
          if (time != null) {
            initialTime = time;
          }
        }
        if (initialTime == null) {
          initialTime = typeof this.startTime_ === 'number' ? this.startTime_ :
              this.video_.currentTime;
        }
        if (this.startTime_ == null && this.manifest_.startTime) {
          initialTime = this.manifest_.startTime;
        }
        const seekRangeStart = timeline.getSeekRangeStart();
        const seekRangeEnd = timeline.getSeekRangeEnd();
        if (initialTime < seekRangeStart) {
          initialTime = seekRangeStart;
        } else if (initialTime > seekRangeEnd) {
          initialTime = seekRangeEnd;
        }
        const startTime = await this.adjustStartTime_(
            initialVariant, initialTime);
        setupPlayhead(startTime);
      }

      this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
          /* clearBuffer= */ false, /* safeMargin= */ 0);
    }

    this.playhead_.ready();

    // Decide if text should be shown automatically.
    // similar to video/audio track, we would skip switch initial text track
    // if user already pick text track (via selectTextTrack api)
    const activeTextTrack = this.getTextTracks().find((t) => t.active);

    if (!activeTextTrack) {
      const initialTextStream = this.chooseTextStream_();

      if (initialTextStream) {
        this.addTextStreamToSwitchHistory_(
            initialTextStream, /* fromAdaptation= */ true);
      }

      if (initialVariant) {
        this.setInitialTextState_(initialVariant, initialTextStream);
      }

      // Don't initialize with a text stream unless we should be streaming
      // text.
      if (initialTextStream && this.shouldStreamText_()) {
        this.streamingEngine_.switchTextStream(initialTextStream);
        this.setTextDisplayerLanguage_();
      }
    }


    // Start streaming content. This will start the flow of content down to
    // media source.
    await this.streamingEngine_.start(segmentPrefetchById);

    if (this.config_.abr.enabled) {
      this.abrManager_.enable();
      this.onAbrStatusChanged_();
    }

    // Dispatch a 'trackschanged' event now that all initial filtering is
    // done.
    this.onTracksChanged_();

    // Now that we've filtered out variants that aren't compatible with the
    // active one, update abr manager with filtered variants.
    // NOTE: This may be unnecessary.  We've already chosen one codec in
    // chooseCodecsAndFilterManifest_ before we started streaming.  But it
    // doesn't hurt, and this will all change when we start using
    // MediaCapabilities and codec switching.
    // TODO(#1391): Re-evaluate with MediaCapabilities and codec switching.
    this.updateAbrManagerVariants_();

    const hasPrimary = this.manifest_.variants.some((v) => v.primary);
    if (!this.config_.preferredAudioLanguage && !hasPrimary) {
      shaka.log.warning('No preferred audio language set.  ' +
          'We have chosen an arbitrary language initially');
    }

    const isLive = this.isLive();

    if ((isLive && ((this.config_.streaming.liveSync &&
        this.config_.streaming.liveSync.enabled) ||
        this.manifest_.serviceDescription ||
        this.config_.streaming.liveSync.panicMode)) ||
        this.config_.streaming.vodDynamicPlaybackRate) {
      const onTimeUpdate = () => this.onTimeUpdate_();
      this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate);
    }
    if (!isLive) {
      const onVideoProgress = () => this.onVideoProgress_();
      this.loadEventManager_.listen(
          mediaElement, 'timeupdate', onVideoProgress);
      this.onVideoProgress_();
      if (this.manifest_.nextUrl) {
        if (this.config_.streaming.preloadNextUrlWindow > 0) {
          const onTimeUpdate = async () => {
            const timeToEnd = this.seekRange().end - this.video_.currentTime;
            if (!isNaN(timeToEnd)) {
              if (timeToEnd <= this.config_.streaming.preloadNextUrlWindow) {
                this.loadEventManager_.unlisten(
                    mediaElement, 'timeupdate', onTimeUpdate);
                goog.asserts.assert(this.manifest_.nextUrl,
                    'this.manifest_.nextUrl should be valid.');
                this.preloadNextUrl_ =
                    await this.preload(this.manifest_.nextUrl);
              }
            }
          };
          this.loadEventManager_.listen(
              mediaElement, 'timeupdate', onTimeUpdate);
        }
        this.loadEventManager_.listen(mediaElement, 'ended', () => {
          this.load(this.preloadNextUrl_ || this.manifest_.nextUrl);
        });
      }
    }

    if (this.adManager_) {
      this.adManager_.onManifestUpdated(isLive);
    }
  }
Starts loading the content described by the parsed manifest.

@param {number} startTimeOfLoad
@param {?shaka.extern.Variant} prefetchedVariant
@param {!Map<number, shaka.media.SegmentPrefetch>} segmentPrefetchById
@return {!Promise}
@private