In HLS live SSAI, Player.getContentPosition() jumps forward by the ad duration across EXT-X-DISCONTINUITY, breaking absolute playback-time calculation
Maintainers usually reply within 5 days
@marcbaechinger is already working on this.
Since Jul 1, 2026.
Assessment
This issue has not been assessed yet.
Description
Hello,
We have a question about computing playback time in HLS live SSAI (server-side ad insertion) with ExoPlayer/Media3.
Background / implementation
We fire SSAI tracking events (STARTED / COMPLETED, etc.) based on the playhead's absolute time. The value actually passed to the firing logic is getPlayingPositionUsingUtc(), computed as follows:
getCurrentPositionAsUTC() = lastWindowStartUnixTimeMs + Player.getContentPosition()
getPlayingPositionUsingUtc() = getCurrentPositionAsUTC() - firstManifestStartMs ← value used for event firing
lastWindowStartUnixTimeMs: the current window's start UTC, derived from the HLS EXT-X-PROGRAM-DATE-TIME (recomputed on every timeline update)
Player.getContentPosition(): content playback position within the window
firstManifestStartMs: the first manifest's start UTC (windowStartTimeMs, PDT-derived), captured once when SSAI playback starts. It is the origin of our SSAI coordinate system and is a fixed constant thereafter
We compare getPlayingPositionUsingUtc() (the elapsed time relative to the head of the first manifest) against the ad metadata's start/end times to fire events. Because firstManifestStartMs is a fixed constant, any jump introduced into Player.getContentPosition() propagates unchanged into getPlayingPositionUsingUtc().
Symptom
At the moment playback crosses an SSAI ad-insertion boundary (EXT-X-DISCONTINUITY), Player.getContentPosition() jumps forward within a single progress callback by roughly the ad duration (~9–9.4s in our measurements). For example, getContentPosition() went from 143612ms to 153302ms (+9384ms) in a single tick.
As a result, getCurrentPositionAsUTC() and getPlayingPositionUsingUtc() jump by the same amount, so the computed playhead time runs several seconds ahead of the video actually being displayed, and STARTED / COMPLETED fire several seconds before the ad video actually appears. Between ad breaks (segments not crossing a discontinuity), the value re-syncs to EXT-X-PROGRAM-DATE-TIME and the steady-state absolute time is accurate (residual ≈ 0 vs the live-edge PDT). The problem is localized to getContentPosition() losing continuity at the instant it crosses a discontinuity boundary.
Questions
Is it expected behavior for Player.getContentPosition() to jump forward by the ad duration when crossing an EXT-X-DISCONTINUITY (SSAI splice) in HLS live? Or is this a bug?
Is there a recommended API / approach to obtain a monotonic, continuous "content elapsed time" or "PDT-based absolute playback time" that remains correct across discontinuities (e.g. Timeline.Window.windowStartTimeMs plus some continuous position, getCurrentLiveOffset(), or a metadata/PDT-based computation)?
As a workaround, is it appropriate to use the raw audio playback clock (AudioTrack.getTimestamp() / AudioTrack.getPlaybackHeadPosition(), i.e. elapsed time based on the number of audio samples actually rendered) as the basis for measuring real playback progress? Specifically, we have observed that the audio clock advances smoothly (without jumping) across discontinuity boundaries, and we would like your opinion on whether using it as a substitute for getContentPosition() to drive ad-event progress is technically sound (with respect to A/V sync drift, handling of seeks / buffering / re-anchoring, validity for live, etc.).
Is there an officially recommended way to obtain a playback position that exactly matches the PTS/PDT of the frame currently being displayed in an SSAI stream (e.g. VideoFrameMetadataListener or a PROGRAM-DATE-TIME–based API)?
We can provide the logs and manifest excerpts needed to reproduce this. Thank you.
- Dominant language
- Java
- Stars
- 3.1k
- Forks
- 998
- Avg merge
- 8d 4h
- Merged PRs (30d)
- 5
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from androidx/media
-
Cast: system output switcher on Samsung One UI 9 (Android 17) only offers Samsung Audio Mirroring, never a Cast sessionPossibly taken @tanay187 claimed this today. Openbug cast needs triage
androidx/media#3500 · 3 comments · 2 assignees ·
Maintainers usually reply within 5 days
-
Waive ads when seek/start at the beginningPossibly taken @microkatz claimed this 2 days ago. Openenhancement
androidx/media#3496 · 3 comments · 1 assignee ·
Maintainers usually reply within 5 days
-
Since 1.9.0, skip buttons in SLOT_BACK / SLOT_FORWARD reach legacy controllers as custom actionsPossibly taken @marcbaechinger claimed this 2 days ago. Openbug
androidx/media#3495 · 1 comment · 1 assignee ·
Maintainers usually reply within 5 days
-
Allow configuring asset-list prefetch timing per HLS interstitialPossibly taken @marcbaechinger claimed this 3 days ago. Openenhancement
androidx/media#3494 · 3 comments · 1 assignee ·
Maintainers usually reply within 5 days
-
Offloaded audio left paused keeps AudioFlinger's AudioOffload wake lock forever, device never suspendsPossibly taken @microkatz claimed this 3 days ago. Openbug
androidx/media#3493 · 1 comment · 1 assignee ·
Maintainers usually reply within 5 days
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
breaking change bug needs human review not ready priority medium size S
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
martin-francois/symphony-trello#1193 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Mend: dependency security vulnerability
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100