In HLS live SSAI, Player.getContentPosition() jumps forward by the ad duration across EXT-X-DISCONTINUITY, breaking absolute playback-time calculation
I maintainer di solito rispondono entro 5 giorni
@marcbaechinger ci sta già lavorando.
Dal 1/7/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
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.
- Lingua principale
- Java
- Stelle
- 3.1k
- Fork
- 998
- Merge medio
- 8g 4h
- PR unite (30g)
- 5
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di androidx/media
-
Cast: system output switcher on Samsung One UI 9 (Android 17) only offers Samsung Audio Mirroring, never a Cast sessionForse già presa @tanay187 l’ha presa 1 giorno fa. Apertabug cast needs triage
androidx/media#3500 · 3 commenti · 2 assegnatari ·
I maintainer di solito rispondono entro 5 giorni
-
Waive ads when seek/start at the beginningForse già presa @microkatz l’ha presa 3 giorni fa. Apertaenhancement
androidx/media#3496 · 3 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
-
Since 1.9.0, skip buttons in SLOT_BACK / SLOT_FORWARD reach legacy controllers as custom actionsForse già presa @marcbaechinger l’ha presa 2 giorni fa. Apertabug
androidx/media#3495 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
-
Allow configuring asset-list prefetch timing per HLS interstitialForse già presa @marcbaechinger l’ha presa 3 giorni fa. Apertaenhancement
androidx/media#3494 · 3 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
-
Offloaded audio left paused keeps AudioFlinger's AudioOffload wake lock forever, device never suspendsForse già presa @microkatz l’ha presa 3 giorni fa. Apertabug
androidx/media#3493 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
Tutte le issue di androidx/media
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
quarkusio/quarkus-agent-mcp#302 ·
I maintainer di solito rispondono entro 2 giorni
-
build
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
MetricsHub/metricshub-community#1472 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
IdentityArrayObjectSet iterator remove may throw ArrayIndexOutOfBoundsExceptionForse già presa @jiteshkhatri11 l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
javapathfinder/jpf-core#660 · 1 commento ·