Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions doc/bin/hls.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ broadcast by path:
/{broadcast}/{video|audio}/{rendition}/seg/t{pts}.m4s
```

A [`moq-archive`](https://docs.rs/moq-archive) recording replayed through its
`Reader` is served the same way, with no second stored copy. Playlists come
from the replayed timeline alone, and a segment GETs exactly one stored object
Comment thread
kixelated marked this conversation as resolved.
of its rendition, so switching renditions never downloads both. An
Comment on lines +43 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Qualify the one-GET claim for undersized caches

When a range object exceeds Reader's configured cache and the HLS segment spans multiple groups, each group request reloads that same object because it cannot remain cached. The newly added a_bounded_cache_rereads_evicted_objects test demonstrates four GETs for one audio segment, so this unconditional statement gives storage operators an incorrect I/O guarantee; clarify that one object path is accessed, but it may be fetched repeatedly unless the cache can hold it.

Useful? React with 👍 / 👎.

inline-parameter-set codec with no catalog `description` is the exception:
the first playlist render GETs one keyframe group to build the init segment,
then caches it. Out-of-band configs need no media GET. Set `--window`
to cover the recording. The playlist ends with `EXT-X-ENDLIST` only once the
reader's caller declares the recording finished; the store holds no completion
marker.

The init URL carries a hash of its bytes, so a reconfigured rendition gets a
new one. An embedder of the library can also label the publisher's run with
`Broadcaster::set_generation`. Every segment URL then carries it
Expand Down
8 changes: 7 additions & 1 deletion quest/m1/archive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ The segment engine is in `rs/moq-mux/src/timeline.rs`:
- `moq-hls` renders live playlists from the timeline alone and FETCHes media
per HTTP request (`rs/moq-hls/src/export/mod.rs:3-8`). A clean timeline
finish ends every window with `EXT-X-ENDLIST` (:325-327).
- The same exporter serves a recording replayed through `moq_archive::Reader`
with no archive-specific code (`rs/moq-hls/src/export/archive_tests.rs`):
playlists read only the timeline (an inline parameter set also GETs one
keyframe group to build its init), and a segment GETs one object of its
rendition. The caller supplies the catalog, and `--window` must cover the
recording.

`rs/moq-archive` stores the versioned objects on any `object_store::ObjectStore`:
percent-encoded track names, `.info` JSON, the binary envelope, and put/get/list/delete.
Expand Down Expand Up @@ -114,8 +120,8 @@ owned by that prerequisite, not duplicated in archive storage.

## Quests

- [Archive HLS window](/quest/m1/archive/hls-window.md) - serve a replayed recording's whole retained timeline without a server-wide `--window`
- [Browser archive](/quest/m1/archive/browser.md) - the same contract for browser-published broadcasts
- [Offline archive HLS](/quest/m1/archive/hls.md) - render playlists from the archive timeline and fetch segment media lazily
- [DVR rewind](/quest/m1/archive/dvr.md) - seek through a bounded archive and return to live playback
- [Archive proof](/quest/m1/archive/proof.md) - prove persistence ordering, selective reads, exact FETCH replay, and timeline-only HLS generation

Expand Down
20 changes: 20 additions & 0 deletions quest/m1/archive/hls-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# [S] Archive HLS window

## Goal

`moq-hls` lists a replayed recording's whole retained timeline in HLS and DASH
without a server-wide `--window`, while live broadcasts keep a window within
the relay's cache.

## Plan

The export window (`moq_hls::export::Config::window`) trims every broadcast a
server exports. A recording served through `moq_archive::Reader` already
bounds itself: DVR expiry pops records from the replayed timeline, and an
unbounded archive never pops. Today an operator must raise `--window` past the
recording's length, which also inflates segment `Cache-Control: max-age` and
DASH `timeShiftBufferDepth` for every live broadcast on the same server.

Decide how an export learns that a broadcast's timeline is authoritative (the
catalog's `archive` entry carrying a store or replay path, a per-broadcast
option, or a separate server) and cap the derived HTTP and DASH values.
38 changes: 0 additions & 38 deletions quest/m1/archive/hls.md

This file was deleted.

8 changes: 2 additions & 6 deletions quest/m1/archive/proof.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,5 @@ objects survive. Failed or incomplete recovery/listing must delete nothing;
restart must finish this cleanup before accepting new groups.

Finally render and reload HLS playlists while rejecting every media-object GET
until a segment URI is requested. The range-bearing URI must resolve one
object directly without any listing or separate index object.

## Required

- [Offline archive HLS](/quest/m1/archive/hls.md)
until a segment URI is requested. A segment request must resolve one object
from the replayed timeline without any listing or separate index object.
4 changes: 4 additions & 0 deletions rs/moq-hls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ tracing = { workspace = true }
url = { workspace = true }

[dev-dependencies]
async-trait = "0.1"
futures = { workspace = true }
moq-archive = { path = "../moq-archive" }
moq-json = { path = "../moq-json" }
Comment on lines +39 to +42

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Declare the new dependencies through the workspace

These new dependencies bypass the repository's centralized dependency declarations: moq-archive and moq-json already exist in [workspace.dependencies], while async-trait is now shared by multiple crates but remains versioned locally. This leaves path/version ownership split across manifests; add the shared version to the root where needed and reference all three with { workspace = true }. rs/CLAUDE.mdL41-L41

Useful? React with 👍 / 👎.

moq-tokio = { path = "../moq-tokio", default-features = false, features = ["tcp", "noq", "aws-lc-rs"] }
tokio = { workspace = true, features = ["test-util"] }
tower = { version = "0.5", features = ["util"] }
Loading
Loading