16 KiB
status, date, definition
| status | date | definition |
|---|---|---|
| draft | 2026-05-20 | technical |
DVR / event-stream support
DVR (digital video recorder) and event-stream HLS support: engine
handles HLS playlists with growing-window semantics (segments
never roll off the start) instead of sliding-window (live). Adds
back-seek capability through history, event-stream recognition via
#EXT-X-PLAYLIST-TYPE:EVENT, and the transition from event-stream to
VOD when termination commits. The third cluster A doc — sibling to
live-stream-support (foundation) and
ll-hls-support (low-latency extension).
A Media-src feature in the framing from clusters.md § Feature classification axes: without it, DVR / event sources either don't play (engine treats the growing playlist as a malformed live stream) or back-seek doesn't work (buffer-management evicts history before the user reaches it).
DVR and event-stream are documented together because they share the
core mechanism — a growing playlist with no roll-off — and structural
implementation. The HLS-spec-defined PLAYLIST-TYPE:EVENT is one
producer-side construct; DVR is the capability that exposes back-seek
through whatever history the server retains. Both consume the same
client-side engine surface.
Status
- Composition: not implemented. Hard prerequisite
live-stream-support is also not
implemented. Today's
parseMediaPlaylistrecognizes#EXT-X-PLAYLIST-TYPE:as a known-tag pass-through but doesn't surface the value to the track output. - Definition depth: technical — scope and SPF touchpoints articulated against live-stream-support's structure; implementation specifics open. Source material: SPF Epics Working Doc — epic #3 DVR / Event Stream Support (cluster A, Media-src, eng M, validation M; "Growing playlist; extension of #2 (live-stream-support).").
- Hard prerequisite: live-stream-support.
The reload loop, target-duration pacing,
Infinityduration semantics, andsetLiveSeekableRangewriter-behavior shape all come from that feature; DVR/event-stream supplies the windowing variance. The "DVR / event boundary" open question in live-stream-support.md's Open questions section is resolved by this doc's existence: DVR is its own feature, not a phase of live-stream-support.
Phases of complexity
Content phases (capability slices). Each phase is a distinct capability slice of "DVR/event-stream supported."
| Phase | What | Notes |
|---|---|---|
| Growing-window playlist semantics | Playlist grows from the recording / event start; no roll-off. Engine retains full history. setLiveSeekableRange start value derives from the playlist's first segment media time (or 0) rather than the sliding-back-N derivation live uses. The reload-loop and target-duration-pacing machinery is unchanged from live |
The core windowing difference. Variant-specific producer behavior (computes seekableStart from the playlist's first retained segment) feeds the variant-agnostic setLiveSeekableRange writer that live also uses |
Event-stream recognition (PLAYLIST-TYPE:EVENT) |
Parser surfaces #EXT-X-PLAYLIST-TYPE:EVENT from the media playlist (today the tag is recognized but not extracted; track output gains playlistType: 'EVENT' | 'VOD' | undefined). Engine uses the value to distinguish event-stream from live-with-large-window — semantically distinct even if structurally similar |
Parser-side change; the value isn't yet surfaced. PLAYLIST-TYPE:VOD is the orthogonal case (already-finished recording) that the parser would surface uniformly |
| Back-seek through history | User can seek arbitrarily far back into the recorded portion. Buffer-management's seek phase already handles non-contiguous gap-fill (per buffer-management.md's "Seek handling" phase); DVR exercises this aggressively with large seek distances. No new behavior; existing seek code path under different load | The "DVR works" experience surface. Stress-tests the existing seek-from-arbitrary-position planning |
| DVR-aware back-buffer policy | Default backBuffer.keepSegments: 2 from buffer-management is too aggressive for DVR (history is evicted before user can seek back to it). Either configurable (large value for DVR variants) or a variant-specific policy ("retain N seconds back" or "retain indefinitely") |
Variant-specific behavior. Affects buffer-management.md's back-buffer eviction phase. Open question: shape of the policy (configurable threshold vs subtractive composition) |
| Event-stream termination → VOD transition | When #EXT-X-ENDLIST appears on an event-stream, live-stream-support's terminated-state-transition phase handles the mechanics (reload loop stops, last segment stabilizes, mediaSource.duration flips from Infinity to the finite value, clearLiveSeekableRange() paired with the transition). This phase notes the additional semantic that the stream now behaves equivalently to VOD: seekable to start, finite duration, normal endOfStream gating |
Composes with live-stream-support's termination phases. No new termination behavior; this phase is the semantic note about what post-termination means for event-stream specifically |
What's in scope vs out of scope
In scope:
- All five phases above for HLS event-stream and DVR-style growing- playlist sources
- Parser surface for
EXT-X-PLAYLIST-TYPE:EVENT(and:VODfor uniformity) - Variant-specific producer behavior for the seekable-range start signal
- Variant-specific back-buffer policy
- Composition with live-stream-support's reload loop and termination phases
Out of scope (separate Media-src candidate features):
- ll-hls-support — orthogonal sibling extension. DVR can compose with LL-HLS for low-latency live with back-seek; both extensions compose on the same reload-loop foundation but address different concerns (LL-HLS = latency reduction at the live edge; DVR = back-seek through history). The composition shape is "DVR + LL-HLS engine variant" with both feature's behaviors composed in.
Out of scope (different architectural layer):
- Adapter-layer customer-facing affordances ("seek back 30 seconds" buttons, scrub bar with history range, DVR window UI). Consume this feature's seekable-range signal; not SPF concerns themselves.
- User-facing DVR window configuration (e.g., "only show last 24 hours"). Adapter-level policy; SPF respects what the server provides in the playlist.
- Server-side DVR retention policy. The engine handles whatever segments the server lists; it doesn't enforce retention.
Likely cross-cutting impact
Things this feature probably forces decisions on, not just additions:
- Composition-variant placement for variant-specific behaviors.
Per the failure-mode catalog's composition-variant entry: behaviors
with variant-specific value derivation (the seekable-range start
producer, the back-buffer policy) compose into the DVR variant, not
as runtime branches in always-on behaviors. Same shape as
ll-hls-support's variant-composition analysis. The
live-stream- supportengine variant, thell-hls-supportextension variant, and thedvr-event-stream-supportvariant are three distinct compositions of the reload-loop foundation; each adds / replaces variant-specific behaviors. - Seekable-range producer split. live-stream-support documents
setLiveSeekableRangeas a new behavior reading derived live-edge data; for DVR, the value derivation differs (start = 0 / first- segment-time vs sliding-back-N). The cleanest split: a variant- specific producer behavior computes the(seekableStart, seekableEnd)signal; a variant-agnostic writer behavior consumes the signal and callsmediaSource.setLiveSeekableRange(). The writer doesn't branch; the producer is variant-specific. Same pattern asupdateMediaSourceDuration's uniform-across-variants shape, mirrored — uniform writer, variant-specific upstream. - Back-buffer policy shape under DVR. Today's
backBuffer. keepSegments: 2is a single config knob. DVR may want one of: (a) a large configurable value, (b) a "retain N seconds back" alternative axis, (c) "retain indefinitely" (no eviction within the DVR window). The choice affects whether the back-buffer policy becomes variant-specific behavior (different policy composed for DVR variant) or stays uniform with a richer config surface. - DVR-vs-live-with-large-window distinction. A DVR stream
without
PLAYLIST-TYPE:EVENTis structurally indistinguishable from "live with a very large sliding window" until the engine observes that segments don't roll off. The engine has options: (a) configure DVR vs live at the adapter layer (consumer opts in via config), (b) detect fromPLAYLIST-TYPE:EVENTwhen present, (c) observe the playlist's behavior over multiple reloads and infer (engine flips to "DVR mode" once it sees segments stay). (a) is the simplest; (c) is the most adaptive but adds detection complexity. endOfStreamgate under DVR. live-stream-support documents thatendOfStreamdoesn't naturally fire for live (playlist keeps growing). For DVR-during-recording, same —endOfStreamwaits for termination. For DVR-post-termination, the gate becomes reachable the same way live-post-termination does (last segment stabilizes). No new gate semantics needed; the existing isLastSegmentAppended + currentTime gate logic from mse-mms-pipeline.md applies uniformly.- Server-side retention edge case. A server may stop serving
older segments while still listing them in the playlist (e.g.,
"we keep 24 hours of history; older segments 404 on fetch"). The
engine references segments via URI; if a back-seek targets a
segment URI that 404s, the fetch fails. Whether this falls under
this feature's scope (recover gracefully — surface a "history
expired" error to the consumer) or under
[unsupported-case-error-mapping](generic fetch-failure mapping) is an open boundary. - DVR + LL-HLS composition. Both are cluster A extensions on the same reload loop. Composition order: LL-HLS replaces the standard reload-loop behavior with its variant; DVR replaces the back-buffer policy and seekable-range producer. The two extensions are orthogonal — neither's behaviors conflict with the other's. A "DVR + LL-HLS" engine variant composes both extension sets atop the live-stream-support foundation.
Open questions
- Back-buffer policy shape. Configurable
keepSegmentswith large default for DVR vs "retain N seconds back" alternative axis vs "retain indefinitely" mode. Affects whether back-buffer becomes variant-specific behavior or stays uniform with richer config. - DVR-vs-live distinction signal source. Adapter-config opt-in
vs
PLAYLIST-TYPE:EVENTdetection vs observe-over-reloads inference. (a) is simplest; (b) only covers spec-flagged event streams; (c) is the most adaptive but adds complexity. Likely combination: (b) when the tag is present; otherwise (a) until (c) matures. - Seekable-range start derivation under server retention. When
the server keeps only the last N hours of segments and the
playlist's first segment slides forward over time, the
seekableStartvalue should track that. Same writer (variant- agnosticsetLiveSeekableRangewriter), but the variant-specific producer needs to read the playlist's current first-segment, not a constant0. - Server-side retention error handling. Segment 404 on back-seek
fetch. Scope of this feature vs
[unsupported-case-error-mapping]. PLAYLIST-TYPE:VODsemantics. When a media playlist arrives withPLAYLIST-TYPE:VODfrom the start (fully-resolved at first fetch, no reload needed), the engine should recognize this and skip reload-loop composition. Adjacent concern; may belong here (parser surfacing the value uniformly) or in live-stream-support (engine-side reload-loop activation gate).- Event-stream-during-pre-event. An event-stream playlist may exist with metadata but few or no segments before the event starts. Reload-loop pacing handles this naturally (target-duration reload until segments appear), but pre-roll segment-zero semantics are worth verifying.
- DVR + LL-HLS composition specifics. Order of behavior composition, shared state between DVR and LL-HLS extensions. Verify when both extensions get implementation work.
liveSeekableRangeclearance on DVR termination. For live → termination, live-stream-support's terminated-state-transition phase pairsclearLiveSeekableRange()with the transition (so the browser'sseekablereverts to buffer-derived semantics). For event-stream → VOD transition, the seekable range stays a finite range from playlist start to last segment — but does it still go throughsetLiveSeekableRange(now with finite end) or throughclearLiveSeekableRange()+mediaSource.durationsetter? Spec allows either; spec-conformant browsers should behave equivalently. Verify when implementation arrives.
Related features
- live-stream-support (hard
prerequisite) — provides the reload loop, target-duration pacing,
Infinityduration semantics, termination detection (ENDLIST+ miss-counter), and thesetLiveSeekableRangewriter-behavior shape. DVR/event-stream supplies the windowing variance and the variant-specific seekable-range start producer. - ll-hls-support — orthogonal cluster A extension. DVR + LL-HLS compose; both extensions sit atop the same reload-loop foundation but address different concerns (latency reduction vs back-seek). A DVR + LL-HLS engine variant is the cross-extension composition.
- buffer-management — back-buffer policy needs DVR-aware shape. Seek-from-arbitrary-position gap-fill is exercised aggressively under DVR. Both phases of buffer-management interact with this feature; the open question on back-buffer policy shape (variant-specific behavior vs configurable threshold) is shared.
- mse-mms-pipeline —
Infinityduration semantics during recording; finite duration on event- stream termination. Same MSE writer semantics as live;endOfStreamgate logic applies uniformly. - non-zero-pts-support — DVR and
event streams typically have PTS far from zero (recording starts
at wall-clock time, not at PTS 0).
currentTime/seekablesemantics require non-zero-PTS support to be correct. [unsupported-case-error-mapping](candidate) — server- side retention 404 errors on back-seek fall under this candidate's scope for consumer-facing mapping.
See also
- live-stream-support.md — cluster A foundation this feature extends; the doc's "DVR / event boundary" open question is resolved by this doc's existence (standalone, not absorbed)
- ll-hls-support.md — sibling cluster A extension; orthogonal composition
- clusters.md § Manifest reload loop — cluster A description
- clusters.md § Feature classification axes — Media-src feature framing
- conventions/behaviors.md →
Inverse: behaviors that operate uniformly across tracks — the
precedent for variant-agnostic writer + variant-specific producer
split this feature applies to
setLiveSeekableRange - SPF Epics Working Doc — source material; epic #3 (DVR / Event Stream Support)
- Mux Video Permutations Matrix — Stream Type section; SPF column shows ⚠️ for DVR (manifest re- polling unverified)
- HLS Spec —
EXT-X-PLAYLIST-TYPE(§4.4.3.5)