Skip to main content

WAI Extension: Uncompressed Essence Contribution

Mirrored from the canonical text at commit c5e7133e ().

Status: Draft. Carries a production’s uncompressed IP essence into a room through the ingest gateway of live-ingest: the video, the PCM sound and the ancillary data of a SMPTE ST 2110 contribution, each an RTP stream a description (SDP) names. This text says how each stream is read and what it is held to (its description, its sequence numbers, its timestamps), what a room receives of it, what is not carried, and every reason a description, a packet or a session is refused for. A whole video frame is encoded onto the video floor and published as wai.video.av1; sound is published as wai.audio.flac; an SCTE 104 message in the ancillary data becomes the room’s signed cues; and the gateway signs, in its session record, a statement of each stream with every loss counted. It registers no capability and no record. No new transport: WAI defines none by charter. The reference implementation is joule-moq-ingest (module st2110; the session behind its st2110 feature) in joule-code/joule-code-rs/crates/; the corpus is live-conformance/st2110/, and its second implementation is live-conformance/st2110_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision, each whole unless a clause is named: RFC 3550 §5; RFC 4175; RFC 3190 §4; RFC 3551 §4.5.11; RFC 8331; RFC 8866; RFC 7273 §4 and §5; RFC 4570 §3; RFC 9639 §8.2 and §9; SMPTE ST 2110-10:2022; ST 2110-20:2022; ST 2110-30:2025; ST 2110-40:2023; ST 291-1:2011 (the ancillary data packet’s words and checksum); ST 2010:2008; and, for §9 alone, ST 2059-1:2021 (the epoch and the alignment of signals to it). The SMPTE documents were read as their publisher serves them at pub.smpte.org on 11 November 2026. A section number of one of those texts here is that revision’s. §3 says what was not read.

1. Scope

In scope: reading a description of streams (§4); the RTP header and the sequence a stream is held to (§5); video rows into frames (§6), PCM into blocks (§7) and ancillary data packets into records, with the SCTE 104 messages they carry (§8); what a description says of its clocks, and what a receiver with no reference clock may say of them (§9); a session that puts the streams into a room’s tracks (§10); and the reasons (§11).

Out of scope: sending essence; a reference clock, and any lock to one; the traffic shaping and delivery timing of a sender; redundant legs; and everything a room, a grant, a track, a receipt and a catalog are, which live-rooms, live-ingest and moq-streaming-format define and this text uses unchanged.

Relationship to the core spec: this extension names no payload format. Its objects are wai.video.av1 and wai.audio.flac envelopes as SPEC §5 frames them, and its receipts are the first hop’s, as live-ingest §8 states them.

2. Terms

3. Texts, and what this revision does not read or do

Every rule of §4 to §9 is a rule of a text the status note lists, or says that it is this extension’s own. Where this text and one of those disagree on a format, that text governs the format and this text is in error.

Not read, and so not relied on: AES67, which ST 2110-30 builds on (§7 holds sound to the RFCs’ payload formats and to a description’s own packet time, and to nothing AES67 alone states); ST 2110-21 beyond the names of its sender types; ST 2059-2 (the PTP profile); IEEE 1588; ST 2022-7; ST 334 and CTA-708 (captions in ancillary data); ST 12-2 (time code in ancillary data); ST 352 (the payload identifier a description’s VPID_Code quotes).

Not done, each refused or counted where it arises, never read as something else:

whatwhere it shows
a sender’s traffic shaping and delivery timing (ST 2110-21: narrow, narrow linear and wide senders)a description’s TP is kept and stated as not checked (§10.7)
lock to a reference clock; traceability of a clock§9: stated as the description states it, never as held
interlaced and segmented scanningsdp_scan_unsupported
constant-luminance, ICtCp, XYZ and key samplings; 16-bit floating point samplessdp_sampling_unsupported, sdp_depth_unsupported
redundant legs (ST 2022-7)sdp_redundancy_unsupported
compressed video (ST 2110-22), AES3 transport (ST 2110-31) and any other subtypesdp_media_unsupported
decoding captions and time code out of their ancillary data packetscounted as not carried, by DID and SDID (§10.6)
RTCPignored where it arrives

4. The description

4.1 Lines

A description is UTF-8 text of lines ending in CRLF or LF, each <letter>=<value> (RFC 8866 §5). It MUST have v=0, an o= and an s= line (sdp_malformed otherwise) and at least one m= line (sdp_no_media). Lines before the first m= are the session’s; the lines after an m= are that stream’s. A session whose attributes hold a=group:DUP (ST 2110-10 §8.5) is sdp_redundancy_unsupported.

For each m=<media> <port> <proto> <fmt> line: fewer than four fields, or a port, a format or its rtpmap’s clock rate that is not a decimal number, is sdp_malformed; a protocol other than RTP/AVP, or more than one format, is sdp_media_unsupported. The stream’s payload type is its format. Its a=rtpmap:<pt> <name>/<rate>[/<channels>] names it; none for its payload type is sdp_rtpmap_missing. Its a=fmtp:<pt> parameters are <name>=<value> pairs and standalone names separated by ; (ST 2110-20 §7.1); an empty name or value is sdp_fmtp_value.

The media and the name decide the reader: video and raw (§4.2), audio and L16 or L24 (§4.3), video and smpte291 (§4.4); any other pair is sdp_media_unsupported. Then, in this order: a payload type outside 96 to 127 (ST 2110-10 §6.2) is sdp_payload_type; a stream with no connection address of its own or the session’s (c=IN IP4 <address> or IP6, RFC 8866 §5.7) is sdp_connection; TSMODE other than NEW, SAMP or PRES, and a TSDELAY or MAXUDP that is no decimal number, are sdp_fmtp_value.

An inclusive a=source-filter (RFC 4570 §3) names the stream’s source address. a=mid, TP, MAXUDP and a sound stream’s channel-order are kept as written.

4.2 Video

The clock rate MUST be 90000 (ST 2110-20 §7.1; sdp_clock_rate). The parameters sampling, depth, width, height, exactframerate, colorimetry, PM and SSN are required (ST 2110-20 §7.2); one absent is sdp_fmtp_missing.

TCS is SDR and RANGE is NARROW where a description states none (ST 2110-20 §7.3, §7.6).

4.3 Sound

L16 (RFC 3551 §4.5.11) and L24 (RFC 3190 §4). The clock rate, which is the sampling rate (ST 2110-30 §6.1), is 44100, 48000 or 96000 (sdp_clock_rate otherwise). The channel count is 1 where rtpmap gives none, and 1 to 64 (sdp_channels otherwise). a=ptime is a decimal number of milliseconds with at most three fractional digits, above 0 and at most 1000 (sdp_fmtp_value otherwise). Where the packet time is a whole number of sample frames at the sampling rate, that number is the stream’s sample frames a packet; a description with no ptime, or one that is not a whole number of them, states none.

4.4 Ancillary data

The clock rate MUST be 90000 (ST 2110-40 §5.3; sdp_clock_rate). Each DID_SDID={0x..,0x..} (RFC 8331 §4) and a VPID_Code of 0 to 255 are kept; a malformed one is sdp_fmtp_value.

5. RTP and the sequence

A packet is read as RFC 3550 §5.1 lays it out: fewer than 12 octets, or a CSRC list or a header extension (§5.3.1) that runs past its end, is rtp_short; a version other than 2 is rtp_version. A header extension is passed over (ST 2110-10 §6.2). Where the padding bit is set, the packet’s last octet counts the padding: 0, or more than the payload holds, is rtp_padding. A payload type that is not the stream’s is rtp_payload_type. The first packet read fixes the stream’s SSRC; a packet of another is ssrc_changed.

The sequence. A video or an ancillary data stream’s sequence number is 32 bits: the header’s 16, below the 16 its payload header begins with (RFC 4175 §4.1; RFC 8331 §2.1). A sound stream’s is the header’s 16, extended by its distance from the number expected: within half its space ahead, it is ahead. The first packet read sets the number expected to its own plus one. For each later packet, after the checks above and before any other:

A packet refused before its sequence number is read is not counted in the sequence, and the packet after it then shows it as lost.

6. Video rows into frames

6.1 Pgroups

Samples are packed most significant bit first, each depth bits, in the order ST 2110-20 §6.2 gives (Tables 1 to 3), which RFC 4175 §4.3 gives too:

samplingone cluster of samplesspans
YCbCr-4:4:4Cb, Y, Crone pixel
RGBR, G, Bone pixel
YCbCr-4:2:2Cb, Y0, Cr, Y1two pixels of a row
YCbCr-4:2:0Y00, Y01, Y10, Y11, Cb, Crtwo pixels of each of two rows

A pgroup is the fewest clusters that make whole octets: one at 8 and 16 bits; at 10 bits four (4:4:4, RGB), one (4:2:2) or two (4:2:0); at 12 bits two (4:4:4, RGB) or one. A frame’s samples are three planes: luma (or red) at width × height, and two more at the same size (4:4:4, RGB), half the width rounded up (4:2:2), or half of each rounded up (4:2:0).

6.2 A packet

After §5, in this order:

  1. A payload of fewer than 2 octets is srd_truncated. The sequence number is read (§5): a duplicate is refused; a packet behind is kept only if the frame of its timestamp is still open, and refused late otherwise.
  2. The frame (§6.3): a packet that is not behind and whose timestamp is not the open frame’s ends that frame. A packet whose timestamp is that of the frame ended last is after_marker.
  3. The sample row data headers (ST 2110-20 §6.1.4), six octets each: a length, the field bit and a 15-bit row, the continuation bit and a 15-bit offset. Fewer than six octets left for a header is srd_truncated; a fourth header is srd_count; a field bit of 1 is field_in_progressive. A length of 0 is allowed in a packet’s only header, which then has no data, and is srd_length beside another header. Data shorter than the headers’ lengths together is srd_truncated.
  4. Each segment, in order: a row not below height is row_out_of_range; in 4:2:0 an odd row is srd_offset; an offset not below width is offset_out_of_range. Then its place: a length that is not a whole number of pgroups is srd_length; an offset that is not a multiple of a pgroup’s pixels is srd_offset; an end (the offset plus the pgroups’ pixels) past width rounded up to a whole pgroup is offset_out_of_range. Then, where no packet was lost or refused since the segment before it, the segment MUST start where that one ended (the next pixel of its row; or, where it reached width, the first pixel of the next row or row pair; a frame’s first segment at row 0, offset 0 where the frame before it arrived whole): one that starts earlier is srd_order, one that starts later format_mismatch. That rule is this extension’s: ST 2110-20 §6.1.4 and §6.1.5 say rows and offsets only increase, and a sender that leaves samples out with nothing lost has described another picture than it sends.
  5. Depth. A segment refused in step 4 for srd_length, for its end, or for format_mismatch, whose place holds entirely at another depth the sampling has a pgroup for (its length, its offset, its end, and its start against the segment before it read at that depth), is refused depth_mismatch instead: the packets are of a depth the description does not state.

A refused packet contributes no sample, and the packet after it is held to no place; nor is the first packet after a frame that no marker ended. An accepted packet’s samples are placed; samples a segment holds past width are fill and are not read (ST 2110-20 §6.2.1).

6.3 Frames

A frame is the packets of one RTP timestamp. It ends at a packet with the marker bit (ST 2110-20 §6.1.2), or, with the mark marker_missing, when a packet of another timestamp arrives or the stream ends. A packet kept from behind (§5) gives its frame the mark reordered.

A frame is complete when every sample of it arrived. A frame that is not complete says so, and lists every row with a sample missing; a missing sample is not replaced, repeated or interpolated. What a receiver does with an incomplete frame is §10.3.

7. PCM into blocks

Each accepted packet is one block: its payload’s samples, signed two’s complement, most significant octet first, the channels of a sample frame interleaved, at the RTP timestamp of its first sample frame. After §5, in this order: the sequence (duplicate; a packet behind is late, since blocks leave in order); a payload that is empty or not a whole number of sample frames is depth_mismatch where it is a whole number of them at the other of the two depths, and pcm_length otherwise; where the description states the sample frames a packet (§4.3) and the packet holds another number, depth_mismatch where its octets hold the stated number at the other depth, and ptime_mismatch otherwise.

A block that does not start at the timestamp where the block before it ended carries the mark timestamp_jump; where it starts later, the sample frames between are counted missing. No sample is made for them.

8. Ancillary data

8.1 Records

A payload (RFC 8331 §2.1) is the 16 high bits of the sequence number, Length, ANC_Count, the two bits F, and 22 reserved bits; then each ancillary data packet: C (1 bit), Line_Number (11), Horizontal_Offset (12), S (1), StreamNum (7), the 10-bit words DID, SDID, Data_Count, as many user data words as Data_Count’s low 8 bits say, and Checksum_Word, then zero bits to the next 32-bit word.

After §5, in this order: a payload of fewer than 8 octets is anc_truncated; the sequence (duplicate, late); F of 0b01 is anc_field; a count of 0 beside a length that is not 0 is anc_count; a payload whose octets after the header are not Length is anc_length. Then each packet: data that ends inside it is anc_truncated; a Data_Count whose bit 8 is not the even parity of bits 7 to 0, or whose bit 9 is not the inverse of bit 8 (ST 291-1), is anc_parity, since the count is then no count. Packets that end before Length does, or after, are anc_length. Each of these refuses the whole payload.

One ancillary data packet is dropped, and the others of its payload kept, where its DID or SDID fails that parity (anc_parity) or its Checksum_Word is not the nine low bits of the sum of the nine low bits of every word from DID to the last user data word, with bit 9 the inverse of bit 8 (anc_checksum). Every other packet is a record: the payload’s timestamp and F, its five location fields, its DID and SDID (their low 8 bits) and its user data words whole.

8.2 SCTE 104 messages

A record of DID 0x41 and SDID 0x07 carries an SCTE 104 message (ST 2010 §5). Each user data word holds one octet in bits 7 to 0 under the parity of §8.1; a word that fails it refuses the record, scte104_parity. The first octet is the payload descriptor: bits 7 to 5 zero and bits 4 and 3 01, or scte104_version; bit 2 says the message continues in the next packet, bit 1 that this packet continues one, bit 0 that the message repeats one of an earlier frame. A packet that continues nothing, a first packet while a message is still open, and a message still open when a record of another timestamp arrives or the stream ends, are scte104_sequence. A whole message’s length MUST be the messageSize its third and fourth octets state (scte104_size).

9. Clocks

What a description says of a stream’s clock is read from a=ts-refclk (RFC 7273 §4; ST 2110-10 §8.2) and a=mediaclk (RFC 7273 §5; ST 2110-10 §8.3), the stream’s own or the session’s, and is one of four classes:

classthe description states
ptp_traceable_statedts-refclk:ptp=<version>:traceable and mediaclk:direct=0
ptp_grandmaster_statedts-refclk:ptp=<version>:<EUI-64>[:<domain>] and mediaclk:direct=0
not_traceableany other pair: localmac=, another source, mediaclk:sender, an offset that is not 0, a rate beside the offset
unstatedeither attribute absent

TSMODE (ST 2110-10 §8.7) says what a timestamp is a time of: SAMP the sampling instant, PRES a timestamp kept from an input that did not say, NEW one made at the sender’s egress; a description that states none means NEW.

A class is a statement of the description. A receiver that holds no reference clock MUST NOT state that a stream is locked, that its clock is traceable, or that a timestamp is a sampling instant: it states the class and the mode as what the description says. It MUST state a stream of class not_traceable or unstated as such wherever it states anything of the stream’s time.

Reading an instant from a timestamp. For the two ptp_ classes, ST 2110-10 §7.3 makes an RTP timestamp the count of the RTP clock since the reference clock’s epoch, modulo 2^32, and ST 2059-1 puts that epoch at 1970-01-01T00:00:00 on the PTP timescale. A receiver MAY read an instant from a timestamp: the instant nearest its own clock’s whose count is the timestamp. It needs the seconds the PTP timescale is ahead of UTC, which it is given (37 since 2017) and does not learn from the stream. The result is the description’s claim evaluated, not a measurement: a receiver MUST check it against its own clock and state it only where the two agree within a bound it states (§10.5). For the other two classes no instant is read from a timestamp.

10. Into a room

10.1 Admission

A publisher POSTs /st2110 with its room grant as the bearer token and the proof of its key, admitted as live-ingest §3 admits a WHIP publisher, with a JSON body:

membermeaning
sdpthe description, as a string. REQUIRED
sourcethe digital source type the publisher states for the essence: digitalCapture, computationalCapture, screenCapture or digitalCreation (synthesis §3.2). OPTIONAL

The gateway reads the description (§4); a refusal of §4 is answered 422 with its reason. It then refuses what it does not carry (§10.8), binds a UDP socket for each stream (§10.2), and answers 201 with Location: /st2110/s/<session> and a JSON object: session; for each stream its index, its media, the port to send it to, its clock class, its TSMODE and the receive buffer its socket was given (§10.9); whether an origin claim will be signed; and, where there is a video stream, encoder: which encoder will encode it, the one that was asked for, and why the two differ where they do (§10.3). The session’s resource answers its own token: DELETE ends the session.

10.2 Streams

10.3 Video

A complete frame (§6.3) is encoded as AV1 in the Main profile at the Main tier, at level 4.1 or below (the video floor, SPEC §5), and published as one wai.video.av1 object, a group at each keyframe, exactly as live-ingest §5 publishes a frame. The Main profile is 4:2:0: a 4:2:2 frame’s two chroma planes are halved in height first, each output row the mean, rounded half up, of the two rows it replaces (the last row alone where the height is odd). An 8-bit frame is encoded at 8 bits and a 10-bit frame at 10.

The encoder is held to the stream’s frame rate. A contribution is live: an encoder that does not keep the stream’s rate is not carrying it. A gateway:

Which encoder. A gateway may hold more than one encoder onto the floor (a GPU’s AV1 encode engine through the operating system’s own interface, a software encoder built for real time, a slower one that needs nothing but the gateway’s own build), and takes one by configuration. One asked for by name that the host does not have is a refusal to start, with the reason; or, only where the operator has said so, the next one that is present, stated at start, in the session’s answer (§10.1) and in its record (§10.7). An encoder is never used in another’s name.

The floor is checked, not assumed. Before it is used, an encoder encodes pictures the gateway computes, at each depth, and the sequence header of what it makes is read: the Main profile, the Main tier, seq_level_idx 9 or below, the picture’s size as its largest frame. One whose stream is outside the bound is refused with what was found, whatever it is and however fast. Every keyframe of every session is held to the same reading before it is published: a session whose encoder leaves the floor ends encoder_outside_floor, and that unit is not published.

The picture’s size. An encode engine may code its frames a few rows or columns larger than the picture, to its own block alignment (one measured codes 1082 rows for a picture of 1080). Such a stream is within the level, and it is the stream’s picture only where it says so: the gateway requires every keyframe to state the picture’s size as its render size (AV1 §5.9.6) and to be coded at that size or less than 64 samples more a side, refuses the encoder for the stream otherwise, and states both sizes in the session’s record. The track’s framing states the size the frames are coded at, as for any publisher’s stream.

Two things are never published, and each is counted in the session’s record (§10.7):

A sink sees either as a longer time between two objects (§10.5). The AV1 a session writes is lossy, and is lossier where the gateway lowered quality to hold the rate; nothing here says how lossy, and a receipt attests the object published, not the essence.

10.4 Sound

Blocks are gathered into objects of wai.audio.flac: each a FLAC stream (RFC 9639) of one frame whose subframes are verbatim (§9.2.4 there), so every sample is the sample that arrived, at its depth. An object ends when it holds the gateway’s object duration (20 ms by default) and before a block marked timestamp_jump: an object never spans samples that did not arrive, and none is made for them. One to eight channels are carried (§8.2 there).

10.5 Time

10.6 Ancillary data

10.7 What the gateway signs

Receipts. Every object’s receipt, as live-ingest §8 states them: the first hop’s.

The session record (live-ingest §16), when the session ends, with protocol st2110. Its detail holds, beside the track counts of every ingest: the description’s digest (SHA-256 of its octets); for each stream its statement and the statement’s digest, its packets, the sequence numbers lost and arrived behind, the packets refused by reason (§11), the datagrams from other sources, what its reader made (frames and incomplete frames; blocks, jumps and sample frames missing; records and packets dropped by reason), what was not published by reason (§10.3), the receive buffer its socket was given, and where its capture instants came from (§10.5); the ancillary data not carried, by DID and SDID; the SCTE 104 messages by outcome; the datagrams dropped because the session’s queue was full; the origin claims; and encoder: which encoder encoded (backend, its version, whether a hardware engine, and where it was loaded from), the encoder the configuration asked for, fallback (why the two differ, or null), and what its stage counted: the picture’s size and the size its frames were coded at, the frames offered, encoded and not encoded because the queue was full, the drop policy in words, the queue’s length and the most it held, the keyframes and octets made, the mean and the longest time a frame took against the frame interval, and every move between quality settings with the frame it was made at and why. Every frame offered is encoded or counted there. The counts are integers; no rate is stated.

A stream’s statement is a JSON object with exactly these members: kind ("wai-essence-statement"), description (the description’s digest), stream (its index), media, format (the parameters of §4.2, §4.3 or §4.4 as read), payload_type, destination, source (the address and port its datagrams came from, or null), ssrc, clock (§9’s class), tsmode, sender_type (the description’s TP, or null), sender_type_checked ("no"), and declared_source (§10.1’s source, or null). Its digest is SHA-256 over its RFC 8785 form.

The origin claim. Where the publisher stated a source, the gateway signs, for each media track, an origin claim (synthesis §3.1) whose subject is the track from its first group, of step capture and class captured, source the stated one, operation st2110:contribution, and record the digest of the stream’s statement. The gateway signs as the encoder; that the essence is a capture is the publisher’s statement, made under its grant, and the claim carries the gateway’s authority and no more (synthesis §3.1). With no source stated, no claim is signed. The claims are in the session’s record; this revision defines no carriage of them in the room.

10.8 Refusals of a session

A description that reads (§4) is refused, with the HTTP status shown, where the gateway does not carry it:

reasonstatuswhen
essence_streams_unsupported422more than one video stream, one sound stream or four ancillary data streams
essence_format_not_carried422video that is not 4:2:2 or 4:2:0 at 8 or 10 bits; sound of more than eight channels
essence_outside_floor422a frame size or rate past level 4.1’s picture size or display rate
essence_encoder_refused422the gateway’s encoder does not take the stream (its size or its depth), with the encoder’s reason
publish_not_permitted403the grant does not let its principal publish a stream’s media kind
multicast_not_permitted403a multicast destination where the gateway joins none
session_conflict409the principal already contributes to the room
body_malformed400no sdp, or a source that is not one of the four

10.9 Bounds

A session holds one bounded queue of datagrams and one bounded queue of frames for its encoder; a datagram or a frame that finds its queue full is dropped and counted, and never waits. A stream’s socket is asked for a receive buffer that holds more than an instant of it, and the session states what the host gave: a high-definition stream is of the order of a hundred thousand datagrams a second, and a reader scheduled a moment late loses to a small buffer what no later stage can count as anything but an incomplete frame. Sessions are bounded as live-contribution §8 bounds contribution sessions. Uncompressed video is of the order of a gigabit a second at high definition (RFC 4175 §8): a gateway’s host, its network path and its encoder each bound what a session can carry, and a throughput figure is a dated measurement of one host, never a property of this extension.

11. Reasons

Refusals of a description (§4):

reasonwhen
sdp_malformednot lines of <letter>=<value>; no v=0, o= or s=; an m= line that does not read
sdp_no_mediano m= line
sdp_media_unsupporteda protocol, a number of formats or a media subtype this text does not read
sdp_rtpmap_missingno rtpmap for the payload type
sdp_payload_typea payload type outside 96 to 127
sdp_clock_ratea clock rate the format does not have
sdp_fmtp_missinga required format parameter absent
sdp_fmtp_valuea parameter value its text does not allow
sdp_sampling_unsupporteda sampling of ST 2110-20 this text does not read
sdp_depth_unsupported16-bit floating point samples
sdp_scan_unsupportedinterlaced or segmented scanning
sdp_redundancy_unsupportedredundant legs
sdp_channelsa channel count outside 1 to 64
sdp_connectionno connection address

Refusals of a packet of any stream (§5):

reasonwhen
rtp_shortfewer octets than its header says
rtp_versiona version other than 2
rtp_paddinga padding count of 0 or past the payload
rtp_payload_typea payload type that is not the stream’s
ssrc_changedan SSRC that is not the stream’s
duplicatea sequence number seen before
latebehind the highest sequence number seen, where the stream no longer takes it

Refusals of a packet of video (§6.2):

reasonwhen
srd_truncatedshorter than its row data headers or their lengths
srd_counta fourth row data header
srd_lengtha length that is no whole number of pgroups; a length of 0 beside another header
srd_offsetan offset inside a pgroup; an odd row in 4:2:0
srd_orderwith nothing lost, a segment that starts before the one before it ended
row_out_of_rangea row not in the picture
offset_out_of_rangea segment that starts or ends past its row
field_in_progressivethe field bit set
after_markerthe timestamp of a frame the marker already ended
depth_mismatchpackets of a depth the description does not state (video, §6.2 step 5; sound, §7)
format_mismatchwith nothing lost, a segment that starts after the one before it ended

Refusals of a packet of sound (§7):

reasonwhen
pcm_lengtha payload that is no whole number of sample frames
ptime_mismatcha packet of another number of sample frames than the description’s packet time

Refusals of a payload of ancillary data, and of one packet in it (§8.1):

reasonwhen
anc_truncateddata that ends inside the header or a packet
anc_lengthLength that is not the octets the payload holds, or not the octets its packets take
anc_counta count of 0 beside a length
anc_fieldF of 0b01
anc_paritya Data_Count whose parity fails (the payload); a DID or SDID whose parity fails (the packet)
anc_checksuma checksum word that is not the words’

Refusals of an SCTE 104 message in ancillary data (§8.2):

reasonwhen
scte104_paritya user data word whose parity fails
scte104_versiona payload descriptor of another mapping version
scte104_sequencea continuation of nothing; a message begun while another is open; a message left open at its frame’s end
scte104_sizea message that is not as long as it states

Marks (§6.3, §7): the frame or the block is kept, and says so.

reasonwhen
reordereda frame that took a packet from behind
marker_missinga frame no marker bit ended
timestamp_jumpa block that does not start where the one before it ended

12. Status and conformance

partstatuswhere
the readers (§4 to §9)implemented, with a reference and a second implementationjoule-moq-ingest st2110; live-conformance/st2110/ and st2110_verify.py
the session (§10)implementedjoule-moq-ingest st2110::session, feature st2110; tests/essence_st2110.rs
the encode stage: its queue, its real-time budget, its drop policy and counts, the choice of an encoder and its probe (§10.3)implementedst2110::encode; its unit tests, and tests/essence_st2110.rs for a named encoder that is absent
the sample loops held to a sample-at-a-time reference (§6.1, §10.3)implementedst2110::convert
a software encoder built for real time, loaded at run time (§10.3)implemented; measured on two hostsst2110::encode::svt; tests/essence_rt.rs
a GPU’s AV1 encode engine through the Video Acceleration API (§10.3)implemented; measured on the one host that has such an enginest2110::encode::va, st2110::encode::obu; tests/essence_rt.rs
hardware AV1 encode on the aarch64 build host and on macOSnone found: the first’s V4L2 encode node enumerates H.264 and H.265 only, and the second’s media framework lists no AV1 encoder (11 November 2026)decisions D22
SCTE 104 in ancillary data to the room’s cues (§10.6)implementedst2110::anc, and the injector of cue-injection
captions and time code in ancillary datanot decoded; counted as not carried§10.6
multicasta group is joined where the configuration lets it; tested as far as a join on a loopback interface§10.2
carriage of origin claims in a roomnot defined§10.7

The corpus. live-conformance/st2110/vectors.json holds descriptions and the RTP packets of their streams, written by the reference’s own sender from pictures and sound it computes from integers (no outside media), with what a reader makes of each: every frame, block and record with the SHA-256 of its samples, every refusal with its reason, every mark, every count. It covers each sampling at each depth with fill; sequence numbers and timestamps across their wraps; and one planted fault a vector, among them a reordered packet, a lost row, a row past the picture’s height, packets of a depth the description does not state, a marker bit on the wrong packet, an ancillary data packet with a bad checksum, and a description whose width disagrees with its packets. Every reason of §11 is shown by a vector that names it. joule-moq-ingest-st2110-vectors --check regenerates it byte for byte; st2110_verify.py, written from this text and the texts it names and sharing no code with the reference, recomputes every expectation, then leaves out each of its own checks in turn and requires the corpus to catch the absence, and alters the corpus one stated value at a time and requires every altered copy to fail.

The session’s test runs on loopback with the reference’s own sender: a 4:2:2 10-bit video stream, two channels of 24-bit sound and an ancillary data stream, with one video packet and one sound packet never sent. It holds that every published object verifies against the gateway’s receipts at a relay subscriber and at the relay’s door; that every keyframe’s object is within the video floor; that the sound decodes to the samples sent, bit for bit, with the lost packet’s sample frames counted and none made; that every frame is published or counted with its reason; that each object states its capture instant and the catalog its playout timing; that the SCTE 104 message became the room’s signed cues; and that the record’s statements, counts and origin claims are as §10.7 says. The sender there holds no reference clock: its description’s clock lines are a fixture for the path of §9, not a statement about a host.

