parseEventStream_(periodStart, periodDuration, elem, availabilityStart) {
    const TXml = shaka.util.TXml;
    const parseNumber = shaka.util.TXml.parseNonNegativeInt;

    const schemeIdUri = elem.attributes['schemeIdUri'] || '';
    const value = elem.attributes['value'] || '';
    const timescale = TXml.parseAttr(elem, 'timescale', parseNumber) || 1;
    const presentationTimeOffset =
      TXml.parseAttr(elem, 'presentationTimeOffset', parseNumber) || 0;

    for (const eventNode of TXml.findChildren(elem, 'Event')) {
      const presentationTime =
          TXml.parseAttr(eventNode, 'presentationTime', parseNumber) || 0;
      const duration =
          TXml.parseAttr(eventNode, 'duration', parseNumber) || 0;

      // Ensure start time won't be lower than period start.
      let startTime = Math.max(
          (presentationTime - presentationTimeOffset) / timescale + periodStart,
          periodStart);
      let endTime = startTime + (duration / timescale);
      if (periodDuration != null) {
        // An event should not go past the Period, even if the manifest says so.
        // See: Dash sec. 5.10.2.1
        startTime = Math.min(startTime, periodStart + periodDuration);
        endTime = Math.min(endTime, periodStart + periodDuration);
      }

      // Don't add unavailable regions to the timeline.
      if (endTime < availabilityStart) {
        continue;
      }

      /** @type {shaka.extern.TimelineRegionInfo} */
      const region = {
        schemeIdUri: schemeIdUri,
        value: value,
        startTime: startTime,
        endTime: endTime,
        id: eventNode.attributes['id'] || '',
        timescale: timescale,
        eventElement: TXml.txmlNodeToDomElement(eventNode),
        eventNode: TXml.cloneNode(eventNode),
      };

      this.playerInterface_.onTimelineRegionAdded(region);
    }
  }
Parses an EventStream element.

@param {number} periodStart
@param {?number} periodDuration
@param {!shaka.extern.xml.Node} elem
@param {number} availabilityStart
@private