syncStreamsWithProgramDateTime_(streamInfos) {
    // We assume that, when this is first called, we have enough info to
    // determine how to use the program date times (e.g. we have both a video
    // and an audio, and all other videos and audios match those).
    // Thus, we only need to calculate this once.
    if (this.lowestSyncTime_ == Infinity) {
      for (const streamInfo of streamInfos) {
        const segmentIndex = streamInfo.stream.segmentIndex;
        goog.asserts.assert(segmentIndex,
            'Only loaded streams should be synced');
        const segment0 = segmentIndex.earliestReference();
        if (segment0 != null && segment0.syncTime != null) {
          this.lowestSyncTime_ =
              Math.min(this.lowestSyncTime_, segment0.syncTime);
        }
      }
    }

    const lowestSyncTime = this.lowestSyncTime_;
    if (lowestSyncTime == Infinity) {
      // Nothing to sync.
      return;
    }

    shaka.log.debug('Syncing HLS streams against base time:', lowestSyncTime);

    for (const streamInfo of this.uriToStreamInfosMap_.values()) {
      if (this.ignoreManifestProgramDateTimeFor_(streamInfo.type)) {
        continue;
      }
      const segmentIndex = streamInfo.stream.segmentIndex;
      if (segmentIndex != null) {
        // A segment's startTime should be based on its syncTime vs the lowest
        // syncTime across all streams.  The earliest segment sync time from
        // any stream will become presentation time 0.  If two streams start
        // e.g. 6 seconds apart in syncTime, then their first segments will
        // also start 6 seconds apart in presentation time.

        const segment0 = segmentIndex.earliestReference();
        if (!segment0) {
          continue;
        }
        if (segment0.syncTime == null) {
          shaka.log.alwaysError('Missing EXT-X-PROGRAM-DATE-TIME for stream',
              streamInfo.getUris(),
              'Expect AV sync issues!');
        } else {
          // Stream metadata are offset by a fixed amount based on the
          // first segment.
          const segment0TargetTime = segment0.syncTime - lowestSyncTime;
          const streamOffset = segment0TargetTime - segment0.startTime;
          this.offsetStreamInfo_(streamInfo, streamOffset);

          // This is computed across all segments separately to manage
          // accumulated drift in durations.
          for (const segment of segmentIndex) {
            segment.syncAgainst(lowestSyncTime);
          }
        }
      }
    }
  }
Synchronize streams by the EXT-X-PROGRAM-DATE-TIME tags attached to their
segments.  Also normalizes segment times so that the earliest segment in
any stream is at time 0.
@param {!Array<!shaka.hls.HlsParser.StreamInfo>} streamInfos
@private