Skip to content

Custom AdsLoader: no supported way to play a skipped-over midroll without breaking AdPlaybackState invariants #3424

Open

Description

@flujan-bedrock

Media3 version

  • 1.11.x (AdsMediaSource / AdPlaybackState)

Desired behaviour (force-play the last missed ad break after a seek)

Cues at 10 / 20 / 30 / 40 min. User starts at 5 min, seeks to 35 min. We want to play the last skipped break (30 min), resume at 35 min, keep 10/20 rewindable, and play 40 min once on the normal AdsLoader path.

Wanted:

  • [10] [20] still playable if user seeks back
  • [30] played after the seek
  • [40] untouched, AdsMediaSource when playhead reaches it

How we build AdPlaybackState today

Media3 1.6+ (checkValidAdPlaybackStateUpdate): timeUs immutable, groups append-only, times must stay sorted (getAdGroupIndexForPositionUs walks from the last index). count = UNSET at the playhead stalls forever; count = 0 is a skipped placeholder that may grow (0 → N + URIs).
At start we publish one group per cue, sorted, at the real times :

  • Cold start (playhead = 0)

    • t=0 preroll count = UNSET → AdsMediaSource waits, we resolve VAST then fill or skip
    • t=10m midroll count = 0 → content plays through
    • t=20m midroll count = 0
    • t=30m midroll count = 0
    • t=40m midroll count = 0
  • Continue watching (bookmark = 12 min)

    • t=0 skipped / unused preroll at 0
    • t=10m midroll count = 0
    • t=12m resume preroll slot count = UNSET ← bookmark is in the initial sorted list
    • t=20m midroll count = 0
    • t=30m midroll count = 0
    • t=40m midroll count = 0

• Midrolls: count = 0 from launch so content is not blocked; AdsMediaSource can createPeriod at the real cue.
• 3–10 s before a cue we resolve VAST and grow that placeholder (count + media). We never move timeUs.
• Resume: a preroll at t=0 is ignored behind the playhead. We put the bookmark in the first sorted AdPlaybackState(...) (not appended later — that would sit after 40 min and hide midrolls). That slot stays UNSET until VAST, then we fill or skip.

Natural playback works. Force-play the last missed ad break after a seek does not.

What we cannot do

  1. Move the 30 min group to playhead + 1 after 5→35 ->crash.
  2. Rewrite all midroll timeUs after the seek — forbidden.
    -> 40 min already exists → append at ~35 min inserts a time before 40 min → unsorted / wrong index
  3. Insert a group at the playhead — same case, forbidden (shifts later indexes).

Question

Do you see a way to implement this on top of the model above (real cue times, midrolls count = 0, UNSET preroll at 0 or bookmark, fill in the preload window) without breaking checkValidAdPlaybackStateUpdate?
In particular:
• After a user seek, can we play the last skipped-over midroll and then resume at the seek position, while later cues (e.g. 40 min) stay on the normal AdsMediaSource path?
• Is anything planned in this area (seek vs behind-playhead groups)?

Thank you in advance for your help and for taking the time to respond.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions