- wai.live.contribution registered (registry.rs; REGISTRY.md, capabilities.json and v2.ttl regenerated); SPEC §5, CHANGELOG and live-ingest point to the extension. - joule-code-conformance runs joule-contrib with and without rist, joule-moq-ingest with rist, and checks the link corpus regenerates; wai-conformance runs live_contribution_verify.py over live-conformance/links and fires on the extension. - A RIST link's rate is bounded by its 16-bit sequence space: fewer than 32 768 packets within the buffer (§8), refused as bitrate_exceeded above it. - READMEs for joule-contrib and the link corpus. Co-Authored-By: Claude Opus 5.5 <[email protected]>
84 lines
5 KiB
Markdown
84 lines
5 KiB
Markdown
# joule-contrib
|
|
|
|
Contribution over UDP with retransmission, for WAI's ingest gateway: SRT
|
|
(`draft-sharabayko-srt-01`) and RIST (VSF TR-06-1:2020 Simple Profile, VSF TR-06-2:2024 Main
|
|
Profile), the MPEG transport stream both carry, and an account of what became of every
|
|
sequence number. WAI's `extensions/live-contribution.md` profiles them; `joule-moq-ingest`
|
|
uses this crate to bring a contribution link into a room's tracks.
|
|
|
|
## SRT
|
|
|
|
`srt::Listener` serves many callers on one UDP port, each connection found by the socket ID
|
|
its packets name; `srt::call` calls a listener. Both run the caller-listener handshake of the
|
|
draft's §4.3.1 (the SYN cookie, the HSv5 extensions, the stream ID, the key material), and
|
|
live mode (§7.1): every message one packet, TSBPD over the negotiated latency, too-late drop,
|
|
ACK/ACKACK with the RTT estimate, immediate and periodic NAKs, retransmission, AES-CTR with
|
|
the key wrapped (RFC 3394) under PBKDF2-HMAC-SHA1. A listener decides each caller through an
|
|
`Admission`, which sees the stream ID and gives the passphrase, the role (receive or send) and
|
|
the latency, or a rejection code.
|
|
|
|
## RIST (feature `rist`)
|
|
|
|
`rist::RistListener` receives one flow: the Simple Profile's RTP on an even port P and RTCP on
|
|
P + 1, or the Main Profile's GRE-over-UDP tunnel on one port, in reduced overhead mode with
|
|
the VSF EtherType or the legacy one, keep-alives, and PSK (PBKDF2-HMAC-SHA256 over the GRE
|
|
nonce, AES-CTR on the GRE sequence number). It takes the first flow whose CNAME is the one it
|
|
expects, and, under PSK, whose packets decrypt. It requests what is missing with range or
|
|
bitmask requests, measures the RTT with the RTT echo, and delivers each packet a buffer after
|
|
it was expected. `rist::send` is the sender of either profile.
|
|
|
|
## The account
|
|
|
|
`stats::Account` records what a receiver did with every sequence number, in order: delivered
|
|
at the first try, recovered within the window, dropped when its time passed, or outstanding
|
|
when the link ended; the loss runs, the requests sent and the numbers they named, the
|
|
retransmissions, duplicates and late arrivals received, the round trips, how long each
|
|
recovery took and its least margin. It is cut into parts, which the gateway signs as the link
|
|
record.
|
|
|
|
## The transport stream
|
|
|
|
`ts::Demux` reads the PAT and PMT (each section's CRC checked) and reassembles each stream's
|
|
PES packets, with the PTS extended past 33 bits; a PES missing a packet is dropped whole and
|
|
counted. `ts::Mux` writes a program of one video and one audio stream, and `ts::Pacer` times
|
|
a stream's chunks by its PCR.
|
|
|
|
## Tools
|
|
|
|
| binary | what |
|
|
|---|---|
|
|
| `joule-contrib-send` | sends a transport stream file (paced by its PCR) or a synthetic program over SRT (calling or listening) or RIST |
|
|
| `joule-contrib-recv` | receives over SRT or RIST into a file, and prints the link's account |
|
|
| `joule-contrib-bench` | one link on loopback, both ends in the process: the payload rate, CPU time and energy, with a lossy path if asked |
|
|
|
|
URLs: `srt://HOST:PORT?streamid=…&passphrase=…&pbkeylen=16&latency=MS` (calls; `srt://:PORT`
|
|
listens), `rist://HOST:PORT?profile=simple|main&cname=…&secret=…&aes-type=128|256&buffer=MS`.
|
|
|
|
## Tests
|
|
|
|
| test | what |
|
|
|---|---|
|
|
| unit tests | RFC 3394, RFC 6070 and TR-06-2 Annex B vectors, SP 800-38A's CTR vector; the packet formats; the TR-06-1 Appendix A requests; the TS multiplexer against the demultiplexer, a lost packet, the PTS wrap; the account |
|
|
| `srt_link` | SRT on loopback through a proxy that drops datagrams each way, every payload in order, the account of every sequence number; each key length, a wrong and a missing passphrase, the rejection codes; a packet held for the latency window; a listener that sends to a caller that receives |
|
|
| `rist_link` | the Simple Profile with range and bitmask requests through lossy proxies; the Main Profile in the clear, under PSK of each length and in the legacy format; another CNAME and another passphrase refused |
|
|
| `interop` (ignored) | against each transport's reference tools run locally, named by `WAI_SRT_LIVE_TRANSMIT`, `WAI_RISTSENDER` and `WAI_RISTRECEIVER`: their caller and senders into this crate and this crate into their listener and receivers, byte for byte, encrypted and through lossy paths. With `--ignored`, a tool not named fails the test |
|
|
|
|
The `lossy` module's proxy drops, delays and reorders datagrams from a fixed seed.
|
|
|
|
## Patents
|
|
|
|
VSF TR-06-1:2020 and TR-06-2:2024 each carry an intellectual property notice: a patent is
|
|
claimed to read on their protocol sections, and its holder has assured the forum that it will
|
|
license the claims to implementers. The RIST code is therefore built only with the feature
|
|
`rist`, which no default build turns on; whether a distributed build carries it is a licensing
|
|
decision for the distributor (`extensions/live-contribution.md` §10).
|
|
|
|
## Dependencies
|
|
|
|
AES, CTR, HMAC, SHA-1 and SHA-256 from RustCrypto (MIT OR Apache-2.0); PBKDF2 (RFC 8018) and
|
|
AES key wrap (RFC 3394) are written here over them. tokio, serde, serde_json, hex, tracing and
|
|
rand_core: MIT or Apache-2.0. No C library is linked.
|
|
|
|
## Licence
|
|
|
|
Apache-2.0.
|