Add the ./live-hls subpath export (build entry + package export) and a
LiveHlsEngineSignals type. Add a bare sandbox template (live-hls-engine) that
wires createLiveHlsEngine to a raw <video> — no player/skin — and logs playback
state, for end-to-end live-playback verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Live segments append at native PTS, so the buffered range sits at a large
timestamp while currentTime starts at 0 — no data at 0, readyState never
advances, playback can't start. seekToLiveEdge watches for the buffered range
and seeks the playhead into it (window start) once present. Listens to events
that fire without data at currentTime (loadedmetadata/durationchange/progress);
once per source. Composed into createLiveHlsEngine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add createLiveHlsEngine: reuses the VoD engine's MSE/segment/ABR behaviors,
swaps one-shot resolve* for the per-type live reload loop, defaults
resolveDuration to Infinity, and adds anchorLiveTracks — a behavior that applies
the per-track stream-origin anchor to the selected tracks so segment.startTime ≈
native PTS (what the segment loader matches currentTime against). Cross-track
alignment is intentionally not composed yet (it would fight the per-track anchor
in a re-firing effect); residual skew is absorbed by native-PTS A/V sync.
Demuxed audio+video; text/discontinuity out of scope. Not yet wired to a DOM
element — engine composition + anchor behavior only, both typecheck/build green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize the video-only reload spike into a per-type factory mirroring
resolve-track: reloadVideoTrack / reloadAudioTrack / reloadTextTrack, each
gating on its own selected*TrackId + track type so demuxed audio and video
reload independently. Inject fetchResolvableText via config (parity with
resolve-track, and testable). Update the live-playlist spike to reloadVideoTrack.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The HLS-tag-shaped name doesn't fit the format-neutral media model. startDate
parallels startTime (a segment carries both) and Track.startDate, while staying
protocol-neutral. Pure rename — no behavior change.
(Open question, deferred: whether a per-segment wall-clock field is needed at
all once Track.startDate is the anchor, or only re-emerges for discontinuities.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add anchorTrackToSequenceOrigin: re-bases a track's timeline to an estimated
stream start (the segment at startSequence, default 0) so startTime reads as
elapsed-since-stream-start and startDate becomes the wall clock at that origin.
The unseen earlier segments' duration is estimated from the observed segments'
average (more reliable than EXT-X-TARGETDURATION, a spec ceiling); present
segments keep their actual spacing. Rough and provisional — refined later from
the buffer; per-track.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Track.startDate — the wall-clock time (epoch seconds) at a track's timeline
origin, derived in the parser as programDateTime − startTime and stable as the
window slides. Provisional from the manifest (refined later from the buffer).
Add alignTrackTimelines(tracks): a pure model transform that re-bases demuxed
tracks onto a common wall-clock origin by their startDate delta, so segments
with equal programDateTime get equal startTime — the cross-track A/V sync step.
Verified against the real demuxed Mux CMAF fixtures, where the 2s audio/video
skew resolves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two decision docs for the live-HLS timeline work:
- mse-timestamp-offset — native-PTS default for live; timestampOffset reserved
for relocation (the manifest→buffer / encoded layer).
- live-timeline-anchoring — align demuxed tracks and recover turnover via PDT,
not sequence number (the manifest layer).
Resolve open questions [4] (sync anchor) and turnover startTime recovery in
live-presentation-modeling, pointing at the decisions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface absolute per-segment program-date-time (epoch seconds) on Segment,
interpolated forward via EXTINF and re-anchored on explicit tags. This is the
cross-track sync anchor for demuxed audio/video — where per-track relative
startTime disagrees, equal PDT identifies the same presentation instant — and
the exact recovery value on a full live-window turnover.
Surfacing only; PDT-anchored placement / the cross-track adjuster is a
follow-up. Adds synthetic unit tests plus sanitized real Mux live snapshots
(TS non-uniform slide; CMAF/LL-HLS demuxed A/V) as fixtures.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
POC spike for live HLS at the playlist layer only (no MSE/segments/DOM):
- parser surfaces target-duration / media-sequence / playlist-type / endlist
into a generic Ham.metadata bag (getMediaPlaylistMetadata accessor), with
stable media-sequence-derived segment ids
- parseMediaPlaylist(text, previous) takes a resolved-or-unresolved prior
track and carries the timeline forward across reloads (media-sequence
overlap + actual durations); first load anchors at 0; targetDuration used
only as the no-overlap fallback
- duration -> Infinity for unended live (finite once VOD/ENDLIST)
- streamType on Presentation, derived from PLAYLIST-TYPE alone
- reloadTrack behavior + createLivePlaylistSpikeEngine composition
WIP: startTime/timestampOffset basis and cross-track (A/V) sync are still
under research; PROGRAM-DATE-TIME capture and the cross-track alignment
strategy are not yet implemented.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Companion to presentation-modeling.md for streams that change over
time (live / DVR / event). Spine is a category decomposition that
keeps data separated by change-rate and consumer: content snapshot
(snapshot/merge segment identity via media-sequence + URL/byteRange),
streamType, completeness-as-duration, refetch policy as its own
category, the PROGRAM-DATE-TIME sync anchor, and the derived consumer
surface. Captures the debated decisions and open questions; scopes to
sliding-window live (LL-HLS / DVR / discontinuity / timestampOffset
deferred). Adds the reciprocal companion link in presentation-modeling.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>