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
9 changes: 5 additions & 4 deletions quest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ grouped into milestones ordered by priority.

## Plan

m0 supplies the GPU video path for the Pronto desktop. m1 is the dev branch line. m2 is the next agent
m0 contains the immediate media work: the Pronto desktop GPU path and the four
0.0.x media crate API gates before 0.1. m1 is the dev branch line. m2 is the
next agent
wave across reliability, features, performance, and planning. Unsettled
quests may stay in m2 for planning; their implementation waits for the
required decisions. m3 holds later features, design studies, experiments,
Expand All @@ -25,9 +27,8 @@ into m2, and opened m4 for the hardware- and partner-gated quests.

## Quests

- [m0: Pronto GPU video](/quest/m0/README.md) - reusable Vulkan/CUDA ownership,
GPU conversion and NVENC for the desktop demo

- [m0: immediate media](/quest/m0/README.md) - Pronto GPU delivery and the
audio, video, transcode, and NVENC contracts required before 0.1
- [m1: the dev line](/quest/m1/README.md) - the breaking API and wire
changes, the merge gates, and the merge itself
- [m2: next wave](/quest/m2/README.md) - implementation and planning across
Expand Down
80 changes: 76 additions & 4 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,67 @@
# m0: Pronto GPU video
# m0: immediate media

## Goal

Supply the reusable GPU media support needed to remove raw-pixel CPU transfers
from the Pronto CARLA demo on its Linux/NVIDIA desktop. This is the immediate
priority; the product integration and installation live in moq.pro.
Settle the public contracts of `moq-audio`, `moq-video`, `moq-transcode`, and
`moq-nvenc` before their first 0.1 releases, while supplying the reusable GPU
media support needed to remove raw-pixel CPU transfers from the Pronto CARLA
demo on its Linux/NVIDIA desktop. Product integration and installation live in
moq.pro.

## Plan

The Pronto GPU quests remain an independent deliverable within m0. They define
portable Vulkan/CUDA ownership, safe partial NVENC initialization, and a strict
GPU conversion path without changing the scope of the pre-0.1 API audit.

The four audited crates are 0.0.x, so their changes target main. Adapt callers
in other packages without breaking their published APIs, C layouts, or wire
formats. Do not bump versions as part of these quests. The final review records
when the four crates are ready for a separately requested release.

The package boundaries are explicit:

- `moq-audio` owns the PCM/layout and codec configuration split, decoder entry
point, publication authority, FEC removal, AEC attachment, playback outcome,
and extensible audio frame and packet construction.
- `moq-video` owns frame conversion and construction, decoder output policy,
synchronous codec thread confinement, capture timestamps and rational rates,
extensible group configuration and `cut` naming, and its feature defaults.
- `moq-transcode` adopts the video rate, group, output, and feature contracts in
its public configuration and observations without adding another media model.
- `moq-nvenc` narrows its safe facade around owned resources and completion,
while loading and incompatibility become fallible public errors.
- Published `moq-mux` gains only the additive shared `rate` namespace. Published
`moq-ffi`, `libmoq`, and language-binding signatures, layouts, and sentinel
behavior remain unchanged while their internals adapt.

The agreed direction is small, honest APIs: typed PCM layouts, rational video
rates, extensible GOP and frame records, explicit ownership, and no knobs that
claim behavior they do not provide. Synchronous codecs remain public and
thread-confined; async sinks own codec execution. Native versus CPU output is a
choice, not a promise that every native backend yields a GPU surface.

OpenH264 becomes optional but stays enabled by default. Rendering becomes
opt-in; inexpensive native codec defaults remain. Hardware libraries already
loaded at runtime do not need a toolkit dependency added to the build.

Each quest updates the existing crate documentation, examples, and affected
callers with its change. Contract tests run in CI; feature checks exercise each
crate independently, since workspace feature unification hides missing gates.
Cross-platform compilation and hardware execution are separate evidence.

The audit was source inspection at `b2ef453e67`, not fresh compilation or
benchmarking. All public module families and their in-tree consumers were
reviewed; the generated NVIDIA ABI was inspected only where wrapper safety
depended on it. Performance concerns remain hypotheses until measured.

API-preserving implementation, codec additions, allocation work, and hardware
proof remain in the existing backlog. Keep audio's integrated packetizing
Producer and transcode's validated Ladder and coalescing active cursor. Keep
one video Frame/Surface hierarchy and its deliberate native/wgpu type interop;
do not add another media abstraction or a renderer crate during stabilization.
Preserve the documented ability to abort publication after finish unless an
actual ownership fix requires a replacement error-finalization contract.

