mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
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>
122 lines
5.9 KiB
Markdown
122 lines
5.9 KiB
Markdown
---
|
||
status: decided
|
||
date: 2026-06-24
|
||
---
|
||
|
||
# Single presentation-level live timeline anchor
|
||
|
||
## Decision
|
||
|
||
Hold **one** rolling presentation-level anchor — a `(media-time ↔ PDT)`
|
||
correspondence — and apply it to **every** selected track, rather than pinning
|
||
each track to its own buffer.
|
||
|
||
The anchor is **learned from whichever selected audio/video track first has
|
||
SourceBuffer ground truth**: the buffer pin (`resolveBufferedAnchor`) reports a
|
||
buffered segment's actual native-PTS start `M₀`, paired with that segment's PDT
|
||
`P₀`. From that one pair, any track's segment is placed by its own PDT:
|
||
|
||
```
|
||
segment.startTime = M₀ + (segment.programDateTime − P₀)
|
||
```
|
||
|
||
Established **once** per source (pin-once — it surfaces drift rather than
|
||
masking it; the parser's PDT carry-forward maintains the timeline across
|
||
reloads). Before any A/V track has buffer ground truth, the manifest estimate
|
||
(the existing bootstrap) supplies an *estimated* anchor of the same shape, which
|
||
the buffer pin later upgrades.
|
||
|
||
This anchor covers **text tracks too** — they have no SourceBuffer to pin, so
|
||
the shared anchor is the *only* way to place them. WebVTT cues are assumed
|
||
already time-aligned (the analog of assuming encoded A/V samples are aligned);
|
||
what we align is the text track's **segment** timeline, by PDT, exactly as for
|
||
A/V. (That cues are sparse/overlapping — a cue may begin or end outside its
|
||
segment's nominal bounds — is a text *loader/eviction* concern, not an
|
||
anchoring one.)
|
||
|
||
Scope: this fixes the **single rolling anchor vs. per-segment measured times**
|
||
question deferred by [live-timeline-anchoring](./live-timeline-anchoring.md),
|
||
and realizes the *manifest → buffer* half of that decision's Boundary as a
|
||
single shared anchor.
|
||
|
||
## Context
|
||
|
||
[live-timeline-anchoring](./live-timeline-anchoring.md) settled the anchor
|
||
*source* — PDT, the universal wall clock shared across renditions — but left
|
||
open how that anchor drives a shared presentation timeline. Today's
|
||
`anchor-live-tracks` pins each selected A/V track to its own buffer
|
||
independently, and doesn't anchor text at all.
|
||
|
||
Two facts make a single shared anchor sufficient — and per-track pinning
|
||
redundant:
|
||
|
||
1. **MSE plays all SourceBuffers on one element timeline.** There is a single
|
||
`currentTime`; audio and video are coerced onto one native-PTS coordinate.
|
||
2. **Native-PTS default** ([mse-timestamp-offset](./mse-timestamp-offset.md)) —
|
||
no `timestampOffset`, so every track shares the encoder's PTS clock.
|
||
|
||
Under (1) + (2) there is no inter-track skew, so one track's `(media-time ↔
|
||
PDT)` pair describes all tracks; further pins would only restate it. And text —
|
||
which has no buffer to pin — can be placed *only* by a shared anchor.
|
||
|
||
**Assumption committed:** no inter-track PTS skew. This is the existing
|
||
live-model assumption (native-PTS default); per-track skew correction remains
|
||
deferred to
|
||
[non-zero-pts-support](../design/spf/features/non-zero-pts-support.md). If skew
|
||
ever needs handling it layers a per-track offset on top of the shared anchor —
|
||
it does not require returning to per-track pinning.
|
||
|
||
## Alternatives Considered
|
||
|
||
- **Per-track buffer pins (today's `anchor-live-tracks`).** Pin each selected
|
||
A/V track to its own buffered segment. Rejected: under the no-skew assumption
|
||
the pins necessarily *agree*, so the extra pins are redundant restatement;
|
||
and the approach structurally **cannot anchor text**, which has no
|
||
SourceBuffer — keeping it would force a separate, divergent text path for the
|
||
same concern.
|
||
|
||
- **Per-track PDT estimate only (no buffer truth).** Place every track from the
|
||
manifest estimate (`sequence × avgDuration` + PDT) and never pin. Rejected:
|
||
drops the authoritative correction — the estimate is duration-variance-prone
|
||
(it produced an observed ~27 s drift at window turnover), and the buffer pin
|
||
is what makes the timeline exact. The estimate is the right *bootstrap*, not
|
||
the final answer.
|
||
|
||
## Rationale
|
||
|
||
PDT is already the cross-track anchor source; this decision commits to **one**
|
||
anchor instead of N. The win is uniformity: audio, video, and text all position
|
||
by the same `(media-time ↔ PDT)` rule, so the behavior has one code path, text
|
||
stops being a special case, and "first track to buffer wins" makes the anchor
|
||
available as early as possible. Pinning once (not per reload) keeps the
|
||
drift-surfacing property: if a track's PDT disagrees with the established
|
||
anchor, it shows up as a visible desync rather than being silently re-corrected
|
||
every reload.
|
||
|
||
This promotes open question **[4] sync anchor** in
|
||
[live-presentation-modeling](../design/spf/live-presentation-modeling.md) from
|
||
"per-segment / per-track" to "presentation-level," as that doc anticipated.
|
||
|
||
## Verification
|
||
|
||
Not yet implemented. The implementation converts `anchor-live-tracks` into a
|
||
reactor (`unanchored → anchored`; a single entry establishes the shared anchor
|
||
once an A/V track has buffer ground truth, then positions all selected tracks)
|
||
— tracked separately. Verification will cover: one A/V pin placing audio + text
|
||
by PDT; first-track-wins; pre-pin estimate → buffer-pin upgrade; pin-once (no
|
||
re-pin across reloads); inert when no PDT / no resolved track.
|
||
|
||
## See also
|
||
|
||
- [live-timeline-anchoring](./live-timeline-anchoring.md) — the anchor *source*
|
||
(PDT); this decision resolves its deferred "single rolling anchor vs.
|
||
per-segment measured times" question.
|
||
- [mse-timestamp-offset](./mse-timestamp-offset.md) — native-PTS default; the
|
||
manifest → buffer offset half this anchor realizes.
|
||
- [non-zero-pts-support](../design/spf/features/non-zero-pts-support.md) — where
|
||
per-track skew correction lands if the no-skew assumption ever breaks.
|
||
- [live-presentation-modeling](../design/spf/live-presentation-modeling.md) —
|
||
open question [4], promoted to presentation-level here.
|
||
- [live-stream-support](../design/spf/features/live-stream-support.md) — the
|
||
`anchor-live-tracks` behavior that implements this.
|