open-standards/joule-code/joule-code-rs/crates/joule-moq-ingest/gateway.example.toml
Transaction Science 57e426c940 live-contribution: the link record's magic is WLK1, no longer the clip record's WCL1
The contribution link record and the live-recording clip record both began WCL1. The clip
record had it first (live-recording §5.1, the registry's only WCL1 row); the link record took
the same four bytes when it was added, so a reader that tells records apart by their magic
could not tell one from the other.

The link record is now WLK1, a magic nothing else in the registry, the code or an open branch
uses. live-contribution §6.2 and SPEC name it, §6.5 step 2 says the clip record's WCL1 is
refused as malformed, and codecs/registry.rs registers it (REGISTRY.md and registry/ exported
from it). joule-moq-ingest writes and reads it. The corpus live-conformance/links/ is
regenerated with it, its files now .wlk1, plus clip_record_magic, a part with the clip
record's magic, refused. live_contribution_verify.py reads WLK1 and also refuses each accepted
part mutated to WCL1.

A wire change: a link record written before this one is malformed to a reader of this
revision. The CHANGELOG says so and acknowledges every corpus file that changed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-04 05:19:53 -05:00

114 lines
5.5 KiB
TOML

# joule-moq-ingest: every field, with its default where it has one.
# No secret lives here: the relay token and the signing key are files the operator
# provides, and a room is its signed descriptor, which is public.
[http]
listen = "127.0.0.1:8088" # the WHIP and WHEP resources; put a TLS front before them
origin = "" # this gateway's origin as grants name it, e.g. "https://ingest.example"
cors_allow_origin = "*"
max_body_bytes = 65536
request_timeout_ms = 10000
challenge_ttl_s = 300 # how long a proof-of-possession challenge stays good
max_challenges = 65536 # challenges held at once, issued and consumed each
[media]
bind_ip = "127.0.0.1" # each session's UDP socket, and its host candidate
ice_lite = true
connect_timeout_ms = 15000
idle_timeout_ms = 20000
[relay]
addr = "127.0.0.1:4443" # the relay's native QUIC endpoint (ALPN moqt-22)
server_name = "localhost"
cert_path = "relay-cert.pem" # the relay's certificate, trusted as a root
token_path = "relay-token" # the token value the relay's grant names by SHA-256
[signing]
key_path = "gateway.key" # 32 bytes, the Ed25519 seed; absent: made at start
signer_id = "" # empty: the key's did:key
origin_label = "wai-ingest"
[[rooms]]
descriptor_path = "room.wrd1" # the room's signed descriptor (WRD1)
revoked = [] # grant digests and viewer tags the room's key log revokes
[limits]
max_whip_sessions = 64 # one more: 503 with Retry-After
max_whep_sessions = 256
max_tracks_per_session = 2 # media sections in one offer; more: 422
max_bitrate_kbps = 8000 # per WHIP session, all tracks; stated per track as b=AS
bitrate_window_ms = 2000
max_frame_bytes = 4194304
max_queue_bytes = 33554432 # a session's queue to the relay
retry_after_s = 5
[groups]
audio_group_ms = 200 # an audio group's duration
max_video_group_ms = 2000 # a longer video group asks the publisher for a keyframe
keyframe_request_interval_ms = 1000
[timeline]
max_skew_ms = 250 # |mapped time - arrival| bound; past it, re-anchor
[whep]
trust = [] # first-hop keys whose receipts WHEP accepts; empty: this gateway's
hold_ms = 5000 # how long a group's objects wait for its receipts
catalog_wait_ms = 2000
retry_after_s = 2 # what a 409 asks a player to wait
[summary]
# out_path = "sessions.jsonl" # session records, one JSON line each; absent: kept in memory only
# link_out_path = "links.hex" # contribution link records (WLK1), one hexadecimal line each
[rtmp]
# Enhanced RTMP ingest (live-ingest §12); off unless a listener is set.
listen = "127.0.0.1:1935" # RTMP over TCP
# tls_listen = "127.0.0.1:1936" # RTMPS, with the two files below
# cert_path = "rtmps-chain.pem"
# key_path = "rtmps-key.pem" # PKCS #8
url = "" # what a stream key's response names; empty: rtmp://<listen>/live
stream_key_ttl_s = 60 # a stream key from POST /rtmp is good this long for its first use
max_sessions = 64
max_message_bytes = 8388608 # the largest message the chunk stream takes
max_bitrate_kbps = 40000 # per publisher, every track, over limits.bitrate_window_ms
connect_timeout_ms = 15000 # a connection that has not published by then is closed
idle_timeout_ms = 20000
chunk_size = 4096 # the chunk size the gateway sends with
reconnect_url = "" # the tcUrl a reconnect request names; empty: none
reconnect_grace_ms = 5000 # how long a session stays after a reconnect request
[injector]
# SCTE 104 automation into signed cues (cue-injection); off unless listen is set.
# listen = "127.0.0.1:5167"
room = "" # the room id, 64 hexadecimal digits, one of [[rooms]]
# key_path = "injector.key" # 32 bytes, the injector principal's Ed25519 seed
# grant_path = "injector.wrg1" # the principal's room grant, permitting cue and meta
leap_seconds = 18 # GPS - UTC, for a UTC timestamp()
fps_num = 30000 # the frame rate duration_extension_frames counts in
fps_den = 1001
dpi_pid_index = [] # the DPI_PID_index values answered; empty: any
max_pending = 256 # cues held for splices still to come
# Contribution over SRT and RIST (WAI extensions/live-contribution.md). A publisher POSTs
# /srt or /rist with its room grant and proof, and gets a one-time session.
[contrib]
host = "" # the host name stated in a session's answer
session_ttl_s = 60 # a session not connected by then is dropped
max_sessions = 16
max_bitrate_kbps = 80000 # per session, all streams, over limits.bitrate_window_ms
record_interval_ms = 10000 # how often a session signs a part of its link record
idle_ms = 5000 # a link that receives nothing this long is ended
[contrib.srt]
# listen = "127.0.0.1:9000" # the SRT listener; absent: /srt is 404
latency_ms = 120 # the connection's is the larger of the two ends'
pbkeylen = 16 # AES key bytes: 16, 24 or 32
call_allow = [] # publishers' listeners the gateway may call: "ip:port" or "ip"
[contrib.rist]
enabled = false # needs a build with the feature `rist`
bind_ip = "127.0.0.1"
port_min = 0 # the ports sessions are given; 0 and 0: any free port
port_max = 0
buffer_ms = 1000
aes = 128 # the Main Profile's PSK key bits: 128 or 256