Files
v10/internal/decisions/live-timeline-anchoring.md
T
Christian PillsburyandClaude Opus 4.8 f531e1055c docs(spf): decide the single presentation-level live timeline anchor
Capture the decision to hold one rolling (media-time ↔ PDT) anchor — learned
from the first A/V track to obtain SourceBuffer ground truth and applied to all
selected tracks (incl. text) by per-segment PDT — replacing today's per-track
buffer pins, which are redundant under the no-skew assumption and can't anchor
text (no SourceBuffer). New decision doc live-presentation-anchor.md; resolves
the deferred single-rolling-anchor question in live-timeline-anchoring and
promotes [4] in live-presentation-modeling to presentation-level.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:00:45 -07:00

100 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: decided
date: 2026-06-15
---
# Live timeline anchoring via PROGRAM-DATE-TIME
## Decision
Anchor the live timeline on `EXT-X-PROGRAM-DATE-TIME` (PDT), not on media
sequence number. PDT gives each segment an absolute wall-clock time (epoch
seconds) used for two things:
1. **Cross-track alignment** — demuxed audio and video are aligned by equal
PDT (same real instant), not by equal sequence number or per-track relative
`startTime`.
2. **Turnover recovery** — on a full live-window slide with no overlap, the
absolute `startTime` is recovered from PDT rather than estimated from
`targetDuration × offset`.
Scope of this decision: the **anchor source** is PDT. The parser *surfaces*
`Segment.programDateTime` (landed; see Verification). Whether the model holds a
single rolling anchor vs. per-segment measured times is **fixed in
[live-presentation-anchor](./live-presentation-anchor.md)** — a single
presentation-level `(media-time ↔ PDT)` anchor, learned from the first A/V
track to buffer and applied to all tracks (incl. text) by PDT. The remaining
per-track `presentationTimeOffset` derivation for the skew case is downstream
and not fixed here.
This resolves open questions **[4] sync anchor** and **turnover `startTime`
recovery** in
[live-presentation-modeling](../design/spf/live-presentation-modeling.md).
## Context
For demuxed live HLS, each track is parsed independently and its segment
`startTime`s accumulate from 0, so the same real instant lands at different
per-track `startTime`s (measured: a demuxed Mux CMAF stream put `segment-82` at
`startTime` 2 in video but 0 in audio — a 2 s A/V skew). Sequence number
identifies and orders segments but does not place them in time. The model needs
a shared, absolute anchor that survives variable durations and window turnover.
## Alternatives Considered
- **Sequence × duration.** Reconstruct a segment's time as
`(seq seq₀) × duration`. Rejected — it assumes uniform duration, which
fails three ways: (a) audio and video segment durations differ (AAC frames
are 1024 samples → a "2 s" audio segment is 2.005 s / 2.048 s, never the
video's exact duration), so the tracks drift apart; (b) manifests round
`EXTINF` (both Mux streams advertised integer durations over non-integer
media), compounding error; (c) once a segment rolls out of the window its
actual `EXTINF` is gone, so absolute time can't be reconstructed by summing.
PDT gives each in-window segment its own absolute time, immune to all three.
- **CMAF-HAM `presentationTimeOffset`.** Borrow the model shape from
common-media-library. Rejected as a *source* — HAM declares the field but
never populates it for HLS, its HLS mapper accumulates each track from 0
(same skew as ours), and it drops PDT entirely. We adopt the *name*
`presentationTimeOffset` for the per-track offset, not HAM's DASH-centric
(and unimplemented) derivation.
## Rationale
PDT is the mechanism RFC 8216 itself describes for correlating positions across
renditions (§4.3.2.6 associates a segment's first sample with absolute time).
It is optional in RFC 8216 but **required by Apple's HLS Authoring
Specification**, so it is reliably present on conformant content — Mux emits it
on every segment of both the TS and CMAF/LL-HLS profiles we captured. It is the
only anchor that is duration-variance-robust, survives window turnover, and is
already shared across tracks.
**Boundary.** PDT aligns the *manifest* timelines across tracks. It does not by
itself align the *buffer* (native-PTS) coordinate — that rides on CMAF's
common encoded presentation timeline plus the per-track offset learned from
`buffered`/`tfdt` (see [mse-timestamp-offset](./mse-timestamp-offset.md)). Two
distinct steps: PDT → shared manifest timeline (alignment); manifest → buffer
(the learned offset). PDT does the first only.
## Verification
`Segment.programDateTime` (epoch seconds) and PDT capture landed in the parser
(`parse-media-playlist.ts`), covered by `parse-media-playlist.test.ts`:
synthetic cases (capture, EXTINF forward-interpolation, re-anchor on an
explicit tag, variable-duration interpolation, absent-PDT → undefined) and real
Mux fixtures — the demuxed CMAF case asserts video/audio `segment-82` share PDT
while per-track `startTime` disagrees (2 vs 0). PDT-anchored placement and the
cross-track adjuster are not yet implemented.
## See also
- [live-presentation-anchor](./live-presentation-anchor.md) — fixes how this
anchor drives a single shared presentation timeline (the deferred
single-rolling-anchor question).
- [mse-timestamp-offset](./mse-timestamp-offset.md) — the buffer-layer half;
the manifest→buffer offset this decision's anchor feeds into.
- [live-presentation-modeling](../design/spf/live-presentation-modeling.md) —
open questions [4] and turnover recovery, resolved here.
- [non-zero-pts-support](../design/spf/features/non-zero-pts-support.md) —
consumes the offset-corrected timeline.