createStreamInfosForVariantTags_(tags, mediaTags, resolution, frameRate) {
    const ContentType = shaka.util.ManifestParserUtils.ContentType;

    /** @type {shaka.hls.HlsParser.StreamInfos} */
    const res = {
      audio: [],
      video: [],
    };
    const groupIdPathwayIdMapping = new Map();
    const globalGroupIds = [];
    let isAudioGroup = false;
    let isVideoGroup = false;
    for (const tag of tags) {
      const audioGroupId = tag.getAttributeValue('AUDIO');
      const videoGroupId = tag.getAttributeValue('VIDEO');
      goog.asserts.assert(audioGroupId == null || videoGroupId == null,
          'Unexpected: both video and audio described by media tags!');

      const groupId = audioGroupId || videoGroupId;
      if (!groupId) {
        continue;
      }
      if (!globalGroupIds.includes(groupId)) {
        globalGroupIds.push(groupId);
      }
      const pathwayId = tag.getAttributeValue('PATHWAY-ID');
      if (pathwayId) {
        groupIdPathwayIdMapping.set(groupId, pathwayId);
      }
      if (audioGroupId) {
        isAudioGroup = true;
      } else if (videoGroupId) {
        isVideoGroup = true;
      }
      // Make an educated guess about the stream type.
      shaka.log.debug('Guessing stream type for', tag.toString());
    }
    if (globalGroupIds.length && mediaTags.length) {
      const mediaTagsForVariant = mediaTags.filter((tag) => {
        return globalGroupIds.includes(tag.getRequiredAttrValue('GROUP-ID'));
      });
      this.createStreamInfosFromMediaTags_(
          mediaTagsForVariant, groupIdPathwayIdMapping);
    }
    const globalGroupId = globalGroupIds.sort().join(',');
    const streamInfos =
        (globalGroupId && this.groupIdToStreamInfosMap_.has(globalGroupId)) ?
        this.groupIdToStreamInfosMap_.get(globalGroupId) : [];
    if (isAudioGroup) {
      res.audio.push(...streamInfos);
    } else if (isVideoGroup) {
      res.video.push(...streamInfos);
    }

    let type;
    let ignoreStream = false;

    // The Microsoft HLS manifest generators will make audio-only variants
    // that link to their URI both directly and through an audio tag.
    // In that case, ignore the local URI and use the version in the
    // AUDIO tag, so you inherit its language.
    // As an example, see the manifest linked in issue #860.
    const allStreamUris = tags.map((tag) => tag.getRequiredAttrValue('URI'));
    const hasSameUri = res.audio.find((audio) => {
      return audio && audio.getUris().find((uri) => {
        return allStreamUris.includes(uri);
      });
    });

    /** @type {!Array<string>} */
    let allCodecs = this.getCodecsForVariantTag_(tags[0]);
    const videoCodecs = shaka.util.ManifestParserUtils.guessCodecsSafe(
        ContentType.VIDEO, allCodecs);
    const audioCodecs = shaka.util.ManifestParserUtils.guessCodecsSafe(
        ContentType.AUDIO, allCodecs);

    if (audioCodecs && !videoCodecs) {
      // There are no associated media tags, and there's only audio codec,
      // and no video codec, so it should be audio.
      type = ContentType.AUDIO;
      shaka.log.debug('Guessing audio-only.');
      ignoreStream = res.audio.length > 0;
    } else if (!res.audio.length && !res.video.length &&
        audioCodecs && videoCodecs) {
      // There are both audio and video codecs, so assume multiplexed content.
      // Note that the default used when CODECS is missing assumes multiple
      // (and therefore multiplexed).
      // Recombine the codec strings into one so that MediaSource isn't
      // lied to later. (That would trigger an error in Chrome.)
      shaka.log.debug('Guessing multiplexed audio+video.');
      type = ContentType.VIDEO;
      allCodecs = [[videoCodecs, audioCodecs].join(',')];
    } else if (res.audio.length && hasSameUri) {
      shaka.log.debug('Guessing audio-only.');
      type = ContentType.AUDIO;
      ignoreStream = true;
    } else if (res.video.length && !res.audio.length) {
      // There are associated video streams.  Assume this is audio.
      shaka.log.debug('Guessing audio-only.');
      type = ContentType.AUDIO;
    } else {
      shaka.log.debug('Guessing video-only.');
      type = ContentType.VIDEO;
    }

    if (!ignoreStream) {
      const streamInfo =
          this.createStreamInfoFromVariantTags_(tags, allCodecs, type);
      if (globalGroupId) {
        streamInfo.stream.groupId = globalGroupId;
      }
      res[streamInfo.stream.type] = [streamInfo];
    }
    return res;
  }
Create audio and video streamInfos from an 'EXT-X-STREAM-INF' tag and its
related media tags.

@param {!Array<!shaka.hls.Tag>} tags
@param {!Array<!shaka.hls.Tag>} mediaTags
@param {?string} resolution
@param {?string} frameRate
@return {!shaka.hls.HlsParser.StreamInfos}
@private