Skip to content

onAdStarted() is not called between consecutive interstitial breaks #3013

Closed

Description

@work-keith

Version

Media3 1.9.0

More version details

No response

Devices that reproduce the issue

Android simulator(API 34) using media3 v1.9.0

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

If interstitial breaks are consecutive, HlsInterstitialsAdsLoader.Listener.onAdStarted() is not called at the beginning of the second and third breaks.

The breaks are defined in the manifest:

#EXT-X-DATERANGE:ID="47115_16_1",CLASS="com.apple.hls.interstitial",START-DATE="2025-12-11T14:16:00.000Z",DURATION=20.0,X-ASSET-URI="{$host}break/47115_16_1.m3u8{$sessionId}"
#EXT-X-DATERANGE:ID="47115_21_1",CLASS="com.apple.hls.interstitial",START-DATE="2025-12-11T14:16:20.000Z",DURATION=40.0,X-ASSET-URI="{$host}break/47115_21_1.m3u8{$sessionId}"
#EXT-X-DATERANGE:ID="47115_31_1",CLASS="com.apple.hls.interstitial",START-DATE="2025-12-11T14:17:00.000Z",DURATION=60.0,X-ASSET-URI="{$host}break/47115_31_1.m3u8{$sessionId}"
#EXT-X-DATERANGE:ID="47115_31_1",CLASS="com.apple.hls.interstitial",X-SNAP="IN"

Expected result

The sequence of callbacks should be like:

onAdStarted() --> break#1 --> onAdCompleted() --> onAdStarted() —> break#2 --> onAdCompleted() --> onAdStarted() —> break#3 --> onAdCompleted()

Actual result

Some of the onAdCompleted() are not called

onAdStarted() --> break#1 --> onAdCompleted() --> break#2 --> onAdCompleted() --> break#3 --> onAdCompleted()

Media

Sample stream URL is sent via email.

Bug Report

Activity

  1. marcbaechinger commented on Jan 19, 2026

    @marcbaechinger
    Contributor

    Thanks for your report.

    The callback isn't called because the ads are not properly played. We look into a fix for this. Once the ads are played as intended by the setup of this playlist the callbacks are called accordingly.

    For other readers, what is currently working, is putting all ads into a single ad group. This can be achieved by giving the same start position to all interstitials that should play consecutively without any primary content in between. This way ExoPlayer puts them into the same ad group and plays them as a group.

    The approach above that was reported as not working is valid as well, but it's broken atm. We look into a fix for that. In the meanwhile you can stick to the same-start-position approach to achieve a similar behavior.

  2. work-keith commented on Feb 9, 2026

    @work-keith
    Author

    Hi @marcbaechinger , thanks for acknowledging and working on this issue. I just wanted to check if there’s any update or timeline for a fix. Really appreciate your efforts!

  3. marcbaechinger commented on Feb 12, 2026

    @marcbaechinger
    Contributor

    I looked into this again.

    From the stream it looks to me that we have the configuration of two consecutive ad groups. The first ad group contains two ads with 20 and 40 seconds duration. The following ad group has a single ad with 60sec duration. Then there is 200sec of content before the next ad follows in the same structure as described above. The target duration of the stream is 4 secs.

    With this stream playback of the ads work as expected. As far as I can see playback of the ads works, but I also see that the onAdStarted() event is not emitted.

    Can you confirm that playback works for you and you are only missing the callback being invoked? That's the behavior I see with your stream.


    If we agree on the state of above, then I think I have located the problem. It is related with a timeline update that then advances the live window for a given duration (about the 4 seconds of the target duration of a segment). This causes a sudden change of the playing period which is reported as a discontinuity of type SKIP. This then isn't correctly recognized by the HlsInterstitialsAdLoader as an ad start and hence the callback isn't correctly called.

    I see several approaches to fix this and I'm currently figuring out what's the best way to do this. Please bare with me if it takes me some more time to look into this. Based on this I'm confident this will be fixed in the next release. In the meanwhile I'm thankful for your patience and the availability of the test stream so we can make this work.

  4. work-keith commented on Feb 12, 2026

    @work-keith
    Author

    Thanks for looking at this again.
    I can confirm that playback was fine. The onAdStarted() callbacks were missing for the second and third ads.

    Regarding the ad grouping, my understanding is that each ad belongs to its own ad group, rather than the configuration you observed, where the 20 and 40-second ads were grouped together and the 60-second ad formed a second group?

  5. marcbaechinger commented on Feb 13, 2026

    @marcbaechinger
    Contributor

    Thanks for confirming that playback works as expected.

    Regarding the grouping I think the problem is the current implementation of how X-SNAP="in" is implemented in ExoPlayer.

    The spec says:

    If the list contains IN then the client SHOULD locate the segment
    boundary closest to the scheduled resumption point from the
    interstitial in the Media Playlist of the primary content and
    resume playback of primary content at that boundary.  If more than
    one Media Playlist is contributing to playback, the client SHOULD
     transition at the latest segment boundary.
    

    I think my implementation of interpreting this part of is a bit naive (or lets say, it's just wrong). Currently the start position of the interstitial is determined by the start time of the segment closest to the resumption position from which the resume offset it subtracted. In the case of the configuration in your playlist for a live stream, this can not really work because at the moment the start position is calculated, the segment where the ad resumes to the content is not yet in the playlist (for live it's likely to be a point in time in the future). So currently it takes the end of the playlist and subtracts from there. Because this happens about 20 seconds after the previous ad with a duration of 20s, this snaps exactly to the same starting point as the previous ad. So they are grouped together.

    I think instead the logic for X-SNAP:in must keep the defined start position and adjust the resume offset of the ad instead to match to the start of given resumption segment. For a live stream, this also needs to be deferred to the moment when that segment actually is added to the playlist. It can't be done at the point in time when the interstitial is inserted.

    I'll follow up on this here in the thread when I have some changes pushed to the main branch.

    [1] https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-19#appendix-C

  6. marcbaechinger commented on Feb 20, 2026

    @marcbaechinger
    Contributor

    The two commits above should fix the problem. Thanks for your report! Very useful!
    I'm closing in the expectation that's fixed. Please open a new issue if you think something isn't right.

  7. locked and limited conversation to collaborators on Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions