live-ingest §9.5 (b19e078cc) in the gateway. The WHEP handler reads the offer's capability
attributes with wai::sdp_caps and, per media kind, forwards the rendition sdp_caps::pick gives:
the first advertised capability the owner publishes at or below the grant's max_layer. The
section is narrowed to that configuration's payload type before the WebRTC stack answers it,
so the answer is the configuration as if it were the actual one (RFC 5939 §3.6.2), and the
configuration's a=acfg goes into that section. Where nothing advertised is published, the
floor, the layer the resource names. An offer with no capability attributes is answered byte
for byte as before, and its session record is unchanged.
caps_unsupported is no longer a refusal: such an offer is answered as if it carried no
capability attributes, as RFC 5939 §3.3.2 has a recipient proceed that does not support a
required extension, with a=csup:med-v0 at each unsupported creq's level (§3.6.2). §9.5 and §14
say so; the other seven reasons are refused, 422, before anything is held. The choice goes
into the session's signed record (detail.caps) and a log line, and the session's subscriber
time is counted under the highest layer it forwards. §17 says the gateway implements §9.5.
One implementation: the gateway compiles wai-rs's src/sdp_caps.rs as its own module by
#[path], as wai-verify compiles wai-rs's integer sources, instead of depending on wai-rs. With
default features off and no feature, that dependency would still bring wai's build script
(cbindgen with syn, writing the tracked include/wai.h on every gateway build), wai's staticlib
and cdylib, about 29 000 lines of ungated modules, and serde_json's preserve_order and
raw_value, unified into every crate of the joule-code workspace built beside the gateway: the
reason joule-moq-room and joule-moq-remote are workspaces of their own. sdp_caps uses std
alone. Its tests come with it: tests.rs is named by #[path] and reads live-ingest.md beside
the file, so the gateway's test run replays live-conformance/sdp-caps/ through its copy. No
lockfile changes.
Tests: whep.rs's unit tests (the first-dispatch rendition and its answer, the grant's bound,
an offer without attributes byte for byte, the floor, caps_unsupported at each level, the
refusals), sdp.rs's for the narrowing and the added lines; tests/whep_caps.rs over HTTP: an
Enhanced RTMP publisher's AV1 layer 0 and H.264 layer 1 and Opus, six WHEP players by their
offers, each answer, each player's codec and frames, and each record. joule-code-conformance.yml
runs them in its joule-moq-ingest job, and its triggers gain the module and the corpus.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2 KiB
live-conformance/sdp-caps — capability attributes in a WHEP offer
Vectors for extensions/live-ingest.md §9.5: the WAI
capabilities a WHEP player advertises per media section of its offer, as SDP media
capabilities (RFC 6871) under capability negotiation (RFC 5939), read back by an egress
gateway, and the rendition the gateway forwards.
vectors.json holds:
reads: an offer, and for each media section the WAI capabilities it advertises, in order, each with the configuration, media capability and payload type that carry it; or the reason the reader does not take it (a refusal, or forcaps_unsupportedan offer a gateway answers as if it carried no capability attributes). Every reason of §9.5 appears.picks: an offer, a section, the renditions the owner publishes (layer and capability), the grant'smax_layerand the layer the resource names; and what the gateway forwards, with the answer'sa=acfgline, or the floor.writes: an offer and a sink's capabilities in its order; the offer with them written into it, byte for byte, and the capabilities left out; or why nothing is written.
Provenance. Every offer is synthetic, written in the form a WebRTC endpoint writes; none is
a capture. The cases were computed by sdp_caps_verify.py and are held by the reference.
Equivalence
The reference is wai::sdp_caps (wai-rs/src/sdp_caps.rs), whose tests replay every case,
write every order of the video capabilities and read it back, and hold §9.5's table and the
reasons of §9.5 and §14 to the module. The egress gateway, joule-moq-ingest, compiles the
same file as its own module, and its test run replays these tests, and so every case, through
that copy. The second implementation, written from §9.5's text and
the grammars of RFC 5939 and RFC 6871 and sharing no code with wai-rs:
python3 -I live-conformance/sdp_caps_verify.py live-conformance/sdp-caps
It recomputes every case and requires every mutated copy of the corpus to fail.