Skip to content

Improved Handling of SCTE-35 Cues for HLS Live Streams #9828

@grushetsky

Description

@grushetsky

Have you read the FAQ and checked for duplicate open issues?
Yes, nothing related was discovered.

Is your feature request related to a problem? Please describe.
It is not possible to reliably schedule ads based on SCTE-35 markers (#EXT-X-DATERANGE) for an HLS Live stream from within metadataadded event handler.

Describe the solution you'd like
I would like to receive timelineregionadded event for an HLS Live stream just like it happens for a DASH Live stream. The timelineregionadded event's detail field contains everything needed for the scheduler to work (ID, start timestamp, end timestamp) in my case. Here's an example of how this event is used for scheduling:

player.addEventListener(`timelineregionadded`, event => {
  /* `timelineregionadded` event example
    {

      detail: {
        endTime: 1773168617.229,
        id: '123487'
        schemeIdUri: 'urn:scte35:2014',
        startTime: 1773168467.229,

      },
      isTrusted: false,
      timeStamp: 72384.100202,
      type: 'timelineregionadded'
    }
  */

  scheduleAd({
    id: event.detail.id,
    startTs: event.detail.startTime * 1000,
    endTs: event.detail.endTime * 1000
  });
});

An alternative approach is to extend the metadataadded event to include the initial program time (along with marker ID value), enabling the calculation of the start date as startTime + initialProgramTime.

Describe alternatives you've considered
The absolute start time for an SCTE-35 cue is defined in START-DATE attribute of EXT-X-DATERANGE tag, but the attribute is excluded from the attributes for which metadataadded is emitted. Thus, it's not available in metadataadded handler.

The other way to calculate the start date is by adding startTime to the value of the initial program time retrieved from getPresentationStartTimeAsDate(). But this approach is unreliable because manifest parsing might still be in progress when the event metadataadded fires (getPresentationStartTimeAsDate() returns null in this case). Additionally, there are discontinuities of HLS Live streams.

I also considered using video text tracks cues, but those weren't available in my case for some reason.

Additional context
Here's an example of a playlist with an SCTE-35 marker:

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:5
#EXT-X-PROGRAM-DATE-TIME:2026-03-13T18:42:32.426+00:00
#EXTINF:5,
video.ts
#EXT-X-DATERANGE:ID="my-id",START-DATE="2026-03-13T18:43:26.705Z",PLANNED-DURATION=30
#EXTINF:5,
video.ts
#EXTINF:5,
video.ts

In order to schedule the upcoming ad for a live stream one needs to know the absolute time the ad starts. metadataadded event contains startTime property representing the amount of seconds passed from the start of the current playlist (startTime value is calculated internally as startDate - initialProgramDateTime), but it is not enough for reliable scheduling, because there might exist multiple EXT-X-DATERANGE tags related to the same ad in the upcoming playlist files and the scheduler can't rely on relative time.

Another alternative solution is to stop excluding START-DATE from the emitted attributes. The handler would look like this:

player.addEventListener('metadataadded', event => {
  if (event.payload.key === 'START-DATE') {
    const adStartDate = event.payload.data;

    scheduleAd({
      id: ,
      startTs: dayjs(adStartDate).unix(),
      endTs: dayjs(adStartDate).add(event.endTime, 'second').unix()
    });
});

However, this approach is less convenient because the event is emitted for every single attribute, making it impossible to correlate the ID with the START-DATE in the same handler invocation.

Are you planning to send a PR to add it?
Yes, it's on its way.

Metadata

Metadata

Assignees

Labels

component: HLSThe issue involves Apple's HLS manifest formatpriority: P3Useful but not urgenttype: enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions