---
status: draft
date: 2026-08-03
definition: technical
---

# LL-HLS support

Low-Latency HLS extensions on top of the [live-stream-support](./live-stream-support.md)
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](./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. The hard prerequisite
  [live-stream-support](./live-stream-support.md) has since landed, so
  the reload loop, sliding window, live-edge tracking, and `Infinity`
  duration now exist — but none of the LL-HLS mechanisms themselves do.
  `parseMediaPlaylist` ignores `#EXT-X-PART`, `#EXT-X-PART-INF`,
  `#EXT-X-SERVER-CONTROL`, and `#EXT-X-PRELOAD-HINT`; reload pacing is
  interval-based (`mediaPlaylistReloadDelay`) with no blocking-reload
  `_HLS_msn` / `_HLS_part` query support; `forward-buffer`'s planner and
  `createTrackedFetch` handle whole segments only. `EXT-X-SERVER-CONTROL`
  is parsed, but only for `HOLD-BACK` — `PART-HOLD-BACK` is deliberately
  unread until partial-segment playback exists, since seating the playhead
  there while fetching whole segments would put it ahead of the last
  complete segment. Capturing `PART-HOLD-BACK` (and `PART-TARGET`) in the
  playlist metadata belongs to this feature's partial-segments phase.
- **Note:** live playback has been *validated against* Mux LL-HLS
  sources, which advertise `CAN-BLOCK-RELOAD=YES` and `PART-TARGET`.
  That is the interval-reload path working on an LL-HLS-capable server —
  not LL-HLS support. Latency is whatever the holdback gives, not
  part-level.
- **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)](https://www.notion.so/35f97a7f89d08123a13fecab1ca1cac4)
  (cluster A, eng size XL, validation M-L, "Largest single gap").
- **Hard prerequisite:** [live-stream-support](./live-stream-support.md)
  — **satisfied.** The four LL-HLS mechanisms all build on the
  reload-loop, sliding-window, live-edge-tracking, and
  `Infinity`-duration primitives that feature introduces, all of which
  have landed. LL-HLS is now unblocked rather than un-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](./clusters.md#naive-vs-full-implementation-depth);
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-CONTROL` advertises 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`'s `setLiveSeekableRange` placement
  decision: a new variant-specific behavior, not a conditional inside
  an existing variant-agnostic behavior. Per the failure-mode catalog
  and `conventions/behaviors.md` § *Inverse: behaviors that operate
  uniformly across tracks*, the existing `updateMediaSourceDuration`
  is 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-CONTROL` flags? 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.
- **`parseMediaPlaylist` extensions** — parser today returns a `Track`
  with segments only. LL-HLS adds: `serverControl` flags, `partInf`
  (part target duration), `parts[]` within the head segment(s), a
  current `preloadHints[]`, optional `skip` metadata. The parser
  output schema grows; the parsed-track shape that downstream
  behaviors consume gains LL-HLS-specific fields. Intersects with
  [presentation-modeling.md](../presentation-modeling.md)'s open
  question on `parseMediaPlaylist` pluggability — LL-HLS-aware
  parsing is a strong forcing function for explicit parser-extension
  shape.
- **`createTrackedFetch` request 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 to
  `target-duration` to 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 part `P` covers `[t0, t1]` and the same interval later appears as
  part of full segment `S`, 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-support` continues to apply to
  full segments; partials past the head are transient by definition.
- **`liveSeekableRange` update frequency** — `setLiveSeekableRange` from
  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 `createTrackedFetch` extension.** Add a
  new request-type discriminant to the existing wrapper (with longer
  timeout), or a sibling `fetchBlockingReload` wrapper 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-buffer` or sibling.** The
  current `getForwardBufferSegments` is a pure function over
  `Segment[]`. Either it grows a `parts?: PartSegment[]` parameter
  (and a reconciliation rule baked in), or a sibling
  `getForwardBufferPartials` runs 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-UNTIL` but 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-REPORT` consumption.** 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-PART` may carry `GAP=YES` indicating
  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 with `endOfStream` gating (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](./live-stream-support.md)** *(hard
  prerequisite)* — provides the reload loop, sliding-window tracking,
  live-edge tracking, `Infinity`-duration semantics, termination
  detection, and `setLiveSeekableRange` placement. 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](./dvr-event-stream-support.md)** —
  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](../presentation-modeling.md)** —
  `parseMediaPlaylist` extensions for LL-HLS tags forces the question
  of parser pluggability raised in that doc's open questions. The two
  features intersect tightly.
- **[buffer-management](./buffer-management.md)** — 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](./video-abr.md)** — variant switching under LL-HLS
  uses the same `bandwidthState` signal; partial-segment chunked-
  sampling continues to feed it via `createTrackedFetch`.
  `EXT-X-RENDITION-REPORT` consumption (deferred, see Open questions)
  is the LL-HLS-aware variant-switch optimization.
- **[non-zero-pts-support](./non-zero-pts-support.md)** — 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` / `seekable` semantics.
- **[mse-mms-pipeline](./mse-mms-pipeline.md)** — partial-segment
  append is same-codec append on the same `SourceBufferActor`; no
  `changeType()`, no buffer recreation. The MSE codec-change check
  explicitly does not fire for LL-HLS.

## See also

- [live-stream-support](./live-stream-support.md) — the cluster A
  foundation this feature extends
- [clusters.md § Manifest reload loop](./clusters.md#manifest-reload-loop)
  — cluster A description
- [clusters.md § Feature classification axes](./clusters.md#feature-classification-axes)
  — Media-src feature framing
- [presentation-modeling.md](../presentation-modeling.md) — parser
  interface; LL-HLS-aware parsing is a strong forcing function on
  parser pluggability
- [SPF Epics Working Doc](https://www.notion.so/35f97a7f89d08123a13fecab1ca1cac4)
  — source material; epic #1, "Could split: blocking reload, partial
  segments, delta playlists, preload hints"
- [Mux Video Permutations Matrix](https://www.notion.so/32c97a7f89d08191b84dd30f06685490)
  — Stream Type section; SPF column shows 🔲 for LL-HLS
- [HLS Spec — Low-Latency HLS](https://datatracker.ietf.org/doc/html/rfc8216bis)
  (§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)
