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
5 changes: 3 additions & 2 deletions doc/bin/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,9 @@ keyframe. The delay also bounds how stale a group may get, so `--delay 0` writes
frame as soon as it is read and drops none as late, but still skips a stalled
group once a newer one is ready.
FLV and MKV reject their former `--max-delay` spelling with a migration
message. TS output's PCR follows the source's clock within what ISO/IEC
13818-1 allows.
message. The output follows the source's clock within what ISO/IEC 13818-1
allows a TS PCR. A source further off fails the export, naming its rate, once
it has used half the delay; a brief network stall only drops what it made late.

`export ts --passthrough` reads the track an `import ts --passthrough` published
and writes its packets back out unchanged, from its first group on, each run
Expand Down
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ above them.
- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - a lite-07 SUBSCRIBE asks for past and live ranges with absolute or relative ends, in either order, and replaces FETCH; merged ranges never starve a subscriber; relays fill misses by range, including over moq-transport
- [Live largest location](/quest/m1/largest.md) - `largest()` replaces `latest()` in Rust and JS as a live stream of the track's largest location, known before the first group from the publisher's report
- [Live TS clock validation](/quest/m1/ts-live-clock.md) - resolve the local PCR-rate failure with reproducible timing evidence and CI controls
- [Slow source fails](/quest/m1/slow-source.md) - an export whose source runs further off real time than the output may follow fails promptly naming the rate, instead of dropping frames for hours
- [Same-instance TS resume](/quest/m1/ts-same-instance-resume.md) - prove valid continuation and fix the unexpected final exporter failure without weakening identity
- [Wire compat media](/quest/m1/wire-compat-media.md) - wire-compat always runs same-version media cells through the compat reader, so planned breaks can't hide its regressions
- [Binding panic supervision](/quest/m1/ffi-panic-supervision.md) - a panic in any moq-c or moq-ffi background task reaches the host as a panic, never a lost callback or Cancel
Expand Down
48 changes: 0 additions & 48 deletions quest/m1/slow-source.md

This file was deleted.

3 changes: 2 additions & 1 deletion rs/moq-mux/src/container/flv/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ impl<S: Stream> Export<S> {

/// Release frames a fixed delay after their decode time, dropping late frames.
///
/// The same delay bounds each source's staleness. Zero (the default) releases each frame as
/// A source whose clock runs further off ours than the output's may follow fails the export
/// once it has used half the delay. The same delay bounds each source's staleness. Zero (the default) releases each frame as
/// soon as it is read and drops none as late, but a stalled group is still skipped once a
/// newer one is ready.
pub fn with_delay(mut self, delay: std::time::Duration) -> Self {
Expand Down
3 changes: 2 additions & 1 deletion rs/moq-mux/src/container/mkv/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ impl<S: Stream> Export<S> {

/// Release frames a fixed delay after their decode time, dropping late frames.
///
/// The same delay bounds each source's staleness. Zero (the default) releases each frame as
/// A source whose clock runs further off ours than the output's may follow fails the export
/// once it has used half the delay. The same delay bounds each source's staleness. Zero (the default) releases each frame as
/// soon as it is read and drops none as late, but a stalled group is still skipped once a
/// newer one is ready.
pub fn with_delay(mut self, delay: Duration) -> Self {
Expand Down
4 changes: 3 additions & 1 deletion rs/moq-mux/src/container/ts/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,9 @@ impl<E: catalog::Catalog> Export<E> {
/// joiner runs at the delay from its first output. The output then keeps the source's
/// pace and muxes every track in `(DTS, PID)` order whatever the arrival skew between
/// them. A frame that arrives after its deadline is dropped, and a video track that
/// dropped one resumes at its next keyframe. A stalled group is skipped once it falls
/// dropped one resumes at its next keyframe. A source whose clock runs further off ours than
/// 13818-1 lets the PCR follow fails the export once it has used half the delay, where a
/// brief network stall only drops what it made late. A stalled group is skipped once it falls
/// half the delay behind the newest content (see [`Consumer`](crate::container::Consumer)),
/// so the group after it still arrives with the other half to spare.
///
Expand Down
17 changes: 17 additions & 0 deletions rs/moq-mux/src/container/ts/export_timing_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,23 @@ async fn a_source_past_the_limit_is_counted() {
assert!(stats.out_of_tolerance > 0, "not counted");
}

/// The same source fails the export once it has used half the delay, about ten minutes in,
/// rather than drop nearly every frame from then on.
#[tokio::test(start_paused = true)]
#[should_panic(expected = "past the 30 ppm the output's may follow")]
async fn a_source_past_the_limit_fails_once_half_the_delay_is_gone() {
on_a_scaled_clock(1.0004, 900_000_000 / VIDEO_US).await;
}

/// A source 22% slow, as an importer starved of CPU, fails the export within seconds.
#[tokio::test(start_paused = true)]
#[should_panic(expected = "the source's clock runs -220")]
async fn a_source_far_off_real_time_fails_within_seconds() {
let mut live = Live::new(1.0 / 1.22, 0).await;
let mut leg = live.join(Duration::ZERO).await;
live.run(10_000_000 / VIDEO_US, &mut [&mut leg], |_| false).await;
}

// A 1+1 pair is two receivers of one broadcast whose outputs a seamless switch compares packet
// for packet. They join at different times and read with different cadences, and from the moment
// they overlap they must render the same bytes. The continuity counters are the known exception
Expand Down
Loading
Loading