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
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ transport, benchmark tooling); worktrees isolate commits, not semantics.
- [Broadcast close](/quest/m1/broadcast-close/README.md) - `close()` is the one way to end a broadcast in every language, a permanent retraction that leaves in-flight tracks alone
- [Relay peer set](/quest/m1/relay-peer-set.md) - a wire consumer tells a client hop from a peer hop, and every mesh credential can mark a peer
- [CLI import clock](/quest/m1/cli-import-clock.md) - fMP4, TS, and FLV imports publish on the shared broadcast clock across restarts
- [Native clock fixtures](/quest/m1/native-clock-fixtures.md) - CI drives native capture through clock edge cases and asserts the published timestamps
- [CLI inspection](/quest/m1/cli-inspect/README.md) - `moq ls` lists what is live and `moq fetch` reads a group over MoQ, and a guide shows how to inspect a relay
- [JS caught up](/quest/m1/js-announce-caught-up.md) - @moq/net's announce consumer says when the initial set has landed, like Rust
- [Bindings caught up](/quest/m1/announce-live-bindings.md) - moq-ffi, libmoq, and every wrapper yield the same flat announce event, `Live` included
Expand Down
1 change: 0 additions & 1 deletion quest/m1/cli-import-clock.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ archive playback. Update the import docs.

## Related

- [Native clock fixtures](/quest/m1/native-clock-fixtures.md) - the same scenarios through native capture
- [GStreamer clock](/quest/m1/3021-moq-gst-anchor-generated-media-timelines-to-wall-clock.md) - separate source adapter
19 changes: 0 additions & 19 deletions quest/m1/native-clock-fixtures.md

This file was deleted.

2 changes: 2 additions & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,7 @@ upstream release waits in [m4](/quest/m4/README.md).
- [Windows capture parity](/quest/m2/capture-windows.md) - system audio and screen cursor capture with a settled app-capture policy
- [Linux capture parity](/quest/m2/capture-linux.md) - Wayland window/system-audio capture with explicit display-selection and app-capture limits
- [Plan capture ergonomics](/quest/m2/capture-ergonomics.md) - scope independent crop and audio mixing quests
- [Capture clock source](/quest/m2/capture-clock-source.md) - capture publishers stamp on the catalog's clock, with no separate clock to pass, on dev
- [Audio capture time](/quest/m2/audio-capture-time.md) - native audio stamps a buffer's capture instant, not when the driver reads it
- [X11 capture transport](/quest/m2/x11-capture-shm.md) - move X11 capture to shared memory and RandR events instead of a per-frame socket copy
- [Capture frame buffers](/quest/m2/capture-frame-buffers.md) - stop rebuilding a full-frame buffer every tick in the X11 and Windows backends
20 changes: 20 additions & 0 deletions quest/m2/audio-capture-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# [S] Native audio stamps acquisition, not arrival

## Goal

Native audio capture stamps a buffer at the instant its first sample was
captured, like native video stamps a frame's acquisition. Today the driver
stamps the broadcast clock when it reads the buffer, so audio lands at least
one device buffer (plus callback and queue latency) later than video captured
at the same instant.

## Plan

cpal reports `InputCallbackInfo::timestamp().capture` per callback; carry it
through `capture::Samples` and map it onto the broadcast clock once per open,
the way video maps its private capture timeline. Fall back to arrival where a
host reports nothing usable, and keep the reset-on-gap behavior. Measure the
skew before and after on at least one real device, and extend the moq-audio
clock fixtures so a synthetic buffer's capture instant is what publishes.

Public API: none. Wire: none.
20 changes: 20 additions & 0 deletions quest/m2/capture-clock-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# [S] Capture publishers read the catalog's clock

## Goal

`moq_video::encode::publish_capture` and `moq_audio::encode::Publication` stamp
on the clock their catalog advertises, with no separate clock to pass. Today
each takes its own `moq_mux::Clock`, and `PublicationOptions::default()` builds
a fresh one, so a caller relying on the default publishes audio against a
mapping the catalog never advertised. `moq import capture` passes
`catalog.clock()` to both, which is the only correct value.

## Plan

Drop the `clock` parameter from video `publish_capture` and the `clock` field
from `PublicationOptions`, reading `catalog.clock()` instead. Update moq-cli and
any binding that forwards a clock. The clock fixtures in both crates already
pass the catalog's clock, so they keep grading the same path.

Public API: breaking in published `moq-video` and `moq-audio`, so it targets
`dev`. Wire: none.
5 changes: 5 additions & 0 deletions quest/m2/js-discontinuity.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ and any other caller over, and keep data tracks skipping a sequence the way
Rust's `discontinuity()` does if a JS data-track caller appears. Rust is
untouched.

Match Rust's break, too: without an explicit end, `discontinuity()` closes the
group with no cadence-estimated duration marker. Whatever resumes can land
sooner than one estimated frame later (a capture swap), and a marker past it
reads as a rewind to every consumer.

Public API: breaking in published `@moq/hang`, so it targets `dev`. Wire: none.
21 changes: 19 additions & 2 deletions rs/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,14 @@ check-changed $FILES $TEST="false":

# moq-video's and moq-audio's device code is behind `capture`, which is off
# by default, so the pass above never compiles it. Only nightly's
# `--all-features` did, and a break there lands on main.
# `--all-features` did, and a break there lands on main. With TEST=true the
# lint rides the test build, as in `check-test`.
if [[ "$packages" == "ALL" ]] || just rs _wants-capture "$packages"; then
just rs capture
if [[ "$TEST" == true ]]; then
CARGO_BUILD_WARNINGS=deny just rs capture-test
else
just rs capture
fi
fi

# moq-relay's io_uring listener is behind `io-uring`, off by default, so the
Expand Down Expand Up @@ -628,6 +633,13 @@ macos *args:
capture *args:
cargo clippy --locked -p moq-video -p moq-audio --all-targets --features moq-video/capture,moq-audio/capture {{ args }} -- -D warnings

# The capture publishers' tests (the clock fixtures among them) drive synthetic
# devices, so they need no hardware and run with every PR that reaches either crate.

# Test the capture feature, which the default test pass skips.
capture-test *args:
just rs test -p moq-video -p moq-audio --features moq-video/capture,moq-audio/capture {{ args }}

# Same idea as `windows`/`macos`, for Android: moq-video's MediaCodec encoder and
# decoder, its `Surface::HardwareBuffer` variant, and the `frame::android` module
# are all `#[cfg(target_os = "android")]`, so a host-target check compiles none of
Expand Down Expand Up @@ -886,6 +898,11 @@ test-changed $FILES:
*) echo "rs: testing $(just rs _names "$packages")"; just rs test --no-tests=pass $packages ;;
esac

# Mirrors `check-changed`: the capture tests are off the default feature set.
if [[ "$packages" == "ALL" ]] || just rs _wants-capture "$packages"; then
just rs capture-test
fi

# Compile and run the `/// ```` examples, which nextest skips.
doctest *args:
cargo test --locked --doc {{ args }}
Expand Down
Loading
Loading