async init(streamsByType, sequenceMode=false,
      manifestType=shaka.media.ManifestParser.UNKNOWN,
      ignoreManifestTimestampsInSegmentsMode=false) {
    const ContentType = shaka.util.ManifestParserUtils.ContentType;

    await this.mediaSourceOpen_;
    if (this.ended() || this.closed()) {
      shaka.log.alwaysError('Expected MediaSource to be open during init(); ' +
          'reopening the media source.');
      this.mediaSourceOpen_ = new shaka.util.PublicPromise();
      this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
      await this.mediaSourceOpen_;
    }

    this.sequenceMode_ = sequenceMode;
    this.manifestType_ = manifestType;
    this.ignoreManifestTimestampsInSegmentsMode_ =
      ignoreManifestTimestampsInSegmentsMode;

    this.attemptTimestampOffsetCalculation_ = !this.sequenceMode_ &&
        this.manifestType_ == shaka.media.ManifestParser.HLS &&
        !this.ignoreManifestTimestampsInSegmentsMode_;

    this.tsParsers_.clear();
    this.firstVideoTimestamp_ = null;
    this.firstVideoReferenceStartTime_ = null;
    this.firstAudioTimestamp_ = null;
    this.firstAudioReferenceStartTime_ = null;
    this.audioCompensation_ = new shaka.util.PublicPromise();

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

Note that it is not valid to call this multiple times, except to add or
reinitialize text streams.

@param {!Map<shaka.util.ManifestParserUtils.ContentType,
              shaka.extern.Stream>} streamsByType
  A map of content types to streams.
@param {boolean=} sequenceMode
  If true, the media segments are appended to the SourceBuffer in strict
  sequence.
@param {string=} manifestType
  Indicates the type of the manifest.
@param {boolean=} ignoreManifestTimestampsInSegmentsMode
  If true, don't adjust the timestamp offset to account for manifest
  segment durations being out of sync with segment durations. In other
  words, assume that there are no gaps in the segments when appending
  to the SourceBuffer, even if the manifest and segment times disagree.
  Indicates if the manifest has text streams.

@return {!Promise}