15 KiB
status, date, definition
| status | date | definition |
|---|---|---|
| draft | 2026-05-20 | technical |
LL-HLS support
Low-Latency HLS extensions on top of the live-stream-support reload-loop foundation: blocking reload for server-gated playlist refresh, partial segments for sub-segment append granularity at the live edge, preload hints for pre-fetching the next part before it's announced, and delta playlists for bandwidth-efficient reloads. Together these mechanisms collapse the engine's distance from the live edge from "≥3× target duration" (regular live) to "≤ a few parts" (low-latency live).
A Media-src feature in the framing from clusters.md § Feature classification axes: LL-HLS-encoded sources play technically via the regular live reload loop (each full segment lands when announced, just with regular-live latency), but "actual support" — engaging the partials / blocking-reload / preload mechanisms the server advertises — requires this feature. Without it, LL-HLS sources play at regular-live latency, not the low-latency the producer optimized the stream for.
Status
- Composition: not implemented. Hard prerequisite live-stream-support
is also not implemented. None of
parseMediaPlaylist, the reload loop (which doesn't exist yet),forward-buffer's planner, orcreateTrackedFetchcurrently handle LL-HLS shapes. - Definition depth: technical — scope and SPF touchpoints articulated against the HLS LL-HLS spec extensions; implementation specifics open. Source material: SPF Epics Working Doc — LL-HLS Support (epic #1) (cluster A, eng size XL, validation M-L, "Largest single gap").
- Hard prerequisite: live-stream-support.
The four LL-HLS mechanisms all build on the reload-loop, sliding-
window, live-edge-tracking, and
Infinity-duration primitives that feature introduces. LL-HLS is not independently scopable.
Phases of complexity
Capability slices, each one an HLS LL-HLS spec extension. Naive vs Full depth applies within each phase per clusters.md § Feature classification axes; e.g., blocking reload at naive depth without preload hints, full depth combining the two.
| Phase | What | Notes |
|---|---|---|
| Blocking reload | _HLS_msn=N&_HLS_part=P query params on playlist reload; server holds the response until the target msn/part is available. Replaces target-duration interval polling with response-driven request chaining. Parser must surface #EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES to enable the mechanism |
Largest shift from regular live: the reload loop's pacing model changes (response-driven, not interval-driven). createTrackedFetch needs long-poll-aware request semantics — a single request may legitimately take ~target-duration to respond |
| Partial segments | #EXT-X-PART:URI=...,DURATION=...,INDEPENDENT=...,GAP=...,BYTERANGE=... tags within the most-recent few segments. Client fetches and appends partials before the full segment is announced via #EXTINF. Parser must surface #EXT-X-PART-INF:PART-TARGET=... (target part duration) and per-part attributes |
Append still goes through the same SourceBufferActor (same variant, same codec — no changeType()). The forward-buffer planner must extend beyond track.segments[] to include a "partial head" past the last complete segment; reconcile a part eventually being superseded by its containing full segment (same media interval, two playlist entries) |
| Preload hints | #EXT-X-PRELOAD-HINT:TYPE=PART,URI=... (or TYPE=MAP). Client may pre-fetch the indicated URL before it appears in the playlist as a regular EXT-X-PART. Used in combination with blocking reload to pipeline the next fetch behind the in-flight blocking-reload response |
Pre-fetched response is retained and consumed when the URL appears as a regular EXT-X-PART on the next reload; double-fetch must be avoided. Pre-fetch is only a latency optimization — never gates other phases |
| Delta playlists | _HLS_skip=YES query param on reload; server responds with a playlist containing #EXT-X-SKIP:SKIPPED-SEGMENTS=N denoting N segments removed from the start. Client merges the delta into its retained playlist state. Parser must surface #EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=... (the minimum-skippable boundary advertised by the server) |
Requires the client to retain playlist state across reloads — today's parseMediaPlaylist returns a fresh Track per fetch, so the reload-loop behavior gains a delta-merge step. Bandwidth optimization, not latency: complements but doesn't replace blocking reload + partials |
What's in scope vs out of scope
In scope:
- All four phases above, applied to HLS LL-HLS-encoded sources where
#EXT-X-SERVER-CONTROLadvertises the capability - Parser surface for
EXT-X-SERVER-CONTROL,EXT-X-PART-INF,EXT-X-PART,EXT-X-PRELOAD-HINT,EXT-X-SKIP,EXT-X-RENDITION-REPORT - Long-poll-aware fetch shape (timeout policy compatible with blocking-reload response holds)
- Forward-buffer planner extension for partial-head tracking
- Client-side playlist-state retention across reloads (for delta merge)
Out of scope (sister Media-src candidate features):
[live-edge-distance-abr](candidate, cluster C extension) — using distance-from-live-edge as an ABR signal alongside bandwidth. Consumer of LL-HLS's tighter live-edge tracking but not part of LL-HLS itself.
Out of scope (different architectural layer):
- Above-engine UI affordances ("seek to live edge," "currently live," live-button states). Consume LL-HLS-tightened live-edge data via the live-stream-support feature's derived live-edge signal; not SPF concerns themselves.
Likely cross-cutting impact
Things this feature probably forces decisions on, not just additions:
- Reload-loop composition variant — LL-HLS isn't a runtime branch
inside a regular-live reload behavior; it's a different reload-loop
behavior composed into a low-latency live engine variant. Same shape
as
live-stream-support.md'ssetLiveSeekableRangeplacement decision: a new variant-specific behavior, not a conditional inside an existing variant-agnostic behavior. Per the failure-mode catalog andconventions/behaviors.md§ Inverse: behaviors that operate uniformly across tracks, the existingupdateMediaSourceDurationis the canonical example of a behavior that stays composition- variant-agnostic; the LL-HLS reload-loop is its inverse — a variant-specific behavior that exists only in the LL-HLS engine. - Variant-decision point — open — where does the engine commit to
the LL-HLS variant: adapter-level upfront (consumer opts in), or
after-first-playlist-parse from
EXT-X-SERVER-CONTROLflags? The spec allows a stream to advertise some LL-HLS capabilities and not others (e.g., partials without blocking-reload), so per-mechanism composition is possible. Either way the behaviors are variant- specific; the question is when the composition is finalized. parseMediaPlaylistextensions — parser today returns aTrackwith segments only. LL-HLS adds:serverControlflags,partInf(part target duration),parts[]within the head segment(s), a currentpreloadHints[], optionalskipmetadata. The parser output schema grows; the parsed-track shape that downstream behaviors consume gains LL-HLS-specific fields. Intersects with presentation-modeling.md's open question onparseMediaPlaylistpluggability — LL-HLS-aware parsing is a strong forcing function for explicit parser-extension shape.createTrackedFetchrequest shape — today the wrapper handles streaming responses chunk-by-chunk with EWMA bandwidth sampling. No changes needed for partial-segment loading (same wrapper, smaller payloads — bandwidth sampling continues working). Required change for blocking reload: the wrapper has no long-poll-aware timeout policy today. A blocking-reload request may legitimately take up totarget-durationto respond; needs either a configurable per-request timeout or a request-type discriminant. Per the sampling-baked-into- loading pattern, the sample producer doesn't move.- Forward-buffer planner extension — current planner iterates
track.segments[](full segments) and filters by buffered ranges within a fixed look-ahead. LL-HLS extends the candidate set with partials past the last complete segment, plus a reconciliation rule: if partPcovers[t0, t1]and the same interval later appears as part of full segmentS, both entries map to the same media interval; the planner must not double-load. Low-latency-aware buffer-duration setting is a separate tunable — the default 30s target buffer is incompatible with low-latency-live's "stay within a few parts of live edge" goal. - Sliding-window awareness under partials — the segment list
mutates more frequently (partials append at the live edge between
full-segment announcements). Existing sliding-window-aware back-
buffer policy from
live-stream-supportcontinues to apply to full segments; partials past the head are transient by definition. liveSeekableRangeupdate frequency —setLiveSeekableRangefrom live-stream-support advances as the live edge advances. Under LL-HLS, the edge advances at part granularity (sub-second updates, not target-duration interval). Same writer, higher update rate; no new multi-writer concern.- Per-type partial coordination — audio playlists can also carry
EXT-X-PART. Inherits live-stream-support's open question on per- type reload coordination, with the additional concern that audio and video parts may have different target durations.
Open questions
- Variant-decision point. Per the cross-cutting note above: adapter-level upfront vs after-first-playlist-parse vs per-mechanism granular composition. Affects how the engine is built and how the capability-detection signal flows. Resolving this likely shapes how the regular-live engine variant is composed too.
- Pre-fetch retention scope. Preload hints pre-fetched in response to one playlist snapshot may be invalidated by the next snapshot (server changed its mind about the next part URI). Retention policy: abort and discard, or hold pending validation against the next playlist? Spec leaves this to implementations.
- Long-poll fetch shape vs
createTrackedFetchextension. Add a new request-type discriminant to the existing wrapper (with longer timeout), or a siblingfetchBlockingReloadwrapper that delegates to the same chunk-streaming infrastructure? Trade-off: one wrapper with conditional timeout vs two wrappers with shared chunk handling. - Planner extension shape — extend
forward-bufferor sibling. The currentgetForwardBufferSegmentsis a pure function overSegment[]. Either it grows aparts?: PartSegment[]parameter (and a reconciliation rule baked in), or a siblinggetForwardBufferPartialsruns alongside and the loader merges. The reconciliation logic (part superseded by containing full segment) is the load-bearing piece either way. - Capability advertisement vs runtime probing. If the server
advertises
CAN-SKIP-UNTILbut the client has already retained less history than the skip boundary, the client must fall back to a full-playlist reload. Where this fallback decision lives — inside the delta-merge step or as a reload-shape decision upstream — is open. #EXT-X-RENDITION-REPORTconsumption. Spec lets the server advertise the LAST-MSN/LAST-PART for other renditions in the playlist; clients switching renditions can resume at the right point without an extra round-trip. Useful for ABR-driven variant switching under LL-HLS but a separate optimization. May be a sub-phase of partial-segments or its own follow-on.- GAP=YES handling.
#EXT-X-PARTmay carryGAP=YESindicating the encoder failed to produce the part on time; clients are spec- advised to fetch the next part anyway and let the buffer underrun. How this interacts withendOfStreamgating (a "gap" past the live edge isn't a true terminator) and stall recovery (the underrun isn't a network stall) is open.
Related features
- live-stream-support (hard
prerequisite) — provides the reload loop, sliding-window tracking,
live-edge tracking,
Infinity-duration semantics, termination detection, andsetLiveSeekableRangeplacement. LL-HLS is structurally an extension of this feature's reload loop with a different pacing model, finer-grained segment list, and added optimizations. - dvr-event-stream-support — sibling extension on the same reload loop with different windowing semantics. Orthogonal to LL-HLS: a DVR stream can also be low- latency (DVR + LL-HLS), in which case both features compose.
- presentation-modeling —
parseMediaPlaylistextensions for LL-HLS tags forces the question of parser pluggability raised in that doc's open questions. The two features intersect tightly. - buffer-management — forward-buffer
planner extension for partials lives in the same
media/buffer/neighborhood; same back-buffer policy applies for full segments below the live edge. - video-abr — variant switching under LL-HLS
uses the same
bandwidthStatesignal; partial-segment chunked- sampling continues to feed it viacreateTrackedFetch.EXT-X-RENDITION-REPORTconsumption (deferred, see Open questions) is the LL-HLS-aware variant-switch optimization. - non-zero-pts-support — live streams
including LL-HLS typically have PTS far from zero; the time-mapping
primitive is consumed by live (including LL-HLS) for correct
currentTime/seekablesemantics. - mse-mms-pipeline — partial-segment
append is same-codec append on the same
SourceBufferActor; nochangeType(), no buffer recreation. The MSE codec-change check explicitly does not fire for LL-HLS.
See also
- live-stream-support — the cluster A foundation this feature extends
- clusters.md § Manifest reload loop — cluster A description
- clusters.md § Feature classification axes — Media-src feature framing
- presentation-modeling.md — parser interface; LL-HLS-aware parsing is a strong forcing function on parser pluggability
- SPF Epics Working Doc — source material; epic #1, "Could split: blocking reload, partial segments, delta playlists, preload hints"
- Mux Video Permutations Matrix — Stream Type section; SPF column shows 🔲 for LL-HLS
- HLS Spec — Low-Latency HLS (§4.4.5 EXT-X-PART, §4.4.3 EXT-X-SERVER-CONTROL, §4.4.5 EXT-X-PRELOAD-HINT, §6.2.5 Delta Playlists)