The session held to its frame rate. tests/essence_rt.rs drives the same session with the reference’s own sender pacing whole 4:2:2 10-bit frames over loopback: 1280 × 720 and then 1920 × 1080 at 30 frames a second, 20 seconds each, with every real-time encoder the host has. It fails unless every frame sent reached the encode stage whole, the stage dropped none, every frame was published in order with its own timestamp and verified against the gateway’s receipts, every keyframe is within the video floor and states the stream’s picture, and every temporal unit decodes with a conforming decoder (the host’s libdav1d) to a picture of the stream’s depth whose luma is the luma sent, within a stated distance. The first frames are decoded a second time by this repository’s own decoder (wai-av1, written from the specification’s text) and compared sample for sample with the first decode; what it says is stated. The test reads the host’s load first and refuses to measure on a loaded host, saying so. It is run on request, on a host that has a real-time encoder: no continuous-integration job runs it, and none could on a shared runner.

What holds a frame rate, dated. Every figure here is one host’s on one day, with the load that host carried, and none is a property of this extension.

On 11 November 2026, on a 32-thread x86-64 build host whose GPU’s open driver exposes AV1 encode, shared with other work. The host was never quiet: given seven minutes, the test refused to measure (a one-minute load of 14 to 18), as it is written to. The figures below were then taken with its load check overridden by hand and are stated with the load they were taken under: what was held on that host while it carried that load, not a measurement of it idle. 4:2:2 at 10 bits in, 20 seconds a run; every frame published was verified, and every temporal unit decoded by libdav1d 1.5.3 to the picture sent.

encoderstreampicturespublisheddropped behind the encodera frame took: mean, longestone-minute load
the GPU’s encode engine1280 × 720 at 30computed600 of 60002.7 ms, 8.8 ms18
1920 × 1080 at 30computed600 of 60004.7 ms, 22.6 ms18
1280 × 720 at 30recorded600 of 60002.6 ms, 10.1 ms17
1920 × 1080 at 30recorded600 of 60004.9 ms, 20.4 ms17 to 21
1920 × 1080 at 60computed1200 of 120004.5 ms, 20.6 ms16 to 20
1920 × 1080 at 60recorded1200 of 120004.5 ms, 20.1 ms17 to 18
the software encoder built for real time1280 × 720 at 30computed600 of 60009.6 ms, 51.9 ms17 to 19
1920 × 1080 at 30computed600 of 600010.3 ms, 60.4 ms18 to 19
1280 × 720 at 30recorded600 of 60006.7 ms, 71.6 ms20 to 21
1920 × 1080 at 30recorded600 of 60006.8 ms, 83.5 ms18 to 20
1920 × 1080 at 60computed1198 of 120028.4 ms, 78.7 ms16 to 17
the fallback (10 seconds)1280 × 720 at 30computed247 of 3005339.8 ms, 160.2 ms18

The same day, on a 14-thread aarch64 build host, no session was measured: under the load it carried when the test was run (a one-minute load of 25 to 32, the test’s check overridden by hand), the receive buffer the host gives a socket (425 984 octets for the 16 MiB asked, under 3 ms of a 1920 × 1080 stream) lost packets on the way in (228 of 242 100 at 1280 × 720, 16 938 of 544 350 at 1920 × 1080), which the test reports as that and not as an encoder’s doing. The software encoder alone, fed pictures as fast as it took them at a load of 10 to 14, took 13.2 ms a 1280 × 720 picture and 22.6 ms a 1920 × 1080 one (128 ms at longest); the fallback 149 ms and 311 ms. That host has no hardware AV1 encode (D22).

History. The session first landed, earlier on 11 November 2026, with the pure-Rust encoder on one thread and a reader that took samples a bit at a time: 5.0, 1.8 and 0.6 frames a second at 640 × 360, 1280 × 720 and 1920 × 1080 on the x86-64 host at a load of 31. Profiled there, a 1920 × 1080 frame took 882.9 ms, 839.2 of them in the encoder and 40.6 in the reader. Those figures describe nothing a gateway does now.

13. Security and privacy considerations