## Quests

Expand All @@ -13,6 +70,21 @@ priority; the product integration and installation live in moq.pro.
- [NVENC registration rollback](/quest/m0/nvenc-registration.md) - release resources when mapping fails after registration
- [GPU conversion and NVENC](/quest/m0/video-gpu-encode.md) - convert, resize and
encode imported frames without CPU pixel transfers or fallback
- [NVENC resources](/quest/m0/nvenc-resources.md) - a small safe facade retains submitted resources through completion
- [NVENC loading](/quest/m0/nvenc-loading.md) - unavailable or incompatible drivers return errors instead of panicking
- [Codec threads](/quest/m0/video-thread-ownership.md) - synchronous codec handles cannot escape their owning thread
- [Media features](/quest/m0/media-features.md) - OpenH264 can be excluded, rendering is opt-in, and feature aliases disappear
- [Shared rate policy](/quest/m0/media-rate-policy.md) - the planned public namespace move happens before 0.1
- [Audio configuration](/quest/m0/audio-config.md) - PCM layout, codec settings, and subscription policy have distinct contracts
- [Audio publication](/quest/m0/audio-publication.md) - callers get demand authority and supported options, not internal transport or resampler machinery
- [Remove ineffective FEC](/quest/m0/audio-fec.md) - no public flag promises redundancy the encoder never emits
- [AEC ownership](/quest/m0/audio-aec.md) - one microphone owns an adaptive canceller and controls remain shareable
- [Playback outcome](/quest/m0/audio-playback.md) - nonblocking writes report accepted and dropped audio
- [Video output](/quest/m0/video-output.md) - codec output and subscription policy are separate, with native or CPU frames
- [Video frames](/quest/m0/video-frames.md) - conversions preserve typed pixels and frame records can grow
- [Video timing](/quest/m0/video-timing.md) - capture time and fractional frame rates survive capture, encoding, and transcode
- [Video GOP](/quest/m0/video-gop.md) - the group contract is extensible before intra-refresh implementation
- [Media release review](/quest/m0/media-release-review.md) - verify the settled contracts before separately authorizing 0.1 releases

## Related

Expand Down
24 changes: 24 additions & 0 deletions quest/m0/audio-aec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# [M] Exclusive microphone ownership for echo cancellation

## Goal

One microphone owns an adaptive echo canceller. Shareable controls cannot be
used to attach the same adaptive state to another microphone, and creating a
second active reference does not silently disable the first.

## Plan

Engine::canceller replaces the engine's previous tap, and Canceller clones
share adaptive state despite the documented one-microphone restriction. Split
the exclusive attachment from a cloneable control handle. Refuse conflicting
attachments explicitly, with release on drop and a clear ownership path from
playback reference through capture teardown.

Keep the current audio-processing implementation. No multi-microphone mixing
or new processing backend is part of this change. Use fake capture/reference
sources to test a second attachment, replacement after drop, control clones,
and teardown while processing. Run the ownership regressions in CI without
real devices, retaining existing signal-quality tests separately.

Public API: AEC construction, capture attachment, and handle ownership change.
Wire: none. Update speakerphone examples and existing audio documentation.
41 changes: 41 additions & 0 deletions quest/m0/audio-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# [L] Separate PCM layout, codec settings, and playback policy

## Goal

One audio codec-settings type describes what the codec accepts. Source PCM
format/rate/layout and MoQ subscription/output policy are separate, and the
low-level decoder can select a backend without changing its constructor later.

## Plan

Encoder::encode accepts codec-sized interleaved f32 at the codec rate, while
its Config also describes source format/rate that only Producer converts.
Options repeats the codec settings. Keep Producer's useful accumulation and
normalization behavior, but compose one settings shape rather than copying a
second set of fields. Keep backend traits private; establish the configuration
and backend-selection entry points with today's implementations first.

Replace ambiguous Rust channel-count configuration with an extensible Layout
contract. Implement today's modes only. Preserve existing multichannel PCM
passthrough without inventing speaker positions from a count: an unspecified
discrete layout must not silently gain a spatial downmix. Named layouts have
a documented canonical speaker order; unsupported conversions are refused.
Surround codecs and new mixer capabilities remain in the existing backlog.

Separate codec configuration from Consumer subscription and output conversion
options. Output rate/layout describe decoded samples, not merely catalog claims.
Refuse settings that do not apply to the chosen codec, including DTX on PCM.
Keep Input and settings construction extensible without compatibility aliases.

Adapt moq-ffi/libmoq internals while preserving their published signatures,
record layouts, channel-count conventions, and sentinel behavior. Tests cover
source/codec rate separation, format conversion, layout mismatch, passthrough,
unsupported settings, and backend refusal in CI. Update existing audio docs.

Public API: Rust audio configuration, layout, and decoder construction change.
Wire and published binding shapes: unchanged.

## Related

- [Audio layouts](/quest/m2/audio-codecs/layout.md) - later named surround layouts and mixing
- [Decode seam](/quest/m2/audio-codecs/decode-backend.md) - later platform selection implementation
26 changes: 26 additions & 0 deletions quest/m0/audio-fec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# [S] Remove the ineffective audio FEC flag

## Goal

No moq-audio option claims to enable loss redundancy that the shipped encoder
never emits. A real loss-recovery policy remains separately scoped.

## Plan

Config and Options only set OPUS_SET_INBAND_FEC. The pinned unsafe-libopus
initializes expected loss to zero, where its decide_fec returns false. Our
decoder also never requests FEC recovery. The existing test reads the control
flag rather than recovering lost audio, and no production caller enables it.

Remove the ineffective boolean from both public configuration paths and their
documentation/tests before 0.1. Keep current Opus packetization, DTX, and
ordinary packet-loss concealment behavior. Add a focused configuration test
for the retained options; do not replace the flag with another unproven knob.

Public API: removes fec from Rust 0.0.x configuration. Wire: no change to the
behavior currently emitted. Real recovery needs loss metadata, sequencing,
decoder policy, and an end-to-end loss fixture before a new API is exposed.

## Related

- [Audio loss recovery](/quest/m3/audio-loss-recovery.md) - decide a tested policy when a consumer needs it
22 changes: 22 additions & 0 deletions quest/m0/audio-playback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [S] Report the outcome of nonblocking playback writes

## Goal

A playback writer can distinguish accepted audio from overflow or output-not-
ready drops without blocking the real-time device path.

## Plan

Sink::write currently discards the accepted-frame count on overflow and returns
success for output-not-ready. Replace the success value with an extensible
typed outcome that reports accepted and dropped sample frames; name units
explicitly so stereo samples are not counted twice. Keep failure distinct from
intentional real-time dropping, including all-accepted and zero-accepted cases.

Propagate or deliberately consume the outcome in existing callers without
changing published binding signatures. Test partial acceptance, output not
ready, conversion/resampling units, and closed/error paths with deterministic
device-independent fixtures in CI. Document how callers observe drops without
adding a retry loop that increases latency.

Public API: playback write's success result changes. Wire: none.
28 changes: 28 additions & 0 deletions quest/m0/audio-publication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# [S] Expose audio publication authority without its internals

## Goal

Audio callers can observe demand without bypassing packetization, and the
public surface stops exposing unused resampler mechanics and duplicated
capture-construction arguments.

## Plan

Replace Producer::track with demand, matching video. A shared transport Producer
can append or finish outside the audio publisher's framing and padding rules;
the external consumers inspected only need its demand handle. Retain privileged
access privately for capture ownership where necessary.

Make the standalone Resampler private: no in-tree external consumer needs its
window/timestamp machinery, and its corresponding held-at accessor is already
private. Let publish_capture take the existing PublicationOptions instead of
reconstructing it from five arguments. Reserve extension points on Frame and
Encoded records through their constructors before adding future metadata.

Preserve arbitrary-sized PCM writes, priming, terminal padding, and the
intentional ability to abort after finish. Adapt bindings and examples without
changing their public signatures. Test demand lifecycle and publication close
behavior through the supported API in CI; update crate examples and rustdoc.

Public API: remove privileged/helper exports and simplify capture arguments.
Wire: none.
33 changes: 33 additions & 0 deletions quest/m0/media-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# [M] Optional native compilation and opt-in rendering

## Goal

A consumer can build these media crates without OpenH264's C++ compilation or
the rendering stack. Defaults retain a working software H.264 fallback and
the existing inexpensive native backends.

## Plan

Make OpenH264 and its sys dependency one optional backend feature, enabled by
default. Remove render from moq-video's defaults. Keep nvidia and mediacodec
defaults and the existing opt-in system-library/libclang features. Remove the
nvenc/nvdec compatibility aliases in video and transcode before 0.1.

Forward the software-backend choice through transcode and explicitly select
features in workspace consumers, tests, and examples. A hardware-only build
without a usable codec refuses construction; Software and Named selection must
never silently use another class of backend. No mandatory toolchain is added
to moq-nvenc, whose bindings are checked in and drivers are loaded at runtime.

Audio keeps its pure-Rust AAC default. Make PipeWire/PulseAudio host flags avoid
activating cpal when neither capture nor playback needs it, and document the
capability combination. Do not split encode/decode into more features without
evidence of useful savings.

Add independent no-default, software-only, native-only, and rendering feature
checks for the affected crates to CI. Inspect dependency graphs to prove
OpenH264/wgpu/cpal are absent when excluded; workspace-wide builds are not
that proof. Preserve codec-independent tests when a backend is disabled.

Public API: Cargo defaults and supported feature names change. Wire: none.
Update feature tables and build prerequisites with the same change.
26 changes: 26 additions & 0 deletions quest/m0/media-rate-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# [S] Settle the shared media rate-policy namespace

## Goal

The existing video rate policy lives at the shared location already planned
for audio and transcode, before removing its video namespace would break 0.1.
Actual audio/ladder bandwidth adaptation remains deferred.

## Plan

The bandwidth quest currently plans to delete the public moq_video::encode::rate
module and move Policy/Control to moq_mux::rate. Perform that API relocation
now, adapt video's existing consumer and docs, and remove the old export
without a compatibility shim. Preserve one policy implementation.

Move its tests with it and make construction/update agree on bounds: the
current initial target uses max.max(min), although update lowers an excessive
minimum to the ceiling. A policy must never initialize above its ceiling.
Test inverted bounds, initial target, decreases, hysteresis, and recovery in CI.

Public API: removes the old 0.0.x video namespace and adds the shared policy
under moq-mux without breaking that package's existing exports. Wire: none.

## Related

- [Audio bandwidth](/quest/m2/2848-follow-the-bandwidth-grant-in-moq-audio-instead-of.md) - later adaptation uses the shared policy
44 changes: 44 additions & 0 deletions quest/m0/media-release-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# [S] Verify the four media contracts before 0.1

## Goal

Record that the agreed audio, video, transcode, and NVENC API changes have
landed, or return concrete remaining blockers, before a separate version-bump
request. Completing this review does not bump or publish packages.

## Plan

Review the final public surface and examples after the prerequisite quests.
Check that deferred backend, surround, refresh, color, and performance work can
use the extension points without another planned replacement of these APIs.
Search the living backlog for obsolete signatures and remove completed work.

Verify independent crate feature builds, default and backend-free refusal,
ownership/cancellation tests, docs, and migrated callers on the exact release
candidate. Use the Nix check/test recipes and platform CI; record skipped
hardware cases separately from compilation. Confirm package manifests do not
reintroduce mandatory native compilation through feature unification.

No published FFI/C layout or wire break is authorized by this stabilization
line. Any newly discovered break outside these four 0.0.x crates needs its own
maintainer decision and appropriate branch. No performance claim is accepted
without measurements; unresolved optimization work alone does not block 0.1.

Public API/wire impact: review only.

## Required

- [NVENC resources](/quest/m0/nvenc-resources.md) - safe ownership is enforced
- [NVENC loading](/quest/m0/nvenc-loading.md) - driver refusal is fallible
- [Codec threads](/quest/m0/video-thread-ownership.md) - direct handles have correct auto traits
- [Media features](/quest/m0/media-features.md) - independent build choices work
- [Shared rate policy](/quest/m0/media-rate-policy.md) - later adaptation will not remove a stabilized namespace
- [Audio configuration](/quest/m0/audio-config.md) - PCM and codec contracts are settled
- [Audio publication](/quest/m0/audio-publication.md) - only intended authority is public
- [Remove ineffective FEC](/quest/m0/audio-fec.md) - no unsupported promise remains
- [AEC ownership](/quest/m0/audio-aec.md) - microphone attachment is exclusive
- [Playback outcome](/quest/m0/audio-playback.md) - drops are observable
- [Video output](/quest/m0/video-output.md) - output and subscription contracts are distinct
- [Video frames](/quest/m0/video-frames.md) - pixels and extension points are typed
- [Video timing](/quest/m0/video-timing.md) - timestamps and rates retain their meaning
- [Video GOP](/quest/m0/video-gop.md) - deferred refresh does not replace the group API
Loading
Loading