<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc version="3" ipr="trust200902" docName="draft-ramadan-moq-fec-00" submissionType="IETF" category="std" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true">

<front>
<title abbrev="MoQ FEC">Forward Error Correction for Media over QUIC</title><seriesInfo value="draft-ramadan-moq-fec-00" stream="IETF" status="standard" name="Internet-Draft"></seriesInfo>
<author initials="O." surname="Ramadan" fullname="Omar Ramadan"><organization>Blockcast</organization><address><postal><street></street>
</postal><email>omar@blockcast.net</email>
</address></author><date year="2026" month="October" day="14"></date>
<area>wit</area>
<workgroup>moq</workgroup>
<keyword>FEC</keyword>
<keyword>RaptorQ</keyword>
<keyword>MoQ</keyword>
<keyword>Reed-Solomon</keyword>
<keyword>ATSC 3.0</keyword>

<abstract>
<t>This document specifies a mechanism for transmitting Forward Error
Correction (FEC) repair data alongside source media in Media over
QUIC (MoQ) sessions.  It defines catalog-based signaling of FEC
configuration -- including a derived RaptorQ Object Transmission
Information that requires no in-session messages -- conventions for
repair track naming, the format of repair objects, and the ISO/IEC
23008-1 block profile that fixes how source symbols and FEC blocks are
formed and identified.  RaptorQ
(RFC 6330) is the mandatory-to-implement and only fully specified
FEC scheme; an algorithm registry provides extension points for
additional schemes.  FEC enables receivers to recover from packet
loss without retransmission latency.  This specification is designed for
compatibility with ATSC 3.0 (A/331) and ARIB STD-B60 broadcast systems.</t>
</abstract>

</front>

<middle>

<section anchor="introduction"><name>Introduction</name>
<t>Media over QUIC (MoQ) <xref target="I-D.ietf-moq-transport"></xref> provides a
publish/subscribe transport for real-time media.  While QUIC provides
reliable delivery through retransmission, the latency incurred by
retransmission can be unacceptable for ultra-low-latency (ULL)
applications such as live sports, gaming, and interactive broadcasts.</t>
<t>Forward Error Correction (FEC) enables receivers to recover lost
packets using redundant repair data, without waiting for
retransmissions.  This is particularly valuable in wireless
environments where burst packet loss is common.</t>
<t>This document defines:</t>

<ol spacing="compact">
<li>A catalog extension carrying the complete FEC configuration,
which is authoritative for MoQ receivers</li>
<li>A normative derivation of the RaptorQ Object Transmission
Information (OTI) from the catalog fields and the Repair FEC
Payload ID of each block, so that catalog-only receivers
(including multicast and sessionless receivers) can fully
configure their decoders</li>
<li>A naming convention for repair tracks</li>
<li>The format of repair objects containing FEC symbols, and the block
profile <tt>iso-ssbg1-v1</tt>, which forms source symbols and FEC blocks
as Annex C of <xref target="ISO.23008-1"></xref> does</li>
<li>Interleaving strategies to protect against burst loss</li>
<li>Relay tolerance requirements that keep FEC signaling extensible</li>
<li>Compatibility mappings for ATSC 3.0 and ARIB STD-B60 <xref target="ARIB-B60"></xref>
broadcast systems</li>
</ol>
<t>The mechanism protects MMTP-packaged tracks <xref target="MOQ-MMT"></xref>; Section 7.3
of this document specifies the protected source symbol, and Section 13
describes the relationship to CMAF packaging informatively.</t>
</section>

<section anchor="terminology"><name>Terminology</name>
<t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;, &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;,
&quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;, &quot;NOT RECOMMENDED&quot;, &quot;MAY&quot;, and
&quot;OPTIONAL&quot; in this document are to be interpreted as described in
BCP 14 <xref target="RFC2119"></xref> <xref target="RFC8174"></xref> when, and only when, they appear in all
capitals, as shown here.</t>
<t><strong>Source Track</strong>: A MoQ track carrying media data (e.g., video, audio).</t>
<t><strong>Repair Track</strong>: A MoQ track carrying FEC repair symbols for a
corresponding source track, as MMTP FEC repair packets
(<xref target="ISO.23008-1"></xref> Section C.4.3).  The layer-0 repair track
(Section 6.3) carries the FEC repair flow (<xref target="ISO.23008-1"></xref> 3.1.9) that
an ISO AL-FEC message names for the source track's FEC encoded flow
(3.1.7); further repair layers (Section 6.3) and a keyframe overlay
(Section 6.4) are repair tracks that only the catalog declares
(<xref target="MOQ-MMT"></xref> Section 8.3).</t>
<t><strong>Source Block</strong>: A sequence of SSB_length source symbols,
1 &lt;= SSB_length &lt;= K, over which FEC encoding is performed, where
SSB_length is the block's source symbol count (Section 7.1) and K the
track's <tt>sourceSymbols</tt> (Section 5.1); the ISO source symbol block
(3.1.34), generated from a source packet block (3.1.32).  A block of
SSB_length source symbols is an <xref target="RFC6330"></xref> source block whose K, in
the notation of <xref target="RFC6330"></xref>, is SSB_length; this document's K is the
catalog bound instead.  The extension of that source block to K'
symbols by padding (<xref target="RFC6330"></xref> Section 5.3.1) happens inside the
encoder and the decoder and is not visible on the wire, and this
document defines no K' of its own.</t>
<t><strong>Source Symbol</strong>: A fixed-size unit of source data used for FEC
encoding; under the block profile of this document, one FEC source
packet framed as Section 7.3 specifies.</t>
<t><strong>Repair Symbol</strong>: A symbol generated by the FEC encoder that can be
used to recover lost source symbols.</t>
<t><strong>FEC Block</strong>: The combination of SSB_length source symbols and P repair
symbols; the ISO encoding symbol block (3.1.5).</t>
<t><strong>Repair Layer</strong>: One of possibly several repair tracks protecting the
same source blocks of a source track, each carrying a disjoint range of
the block's repair symbols (Section 6.3).  All layers of a source track
share one source block partition and differ only in how many repair
symbols they carry.  Layer 0 is the track named by <tt>repairTrack</tt>.</t>
<t><strong>Layer Index</strong>: The integer <tt>repairLayer</tt> giving a layer's position in
the ordered set of repair layers of one source track.  Layer 0 is the
base layer; enhancement layers are numbered contiguously from 1.</t>
<t><strong>RS_ID Offset</strong>: The first Repair Symbol ID a layer may use; O_i for
layer i (Section 6.3.2).</t>
<t><strong>Keyframe Overlay</strong>: A second, independent FEC instance over a source
track whose source symbols are only the fragments of Random Access
Points, with its own source symbol count, its own repair symbols, and
its own repair track, declared with <tt>&quot;scope&quot;: &quot;keyframe&quot;</tt>
(Section 6.4).  An overlay is not a repair layer and carries no layer
index.</t>
<t><strong>Interleave Depth</strong>: When positive, the complete time span, in
milliseconds, of one FEC source/repair packet block, signaled as
<tt>interleaveDepthMs</tt> (Section 5.1); the catalog form of
<tt>protection_window_time</tt> in <xref target="ISO.23008-1"></xref> Sections 11.2 and C.6.3.
Zero selects the ISO packet-count alternative and is not a millisecond
span.</t>
<t><strong>Object Transmission Information (OTI)</strong>: Parameters required to
configure a RaptorQ decoder, as defined in <xref target="RFC6330"></xref>.</t>
<t><strong>SS_ID</strong>: The 32-bit sequence number of a source symbol, carried in
the Source FEC Payload ID of its FEC source packet (<xref target="ISO.23008-1"></xref>
Section C.5.2).  It advances by one per FEC source packet and wraps
modulo 2^32 (Section 7.5).</t>
<t><strong>SS_Start and SSB_length</strong>: The first SS_ID of a source block and the
block's source symbol count, carried in the Repair FEC Payload ID
of every repair packet of the block (Section 7.1).  A block is the
SS_ID range [SS_Start, SS_Start + SSB_length) and is identified by its
SS_Start; this document defines no block number.</t>
<t><strong>Block Profile</strong>: The rules that fix how a source symbol is formed
from a source packet and how FEC blocks are sized, delimited and
identified, named per FEC-protected source track by <tt>fec.blockProfile</tt>
(Section 5.1).</t>
</section>

<section anchor="protocol-overview"><name>Protocol Overview</name>
<t>The protocol operates as follows (Appendix A.1 shows the exchange):</t>

<ol spacing="compact">
<li>Subscriber obtains the catalog and reads the track's <tt>fec</tt>
object (Section 5), which carries the complete FEC configuration</li>
<li>Subscriber sends SUBSCRIBE for source track</li>
<li>Publisher responds with SUBSCRIBE_OK</li>
<li>Subscriber sends SUBSCRIBE for the repair track if FEC
protection is desired (Section 6.2)</li>
<li>Publisher sends source objects and repair objects</li>
<li>Subscriber configures its decoder from the catalog fields and the
Repair FEC Payload ID of each block (Section 4.2) and uses repair
symbols to recover any lost source symbols</li>
</ol>
<t>The catalog is the subscriber's authoritative FEC configuration; the
subscriber needs no other FEC signaling (Section 5.2).</t>
<t>When source objects are delivered as QUIC datagrams (unreliable), FEC
recovery is the primary loss mitigation mechanism.  When delivered as
QUIC stream objects (reliable), QUIC retransmission handles loss and
FEC is redundant -- receivers MAY skip FEC decoding in this case.</t>
</section>

<section anchor="fec-configuration"><name>FEC Configuration</name>
<t>This section defines the FEC algorithm identifiers and the decoder
parameters that constitute a track's FEC configuration, which is
signaled in the catalog (Section 5.2); for RaptorQ, the full RFC 6330
Object Transmission Information is
derived from the catalog fields (Section 4.2) rather than carried
on the wire.</t>

<section anchor="fec-algorithms"><name>FEC Algorithms</name>
<t>FEC algorithm values are registered in the &quot;MoQ FEC Algorithms&quot;
registry (Section 15.2); the catalog (Section 5.1) carries the
corresponding string identifiers.</t>
<t><strong>RaptorQ (0x01)</strong>: RaptorQ fountain code per <xref target="RFC6330"></xref>.  Can recover
from loss of any symbols as long as K symbols (source or repair) are
received.  It is the mandatory-to-implement scheme (Section 4.3).</t>
<t><strong>Reed-Solomon (0x02)</strong>: Reed-Solomon erasure code over GF(2^8) per
<xref target="RFC5510"></xref>; an extension point not specified by this document
(Section 4.3).</t>
</section>

<section anchor="raptorq-object-transmission-information"><name>RaptorQ Object Transmission Information</name>
<t>An RFC 6330 decoder is configured by the Object Transmission
Information (OTI): the 8-byte Common FEC OTI (Section 3.3.2 of
<xref target="RFC6330"></xref>) and the 4-byte Scheme-Specific FEC OTI (Section 3.3.3
of <xref target="RFC6330"></xref>), totaling 12 bytes:</t>

<artwork><![CDATA[RaptorQ OTI {
  Transfer Length (40),
  Reserved (8),
  Symbol Size (16),
  Number of Source Blocks (8),
  Number of Sub-Blocks (16),
  Symbol Alignment (8),
}
]]></artwork>
<t>This specification does not carry the OTI on the wire.  When a
track's catalog <tt>fec.algorithm</tt> is &quot;raptorq&quot;, receivers MUST
construct the OTI of each FEC block from the catalog fields
(Section 5.1) and the block's SSB_length, which every repair packet
of the block carries (Section 7.1), under the source symbol
construction of Section 7.3, as follows:</t>

<ul spacing="compact">
<li><strong>Transfer Length</strong>: F = SSB_length x T, where SSB_length is the
block's source symbol count (Section 7.1) and T is <tt>symbolSize</tt>, exact because every source symbol of the
construction of Section 7.3 is exactly T bytes.  It is never
computed from the cumulative size of source objects, which a
receiver that has lost objects could not know, and never from
<tt>sourceSymbols</tt>, which bounds SSB_length but is not the size of
any particular block (Section 7.4).  From this F an <xref target="RFC6330"></xref>
decoder derives that document's K as SSB_length, and from K its own
K' (<xref target="RFC6330"></xref> Section 5.3.1).</li>
<li><strong>Symbol Size</strong>: T = <tt>symbolSize</tt>.</li>
<li><strong>Number of Source Blocks</strong>: Z = 1.  Each FEC block of this
specification is decoded as an independent RFC 6330 object
containing a single source block.  Blocks are identified by the
SS_Start of the Repair FEC Payload ID of repair objects
(Section 7.1), and source symbols are placed in them by SS_ID
(Section 8.3) -- not by the RFC 6330 Z partitioning.</li>
<li><strong>Number of Sub-Blocks</strong>: N = 1.  Catalog-signaled sessions do
not use sub-blocking (Section 7.3).</li>
<li><strong>Symbol Alignment</strong>: Al = 8.  <tt>symbolSize</tt> MUST be a multiple
of 8.</li>
</ul>
<t>This derivation is normative and complete: a receiver that has a
track's catalog <tt>fec</tt> object requires no additional signaling to
configure its decoder (Section 5.2).  Its one per-block input, SSB_length, travels in the Repair FEC Payload ID of every repair packet of the
block, so a receiver holding any repair symbol of a block holds the block's SSB_length.</t>
</section>

<section anchor="other-fec-algorithms"><name>Other FEC Algorithms</name>
<t>RaptorQ is the mandatory-to-implement FEC scheme: an implementation
that performs FEC decoding under this specification MUST support
&quot;raptorq&quot;.  It is also the only algorithm this document fully
specifies.</t>
<t>The algorithm registry (Section 15.2) provides an extension point
for additional schemes.  In particular, &quot;reed-solomon&quot; (0x02) is
allocated for a Reed-Solomon erasure code over GF(2^8) <xref target="RFC5510"></xref>,
but its symbol construction, parameter derivation, and repair
object semantics are not specified by this document; a future
companion specification is required before it can be used
interoperably.</t>
<t>A receiver that does not implement a track's signaled
<tt>fec.algorithm</tt> simply forgoes FEC protection for that track: it
consumes the source track normally and does not subscribe to the
repair track.  Repair-track subscription is optional (Section 6.2),
so an unrecognized or unimplemented algorithm is not an error.</t>
</section>
</section>

<section anchor="catalog-fec-extension"><name>Catalog FEC Extension</name>

<section anchor="catalog-fields"><name>Catalog Fields</name>
<t>The catalog (Section 5.2) is an MSF catalog
<xref target="I-D.ietf-moq-msf"></xref>, extended by the documents of this suite as
described in <xref target="MOQ-MMT"></xref> Section 12, and is delivered on the track
named <tt>catalog</tt> (<xref target="I-D.ietf-moq-msf"></xref> Section 5).  This document
adds one track-level field -- the <tt>fec</tt> object defined below -- and
one packaging value (<tt>fec-repair</tt>, below).  The FEC configuration
is carried at the track level:</t>

<sourcecode type="json"><![CDATA[{
  "tracks": [
    {
      "name": "video",
      "packaging": "mmtp",
      "mmtpMode": "mfu",
      "timescale": 90000,
      "presentationAnchorTicks": 0,
      "groupDurationMs": 1000,
      "codec": "avc1.64001f",
      "width": 1920,
      "height": 1080,
      "framerate": 30,
      "fec": {
        "algorithm": "raptorq",
        "blockProfile": "iso-ssbg1-v1",
        "sourceSymbols": 625,
        "repairSymbols": 125,
        "symbolSize": 1000,
        "interleaveDepthMs": 1000,
        "reorderToleranceMs": 40,
        "repairTrack": "video/repair"
      }
    },
    {
      "name": "video/repair",
      "packaging": "fec-repair",
      "depends": ["video"],
      "repairSymbols": 125,
      "priority": 240
    }
  ]
}
]]></sourcecode>
<t>(Appendix B works this parameter set through in full.)</t>
<t>Field definitions:</t>
<t><strong>algorithm</strong> (string, REQUIRED if fec present): FEC scheme identifier.</t>

<ul spacing="compact">
<li>&quot;none&quot;: No FEC</li>
<li>&quot;raptorq&quot;: RaptorQ per RFC 6330 (mandatory to implement,
Section 4.3)</li>
<li>&quot;reed-solomon&quot;: Reserved extension point (Section 4.3); not
specified by this document</li>
</ul>
<t><strong>blockProfile</strong> (string, REQUIRED when <tt>algorithm</tt> is not &quot;none&quot;):
The block profile of the track's
FEC: the rules that fix how a source symbol is formed from a source
packet, how many source symbols a block holds, how a block and the
source symbols in it are identified, and how those identifiers wrap.
It applies to every FEC instance of the source track, its repair
layers (Section 6.3) and any keyframe overlay (Section 6.4) included,
and a repair track carries no <tt>blockProfile</tt> of its own
(Section 6.3.4, rule 8).  A publisher MUST NOT change a published
track's <tt>blockProfile</tt>; a different profile is a different rendition.
A <tt>fec</tt> object whose <tt>algorithm</tt> is &quot;none&quot; declares no FEC instance
and need not carry <tt>blockProfile</tt>.
This document defines exactly one value:</t>

<ul spacing="compact">
<li>&quot;iso-ssbg1-v1&quot;: the ISO/IEC 23008-1 Annex C profile of this
document, all of whose rules a receiver applies together.  A
source symbol is the ssbg_mode1 framing of one FEC source packet
(Section 7.3).  A block holds SSB_length source symbols, with
<tt>sourceSymbols</tt> as the upper bound on SSB_length (Section 7.4).  SS_IDs
advance by one per FEC source packet, blocks are consecutive, and
a source symbol is placed in its block by range membership
(Section 8.3).  SS_ID arithmetic is modulo 2^32, and a block's
repair objects are grouped under its 62-bit extended SS_Start
(Section 7.5).  An in-band AL-FEC message that describes such a
track carries the coding byte 0x14 (Section 7.3).</li>
</ul>
<t>A receiver MUST NOT apply FEC to a track whose <tt>blockProfile</tt> is
absent or names a profile the receiver does not implement.  It treats
FEC as unavailable for that track, as for an unimplemented
<tt>algorithm</tt> (Section 4.3): it consumes the source track without FEC
and does not subscribe to or join the track's repair tracks, and it
MUST NOT fail the session, or FEC for any other track, on that
account.  There is no default profile, and a receiver MUST NOT infer
one from the wire, whether from the fields of an in-band AL-FEC
message, from the length of the source packets it receives, or from
any other observation.</t>
<t><strong>sourceSymbols</strong> (integer, REQUIRED): K, the largest number of source
symbols an FEC block may hold.  MUST be &gt;= 1.  It is an upper bound,
not the size of each block: a block holds SSB_length source
symbols, 1 &lt;= SSB_length &lt;= K (Section 7.4).  It is the value an in-band
AL-FEC message carries as <tt>maximum_k_for_repair_flow</tt>
(<xref target="ISO.23008-1"></xref> Clause C.6.3), which is likewise a maximum.</t>
<t><strong>repairSymbols</strong> (integer, REQUIRED): P value - repair symbols per
FEC block.  MUST be &gt;= 1 when a repair track is published.</t>
<t><strong>symbolSize</strong> (integer, REQUIRED): T value - bytes per symbol.  All
symbols in a block have the same size; the byte layout of each source
symbol is fixed by the track's <tt>blockProfile</tt> -- for &quot;iso-ssbg1-v1&quot;,
the ssbg_mode1 construction of Section 7.3, under which a source
packet of up to T - 2 bytes is protected -- and is not otherwise
carried in the catalog.  For &quot;raptorq&quot;, T is a multiple of 8, the
fixed Symbol Alignment of the derived OTI (Section 4.2).</t>
<t><strong>interleaveDepthMs</strong> (integer, OPTIONAL): When present, its value MUST
be a non-negative integer.  A value greater than zero is the complete
FEC source/repair packet send span in milliseconds.  It is the catalog
form of <tt>protection_window_time</tt> in
<xref target="ISO.23008-1"></xref> Sections 11.2 and C.6.3: the actual elapsed time from
sending the first source or repair packet of a block to sending the
last source or repair packet of that block MUST NOT exceed this value.
For a positive value it is a duration, never a count of frames, groups,
samples, or symbols, and never a per-symbol interval.</t>
<t>This field does not select FEC block boundaries, the number of source
symbols in a block, the number of blocks in a MoQ Group, or the number
of groups a block spans.  Those are determined by the consecutive
source <tt>SS_ID</tt> values and the <tt>(SS_Start, SSB_length)</tt> carried by the
block's repair packets (Sections 7.4 and 8.3).  A block MAY contain
part of a Group, one Group, or several Groups, and a Group MAY contain
more than one block.</t>
<t>Thus <tt>interleaveDepthMs</tt> and <tt>groupDurationMs</tt> are not inputs to block
assignment; Section 8.3 specifies the source-symbol range and repair
packet fields that assign a source symbol to a block.</t>
<t>When present with a value greater than zero, a publisher chooses this
value to cover the actual source/repair send span of every block.  An
absent field supplies no catalog-signaled span.  A value of zero has
the ISO meaning of using <tt>protection_window_size</tt> instead of a time
window <xref target="ISO.23008-1"></xref> Clause C.6.3; this catalog profile carries no
packet-count window.  A catalog-only receiver therefore MUST NOT treat
zero as a zero-duration span or use it to derive a block count, and has
no elapsed-time FEC deadline from this field.  If an applicable ISO
packet-count window is accepted in-band, it governs separate
count-based processing; it does not supply a millisecond deadline, and
the receiver MUST NOT assume a media cadence to convert it.  Without an
elapsed-time deadline, open-block state is bounded only by the local
policy of Section 9, and on a multicast or AMT leg the receiver
performs no block classification or unicast repair (Section 11.4) and
keeps its repair-layer selection fixed (Section 6.3.6).</t>
<t>Note: the <tt>iso-ssbg1-v1</tt> token is unchanged from an earlier revision of
this document that derived the number D of Groups per block from this
field and read an absent or zero value as one group duration (D = 1),
so receivers implementing that derivation must change in lockstep with
producers.</t>
<t><strong>reorderToleranceMs</strong> (number, OPTIONAL): A receiver-local allowance
for packet reordering, network jitter, and local processing variance,
in milliseconds.  When present, the value MUST be finite and MUST be
greater than or equal to zero; fractional values are permitted.  An
explicit value of zero means that no additional allowance is required.
An omitted field means that the publisher did not signal an allowance;
receivers MUST preserve that distinction from an explicit zero.</t>
<t>For a receiver that uses a positive <tt>interleaveDepthMs</tt>, the FEC block
deadline is the receiver-local timestamp of the first accepted packet
plus the complete block span.  When <tt>reorderToleranceMs</tt> is present,
its catalog allowance is then added:</t>

<artwork><![CDATA[base_deadline = firstAcceptedAtMs + interleaveDepthMs
deadline = base_deadline + reorderToleranceMs  // when present
]]></artwork>
<t>The catalog allowance is added exactly once when present.  Its absence
is not equivalent to an explicitly signaled zero; a receiver that
applies an explicit local policy MUST keep that policy separate from
the catalog value.  When <tt>interleaveDepthMs</tt> is absent or zero, this
formula supplies no elapsed-time FEC deadline; an applicable ISO
packet-count window, if accepted in-band, remains separate count-based
processing and is not converted to milliseconds.  A receiver whose
FEC deadline API requires a signaled allowance MUST reject or disable
FEC for a track that omits <tt>reorderToleranceMs</tt>.</t>
<t><strong>repairTrack</strong> (string, REQUIRED): Track name for repair symbols,
following the convention in Section 6.1.</t>
<t>Repair tracks themselves are identified in the catalog by the
<tt>packaging</tt> value <tt>&quot;fec-repair&quot;</tt>: a track with
<tt>&quot;packaging&quot;: &quot;fec-repair&quot;</tt> carries repair objects (Section 7) for
the source track whose <tt>fec.repairTrack</tt> field names it, and
carries no directly renderable media.  The value extends the
allowed packaging values of <xref target="I-D.ietf-moq-msf"></xref> Section 5.2.4 in
the same manner as the <tt>cmaf</tt> value of <xref target="I-D.ietf-moq-cmsf"></xref>; see
Section 15.3.  Receivers that do not
implement this specification do not recognize the value and ignore
such tracks.</t>
<t><strong>enhancementRepair</strong>: Not defined.  Repair layers and keyframe
overlays are declared on their own repair-track entries
(Section 5.1.1), and a catalog carrying this member is rejected under
the exceptions there.</t>

<section anchor="repair-track-fields"><name>Repair Track Fields</name>
<t>A track with <tt>&quot;packaging&quot;: &quot;fec-repair&quot;</tt> describes its own role.  It
carries the flat MSF track fields plus the fields below.  Layer 0 is
identified by the source's <tt>fec.repairTrack</tt>; its entry MAY also carry
<tt>depends</tt>, <tt>&quot;repairLayer&quot;: 0</tt> and <tt>repairSymbols</tt>, which MUST agree
with the source's corresponding field when present (Section 6.3.4,
rules 2 and 11).</t>
<t><strong>depends</strong> (array of strings, REQUIRED except on layer 0): The name
of the source track this track repairs.  The
array MUST contain exactly one name, and that name MUST identify a
track in the same catalog whose <tt>packaging</tt> is <tt>mmtp</tt> and which
carries an <tt>fec</tt> object.</t>
<t><strong>repairLayer</strong> (integer, REQUIRED on enhancement layers, OPTIONAL on
layer 0, MUST NOT appear on an overlay): The layer index (Section 6.3).</t>
<t><strong>repairSymbols</strong> (integer, REQUIRED except on layer 0; MUST be</t>
<blockquote><t>= 1): The repair symbols per block that this track carries, P_i.
For layer 0 the source track's <tt>fec.repairSymbols</tt> is the
authoritative P_0 (Section 6.3.4, rule 11).</t>
</blockquote><t><strong>priority</strong> (integer, OPTIONAL): The MoQ Transport priority of this
track (Section 10), in the range 192 to 255.</t>
<t><strong>scope</strong> (string, OPTIONAL): When present, MUST be <tt>&quot;keyframe&quot;</tt>, and
declares this track to be the source track's keyframe overlay
(Section 6.4).  It is one of the unknown-key exceptions below.</t>
<t><strong>sourceSymbols</strong> (integer, REQUIRED on an overlay, MUST NOT appear
otherwise): The overlay instance's own K, the upper bound on the
SSB_length of its blocks (Section 7.4).</t>
<t>Track names carry no meaning in any of this.  A receiver MUST resolve
every relationship from <tt>fec.repairTrack</tt>, <tt>depends</tt>, <tt>repairLayer</tt>
and <tt>scope</tt>, and MUST NOT infer one by parsing a track name or a name
suffix.</t>
<t>A receiver MUST ignore a track-level or <tt>fec</tt> object key that it does
not recognize, and MUST NOT treat its presence as an error, so that
this suite can add fields without a flag day.  Exactly three keys
defined by this document are exceptions, because ignoring any of them
would change how the receiver must interpret the packets it receives:</t>

<ul spacing="compact">
<li><tt>fec.enhancementRepair</tt>: a receiver MUST reject a catalog carrying
it.</li>
<li><tt>scope</tt>: a receiver that does not implement overlays MUST fail
closed on a catalog carrying it (Section 6.4).</li>
<li><tt>fec.blockProfile</tt>: a receiver MUST NOT apply FEC to a track whose
<tt>blockProfile</tt> names a profile it does not implement (Section 5.1).</li>
</ul>
</section>

<section anchor="worked-catalog"><name>Worked Catalog</name>
<t>Three repair layers and one keyframe overlay on one source track:</t>

<sourcecode type="json"><![CDATA[{
  "tracks": [
    {
      "name": "video",
      "packaging": "mmtp",
      "mmtpMode": "mfu",
      "timescale": 90000,
      "presentationAnchorTicks": 0,
      "groupDurationMs": 1000,
      "codec": "avc1.64001f",
      "width": 1920,
      "height": 1080,
      "framerate": 30,
      "fec": {
        "algorithm": "raptorq",
        "blockProfile": "iso-ssbg1-v1",
        "sourceSymbols": 64,
        "repairSymbols": 8,
        "symbolSize": 1200,
        "interleaveDepthMs": 200,
        "repairTrack": "video/repair"
      }
    },
    {
      "name": "video/repair",
      "packaging": "fec-repair",
      "depends": ["video"],
      "repairLayer": 0,
      "repairSymbols": 8,
      "priority": 240
    },
    {
      "name": "video/repair/1",
      "packaging": "fec-repair",
      "depends": ["video"],
      "repairLayer": 1,
      "repairSymbols": 16,
      "priority": 244
    },
    {
      "name": "video/repair/2",
      "packaging": "fec-repair",
      "depends": ["video"],
      "repairLayer": 2,
      "repairSymbols": 32,
      "priority": 248
    },
    {
      "name": "video/repair/kf",
      "packaging": "fec-repair",
      "depends": ["video"],
      "scope": "keyframe",
      "sourceSymbols": 256,
      "repairSymbols": 32,
      "priority": 242
    }
  ]
}
]]></sourcecode>
<t>A receiver derives the following from that catalog, the ESI column
for a full block; none of it is carried on the wire:</t>
<table>
<thead>
<tr>
<th>Layer</th>
<th>P_i</th>
<th>O_i</th>
<th>RS_ID range</th>
<th>ESI range (full block, SSB_length = 64)</th>
</tr>
</thead>

<tbody>
<tr>
<td>0</td>
<td>8</td>
<td>0</td>
<td>0 to 7</td>
<td>64 to 71</td>
</tr>

<tr>
<td>1</td>
<td>16</td>
<td>8</td>
<td>8 to 23</td>
<td>72 to 87</td>
</tr>

<tr>
<td>2</td>
<td>32</td>
<td>24</td>
<td>24 to 55</td>
<td>88 to 119</td>
</tr>
</tbody>
</table><t>The RS_ID ranges are fixed by the catalog.  The ESI ranges are those
of a full block: a repair symbol's ESI is the block's SSB_length plus
its RS_ID (Section 7.2), so in a short block every ESI range
moves down by 64 - SSB_length while the RS_ID ranges do not move.</t>
<t>The total repair count is 8 + 16 + 32 = 56, so RSB_length is 56 on
every repair packet of layers 0, 1 and 2 (Section 7.1).  The overlay is
a separate FEC instance and is not in that table: its own K is 256, its
own P is 32, its RS_ID range is 0 to 31, its ESI range in a full
overlay block is 256 to 287, and its packets carry RSB_length 32.</t>
</section>
</section>

<section anchor="signaling-model"><name>Signaling Model</name>
<t>The catalog <tt>fec</tt> object (Section 5.1) is the authoritative FEC
signaling for MoQ receivers, that is for every receiver that obtains
the track's catalog entry.  Such a receiver has everything needed to
discover and subscribe to the repair track (Section 6) and to
configure its decoder via the derived OTI (Section 4.2); no
in-session signaling is required.</t>
<t>A packaging profile MAY also define in-band FEC signaling carried
with the media, which serves a receiver that consumes a flow without
the catalog.  For the mmtp packaging this is the AL-FEC message of
<xref target="ISO.23008-1"></xref> Clause C.6 (<xref target="MOQ-MMT"></xref> Sections 8 and 8.3).
In-band FEC signaling MUST NOT signal FEC parameters that contradict
the track's catalog <tt>fec</tt> object.  Where the two disagree the catalog
governs for a MoQ receiver, and a MoQ receiver MUST NOT require
in-band signaling in order to configure its decoder.</t>
<t>The catalog's authority holds uniformly across a MoQ receiver's
delivery paths, its multicast and AMT legs included.  MoQ control
messages cannot reach multicast or sessionless receivers at all
(Section 11), so no control-message mechanism could serve as the
common signaling path; the catalog can, because it is delivered as
track data or out of band.</t>
</section>

<section anchor="fec-source-info-object-property"><name>FEC Source Info Object Property</name>
<t>A publisher that carries FEC source symbols as MoQ objects MUST tag
each such object with a FEC Source Info Object Property, whose type
is the odd value 0x11 (Section 15.1).</t>
<t>0x11 is the value this document requests, and the registration policy
for the range it lies in is not reachable by an individual draft
(Section 15.1).  Until that request is resolved, 0x11 is to be read as
provisional.  If it is not obtainable, Section 15.1 names an odd value
in the range 0x80 to 0x37FF as the fallback; that value is a 2-byte
Delta Type, so adopting it changes the bytes on the wire and not only
the constant in this paragraph.</t>
<t><xref target="I-D.ietf-moq-transport"></xref> calls these Object Properties; drafts
before draft-17 called them object extension headers, and the two
terms name the same wire construct.  It encodes a Property as a
key-value pair whose type parity selects the value encoding: an even
type carries a single variable-length integer, an odd type carries a
length-prefixed sequence of bytes.  FEC Source Info is byte-valued,
so its type is odd, and a receiver or relay that knows nothing of
this document still steps over the Property correctly by its length
prefix.</t>
<t>Deployed implementations have used the even value 0x10 for this
purpose.  That value is not available: <xref target="I-D.ietf-moq-transport"></xref>
already lists 0x10 as the TIMESTAMP Object Property of
draft-ietf-moq-loc, in the same Property Type space and at the same
Object scope.  A 0x10-tagged FEC object is therefore not merely
unparseable under the parity rule; it is a semantic collision with an
unrelated Property.  A receiver that implements TIMESTAMP parses the
FEC Source Info value as a variable-length integer, yields a garbage
timestamp, and then reads the next Property type out of the middle of
the FEC Source Info bytes.  The key-value sequence is desynchronized
from that point on, so the exchange ends in a session closure rather
than in a quietly wrong value.  Which closure depends on where the
desynchronized parse lands: a Delta Type read out of the FEC Source
Info bytes that overflows 2^64-1, or a Length that exceeds 2^16-1,
is a <tt>PROTOCOL_VIOLATION</tt>; a type that is understood but whose value
does not match its serialization is a <tt>KEY_VALUE_FORMATTING_ERROR</tt>.
This is why implementations
that use 0x10 must special-case the type ahead of the parity rule to
interoperate at all.  An implementation of this document MUST NOT
send 0x10.  The defence is necessarily publisher-side: a receiver
cannot detect a 0x10-tagged FEC object as such, because by
construction it is indistinguishable from a well-formed TIMESTAMP
until the following Delta Type fails.  A receiver cannot reject a
0x10 Property and carry on,
because the sequence is already desynchronized by the time the value
has been mis-parsed; it MUST close the session as
<xref target="I-D.ietf-moq-transport"></xref> requires.</t>
<t>The Property value is:</t>

<artwork><![CDATA[FEC Source Info {
  SS_ID (32),
}
]]></artwork>
<t>SS_ID is an unsigned integer in network byte order.  It is the
sequence number of the source symbol the object carries (Section 2),
the same value and the same definition that the Source FEC Payload ID
trailer of a FEC source packet carries on the MMTP path
(Section 8.5).  This Property is that trailer's MoQ-layer carrier:
one identifier, one definition, whichever path the symbol travels.</t>
<t>Where the packaging also delivers the trailer, both carry the same
value and a publisher MUST make them identical.  On the mmtp
packaging of <xref target="MOQ-MMT"></xref> that is every source object, because the
object payload is the whole FEC source packet, trailer included.  The
Property is wanted there as well: it places the symbol at the MoQ
layer, reachable by a relay and by a receiver that does not parse
MMTP, whereas the trailer is the field the FEC encoder emitted and
the one Section 8.3 locates the symbol by.  Where the two disagree
the trailer prevails (Section 8.5).  A packet the decoder recovers
carries neither (Section 7.3): the Property is not recovered with the
object, and the trailer is appended after FEC encoding, so a receiver
that recovers a packet determines its SS_ID from the block coordinate
that recovered it, within that FEC instance's SS_ID space
(Section 6.4.1); an overlay coordinate does not yield a base SS_ID
(Section 7.3).</t>
<t>Where a keyframe overlay applies (Section 6.4), an object carrying a
Random Access Point fragment is a source symbol of two FEC instances,
whose SS_ID spaces are disjoint (Section 6.4.1), so &quot;the source
symbol the object carries&quot; names two SS_IDs rather than one.  This
Property carries the base instance's SS_ID -- the value the Source
FEC Payload ID trailer carries on the MMTP path (Section 8.5.1) --
and a publisher MUST NOT place an overlay SS_ID in it.  No second
Property conveys the overlay SS_ID: it travels in the 0x8B01 MMTP
header extension, which lies inside the MMTP packet header and is
therefore part of the protected packet of both instances
(Section 8.5.1), so it rides inside the object's payload on this path
as on any other.  A receiver takes an overlay SS_ID from that
extension and from nothing else, and in particular MUST NOT infer one
from this Property (Section 8.5.1).</t>
<t>A receiver places the symbol in a block by SS_ID (Section 8.3) and
learns the block's extent from the (SS_Start, SSB_length) of a repair
object (Section 7.1), exactly as on the MMTP path.  The Property
carries no block coordinate, and a receiver MUST NOT infer one from
it: the constraints of Section 7.4 on delimiting a block apply
unchanged to a MoQ receiver, so it MUST NOT infer a block boundary,
or SSB_length, from a gap in SS_IDs, from a group or MPU boundary --
which for a MoQ receiver includes a Group boundary -- from elapsed
time, or from <tt>sourceSymbols</tt>.  Until it has
accepted a repair object of the block it holds the symbol without
placing it, as Section 8.3 describes.</t>
<t>An object that carries a source symbol but no FEC Source Info
Property violates the publisher requirement that opens this section.  A receiver that does not
parse the FEC source packet has no SS_ID for it -- at the MoQ layer
the Property is the only carrier -- so it MUST NOT feed such an
object to the base decoder and MUST NOT count it in K or in any base
block, and MAY still deliver it as media.  Where the packaging
delivers the trailer, a receiver that parses the packet MAY take the
SS_ID from there instead (Section 8.3).  An overlay SS_ID is
unaffected either way: it travels in the 0x8B01 MMTP header
extension (Section 8.5.1), which this Property does not carry, and
Section 8.5.1 alone governs when the overlay decoder may be fed.</t>
<t>The value is exactly 4 bytes.  A value of any other length does not
match the serialization defined for this type, so a receiver that
implements this document MUST close the session with
<tt>KEY_VALUE_FORMATTING_ERROR</tt>, as <xref target="I-D.ietf-moq-transport"></xref> requires
of any Property whose type is understood and whose value does not
match.</t>
<t>SS_ID is a fixed 32-bit field rather than a variable-length integer
for two reasons.  First, <xref target="I-D.ietf-moq-transport"></xref> does not require
its variable-length integers to be encoded in the minimum number of
bytes, so one numeric value has several valid encodings that differ in
length; a varint field inside the Property value would therefore vary
the Property's own length without varying its meaning.  Second, the
encoding is a property of the session: <xref target="I-D.ietf-moq-transport"></xref>
replaced it at draft-17 (transport issue 1016) with a leading-1-bits scheme that is
not the QUIC variable-length integer encoding of earlier drafts and
does not decode the same bytes to the same values, so a varint field
following the session encoding would decode differently on two
drafts.  A fixed width removes both.  A publisher and a receiver that
negotiated different session versions, and a relay that re-encodes
between them, decode this field identically.</t>
<t>This Property carries no object length.  A receiver that recovers an
object by FEC decoding receives no Properties with it, so a length
carried here would be absent in exactly the case a recovered length is
wanted.  The recoverable length is the <tt>Length</tt> field inside the
source symbol itself (Section 7.3), which is recovered with the
symbol.  Under the source symbol
construction of Section 7.3 the padding that completes a symbol is
applied by the encoder and decoder and is not transmitted, so there is
no transmitted padding for a receiver to strip.</t>
</section>

<section anchor="relay-extensibility-requirements"><name>Relay Extensibility Requirements</name>
<t>Relays conforming to this specification are subject to the following
requirements:</t>

<ol>
<li><t>A relay MUST NOT terminate, reset, or otherwise fail a session
in response to a control message whose type it does not
recognize.  Such messages MUST be ignored.</t>
</li>
<li><t>A relay MUST NOT terminate, reset, or otherwise fail a session
in response to an Object Property whose type it does not
recognize.  Such Properties MUST be forwarded unmodified
to downstream subscribers; a relay MUST NOT strip them.</t>
</li>
</ol>
</section>
</section>

<section anchor="repair-track-convention"><name>Repair Track Convention</name>

<section anchor="track-naming"><name>Track Naming</name>
<t>For a source track with name components [namespace, track_name], the
corresponding repair track MUST be named:</t>

<artwork><![CDATA[[namespace, track_name, "repair"]
]]></artwork>
<t>Examples:</t>
<table>
<thead>
<tr>
<th>Source Track</th>
<th>Repair Track</th>
</tr>
</thead>

<tbody>
<tr>
<td>[&quot;live&quot;, &quot;video&quot;]</td>
<td>[&quot;live&quot;, &quot;video&quot;, &quot;repair&quot;]</td>
</tr>

<tr>
<td>[&quot;broadcast&quot;, &quot;video&quot;, &quot;1080p&quot;]</td>
<td>[&quot;broadcast&quot;, &quot;video&quot;, &quot;1080p&quot;, &quot;repair&quot;]</td>
</tr>

<tr>
<td>[&quot;stream&quot;, &quot;audio&quot;, &quot;en&quot;]</td>
<td>[&quot;stream&quot;, &quot;audio&quot;, &quot;en&quot;, &quot;repair&quot;]</td>
</tr>
</tbody>
</table><t>These name components are commonly rendered in slash-separated
form for URIs and logging (e.g., &quot;live/video&quot; and
&quot;live/video/repair&quot;); the normative form is the tuple.</t>
<t>The convention covers layer 0 only, and it is a convention rather than
a resolution mechanism.  Enhancement layers (Section 6.3) and a
keyframe overlay (Section 6.4) have no required name: they are
resolved from <tt>depends</tt>, <tt>repairLayer</tt> and <tt>scope</tt> on their own
catalog entries (Section 5.1.1).  A receiver MUST NOT infer that a
track is a repair track, which source it repairs, or which layer it
is, by parsing a track name or a name suffix, and a publisher MUST NOT
rely on a receiver doing so.  Names such as &quot;video/repair/1&quot; appear in
the examples of this document for readability only.</t>
</section>

<section anchor="subscription-model"><name>Subscription Model</name>
<t>Subscribers SHOULD subscribe to the source track first, then
subscribe to the repair track if:</t>

<ol spacing="compact">
<li>The track's catalog entry signals FEC (a <tt>fec</tt> object naming a
<tt>repairTrack</tt>, Section 5.1), AND</li>
<li>The subscriber desires FEC protection</li>
</ol>
<t>Repair-track subscription is selective and per-need: a subscriber
chooses whether to consume repair data based on its own path
conditions, and MAY start or stop its repair-track subscription at
any time during the session -- for example, subscribing only after
observing loss, or not subscribing at all on a reliable path.</t>
<t>Publishers and relays MUST NOT require subscription to repair
tracks and MUST NOT condition delivery of a source track on a
repair-track subscription.  Repair tracks are optional; subscribers
MAY choose to rely solely on QUIC retransmission or to accept
unrecovered loss.</t>
</section>

<section anchor="layered-repair-tracks"><name>Layered Repair Tracks</name>
<t>A source track MAY be protected by more than one repair track.  Each
such track is a repair layer: an independently subscribable set of
repair symbols for the same source blocks.  Layer 0 is the repair
track named by <tt>repairTrack</tt>, carrying the source's <tt>repairSymbols</tt>
symbols per block.  Layers 1..n are the tracks that name this source
in <tt>depends</tt> and carry a <tt>repairLayer</tt> (Section 5.1.1), one track per
layer index.</t>
<t>Layered repair is an extension of <xref target="ISO.23008-1"></xref> that an ISO AL-FEC
message cannot express: each FEC source flow has one FEC encoded flow,
whose one-stage coding structure carries a single <tt>repair_flow_id</tt>
(<xref target="ISO.23008-1"></xref> Clause C.6.3), so only layer 0 maps to an ISO repair
flow.  An in-band AL-FEC message names layer 0 and no other layer
(<xref target="MOQ-MMT"></xref> Section 8.3).  A repair layer is also unrelated to the
layers of ISO layer-aware FEC (LA-FEC, Clause C.2.3).</t>
<t>Layering separates the two costs of FEC: the repair count P buys
tolerance to random loss at a cost in bandwidth, and the interleave
window buys tolerance to burst loss at a cost in recovery latency
(Section 9).  Layers let a receiver on a lossier path add repair
without changing the source encoding.  A source track names only
layer 0; each further layer declares itself on its own <tt>tracks</tt>
entry, so the layer set is validated as a whole (Section 6.3.4) and
changed only as Section 6.3.9 allows.  A relay that forwards a subset
of a catalog MUST NOT forward a <tt>fec-repair</tt> track whose source track
it does not forward (Section 6.3.4, rule 9).</t>

<section anchor="shared-block-geometry"><name>Shared Block Geometry</name>
<t>All repair layers of a source track share its block geometry
(<tt>algorithm</tt>, <tt>blockProfile</tt>, <tt>sourceSymbols</tt>, <tt>symbolSize</tt>,
<tt>interleaveDepthMs</tt>, <tt>reorderToleranceMs</tt>) and differ only in
<tt>repairSymbols</tt>.  A repair
layer MUST NOT carry a geometry field; rule 8 of Section 6.3.4 lists
them, and a receiver rejects a catalog that violates it.  Because each
source packet carries one base Source FEC Payload ID (Section 8.5), a
different K or interleave window needs a separate rendition; the
keyframe overlay (Section 6.4) is a separate FEC instance, not a
layer.</t>
</section>

<section anchor="repair-symbol-identity-across-layers"><name>Repair Symbol Identity Across Layers</name>
<t>Let P_i be the <tt>repairSymbols</tt> of layer i and O_i its RS_ID offset,
defined below (O_0 = 0).  P_0 is the source track's
<tt>fec.repairSymbols</tt> (Section 6.3.4, rule 11), and P_i for i &gt;= 1 the
layer track's own <tt>repairSymbols</tt>.  Layer i carries, for every source
block, the repair symbols with RS_ID in [O_i, O_i + P_i).  The
Encoding Symbol ID follows the single-layer rule of Section 7.2:</t>

<artwork><![CDATA[O_i   = sum(P_j for j < i)
RS_ID = O_i + j, for the j-th symbol of layer i
ESI   = SSB_length + RS_ID
]]></artwork>
<t>where SSB_length is the block's source symbol count (Section 7.1).</t>
<t>The total repair count of the block is the sum of P_i over all
published layers.  RSB_length on every repair packet of every layer
carries this total (Section 7.1), not the layer's own P_i.  That is
what makes the RS_ID to ESI mapping independent of which layers a
given receiver joined: a receiver holding a non-prefix subset computes
the same coordinate for a symbol as a receiver holding everything, and
the <tt>RS_ID &lt; RSB_length</tt> bound holds for a symbol from any layer.</t>
<t>Because RaptorQ repair symbols are identified by ESI alone and any set
of distinct encoding symbols of a block decodes together
(<xref target="RFC6330"></xref>), symbols received from any subset of layers, over any
mix of paths, combine in one decode.  Subsets need not be prefixes: in
the worked catalog of Section 5.1.2 a receiver holding layers 0 and 2
holds, for a full block, ESIs 64 to 71 and 88 to 119, which are
distinct encoding symbols of one code, and it decodes as soon as it
holds enough distinct symbols in total.</t>
<t>A receiver that has subscribed a set of layers recovers a block
whenever the number of lost symbols, source and repair together, does
not exceed C - e, where C is the total P over the layers it holds and
e is the RaptorQ decoding overhead (roughly 1e-2, 1e-4, and 1e-6
residual failure at 0, 1, and 2 symbols of overhead per <xref target="RFC6330"></xref>).
This loss tolerance is derived from K and the layer counts; it MUST
NOT be signaled as a separate catalog field.</t>
<t>Receivers MUST take layer membership and per-layer counts from the
catalog.  RSB_length carries the total and says nothing about which
layers a receiver holds.</t>
<t>On layer i, the block's repair objects form the MoQ group whose Group
ID is the block's extended SS_Start (Section 7.5), and that group
carries P_i objects (Section 7); object j of that group carries the
repair symbol with RS_ID = O_i + j.</t>
</section>

<section anchor="why-raptorq-only"><name>Why RaptorQ Only</name>
<t>Repair layers and the overlay are defined only for <tt>raptorq</tt>: a
publisher MUST NOT signal either under any other algorithm, and a
receiver rejects such a catalog (Section 6.3.4, rule 7).  Layering
relies on RaptorQ's open Encoding Symbol ID space, in which repair
symbols from disjoint ESI ranges on separate tracks remain symbols of
one code; a block code such as Reed-Solomon fixes n = K + P at
encoding time, so its symbols for one P are not valid for another.</t>
</section>

<section anchor="catalog-rules-and-fail-closed-validation"><name>Catalog Rules and Fail-Closed Validation</name>
<t>A receiver MUST validate all of the following for a source track
before starting FEC for it.  On any violation the receiver MUST fail
closed: it MUST report the offending catalog path and MUST NOT start
FEC for that source track.  A receiver MUST NOT repair the catalog by
ignoring the offending track, because every rule below distinguishes a
layer set that decodes from one that silently mis-maps symbols.</t>

<ol spacing="compact">
<li><tt>depends</tt> names exactly one track in the same catalog, whose
<tt>packaging</tt> is <tt>mmtp</tt> and which carries an <tt>fec</tt> object.</li>
<li>The <tt>repairLayer</tt> values for one source track are contiguous from 1
to n, with no gaps and no duplicates.  Layer 0 is the track named
by the source's <tt>fec.repairTrack</tt>.</li>
<li><tt>priority</tt>, where declared, is in the range 192 to 255 inclusive,
and is monotonic non-decreasing with layer index.  Layer 0's
priority MAY be declared on its own track; when absent it is 240.</li>
<li>For each FEC instance, the total of <tt>repairSymbols</tt> across all its
layers is at most 2^24 - 1, the range of RSB_length.</li>
<li>For each FEC instance, K + totalP - 1 is at most 2^24 - 1, which
bounds the largest ESI the instance can produce.</li>
<li>For each FEC instance, K is at most 56403.  <xref target="RFC6330"></xref> extends
a source block of K source symbols to K' symbols, the smallest
value at least K in its Table 2 (<xref target="RFC6330"></xref> Section 5.3.1), and
56403 is the largest such value, K'_max (<xref target="RFC6330"></xref>
Section 5.1.2), so a RaptorQ source block holds at most 56403
source symbols.</li>
<li>Repair layers and any overlay appear only when <tt>fec.algorithm</tt> is
<tt>raptorq</tt> (Section 6.3.3 above).</li>
<li>A track whose <tt>packaging</tt> is <tt>fec-repair</tt> carries no geometry
field, whether as a flat field or inside an <tt>fec</tt> object of its
own: <tt>algorithm</tt>, <tt>blockProfile</tt>, <tt>mmtpMode</tt>, <tt>timescale</tt>, any
<tt>groupDuration</tt> field, <tt>symbolSize</tt>, <tt>interleaveDepthMs</tt>,
<tt>reorderToleranceMs</tt>, and <tt>sourceSymbols</tt> except on an overlay
(Section 6.4).</li>
<li>No orphan repair track: every track whose <tt>packaging</tt> is
<tt>fec-repair</tt> is reachable from a source track, either by being
named in that source's <tt>fec.repairTrack</tt> or by naming that source
in <tt>depends</tt>.  This rule binds once the catalog declares any FEC
source, that is any track whose <tt>fec.algorithm</tt> is not <tt>none</tt>; a
catalog that declares no FEC source at all MAY carry an
unreferenced <tt>fec-repair</tt> track that nothing joins.  This rule is
the one exception to the per-source remedy of the preamble above:
an orphan track is by definition associated with no source track,
so there is no source track to stop.  The receiver MUST refuse to
join the orphan track and MUST report its catalog path, and MUST
NOT stop FEC for any source track on account of it.</li>
<li>A source track has at most one track with <tt>&quot;scope&quot;: &quot;keyframe&quot;</tt>
(Section 6.4), and such a track carries no <tt>repairLayer</tt>.</li>
<li>The layer-0 repair track's <tt>repairSymbols</tt>, where declared, equals
the source track's <tt>fec.repairSymbols</tt>.  The source field is the
single authoritative value of P_0; the layer-0 track MAY restate
it and MUST restate it identically.  A receiver MUST reject a
catalog declaring both with different values, and MUST NOT resolve
the conflict by preferring either field, because the two readings
disagree about O_1, about the block total, and therefore about the
RSB_length that every layer's packets carry (Section 6.3.2).  This
rule is why rules 4 and 5 have a single well defined totalP to
bound.</li>
</ol>
<t>Section 6.3.9 adds one check that can only be made on received repair
packets.</t>
<t>The following are the fail-closed cases this section introduces,
written against the worked catalog of Section 5.1.2 (K = 64, P_0 = 8,
P_1 = 16, P_2 = 32) so that each defect is one edit away from a valid
catalog.  Each row violates the rule shown, and none of them is
detectable from the wire.</t>
<table>
<thead>
<tr>
<th>Catalog defect</th>
<th>Rule</th>
<th>Why the wire cannot catch it</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>video/repair</tt> declares <tt>repairSymbols</tt> 16 while the source declares <tt>fec.repairSymbols</tt> 8</td>
<td>11</td>
<td>Both readings are self-consistent: one derives O_1 = 8 and total 56, the other O_1 = 16 and total 64.  A repair symbol is identified by ESI alone, so a receiver that resolved P_0 the other way decodes with a shifted mapping and reports a corrupt block, not a catalog error.</td>
</tr>

<tr>
<td>Two tracks declare <tt>&quot;repairLayer&quot;: 1</tt> for <tt>video</tt></td>
<td>2</td>
<td>Both claim RS_ID 8 to 23.  Symbols from the two tracks are distinct on the wire but collide in ESI, so a decode fed from both sees duplicate encoding symbols and stalls short of K.</td>
</tr>

<tr>
<td><tt>video/repair/2</tt> is present but no track declares layer 1</td>
<td>2</td>
<td>O_2 is a function of P_1, which is absent, so the receiver has no offset for layer 2 at all.</td>
</tr>

<tr>
<td><tt>video/repair/kf</tt> carries <tt>&quot;repairLayer&quot;: 3</tt> alongside <tt>&quot;scope&quot;: &quot;keyframe&quot;</tt></td>
<td>10</td>
<td>The overlay is a second FEC instance over its own K (Section 6.4).  Admitting it as a layer would fold its RS_ID space into O_i and place its symbols in the base instance's ESI range.</td>
</tr>

<tr>
<td>A second track for <tt>video</tt> declares <tt>&quot;scope&quot;: &quot;keyframe&quot;</tt></td>
<td>10</td>
<td>A RAP packet carries one overlay SS_ID, in its one header extension (Section 8.5.1), so a second overlay has no SS_ID on the wire.</td>
</tr>

<tr>
<td><tt>video/repair/1</tt> carries <tt>symbolSize</tt> or its own <tt>fec</tt> object</td>
<td>8</td>
<td>A repair track carrying its own geometry would name itself as layer 0 and bypass rule 9's reachability check.</td>
</tr>
</tbody>
</table><t>A receiver MAY report several violations at once.</t>
</section>

<section anchor="receiver-selection"><name>Receiver Selection</name>
<t>The per-need model of Section 6.2 applies to each layer
independently.  On a lossy path a receiver SHOULD subscribe layer 0
first.  When a block fails recovery with the receiver's current layer
set and a higher layer exists, the receiver SHOULD subscribe the next
layer; it MAY instead request only the failed block's repair objects
from that layer, a request bounded to the block's repair group
(Section 7.5), when the block is still inside its recovery budget
(Section 9).   On a multicast or AMT leg, Section 11.4 governs such
per-block requests: which blocks get one, when, with what budget and
priority, and what happens when one fails.  A receiver MAY
unsubscribe a layer after a receiver-chosen number of consecutive
blocks whose loss stayed within the tolerance of the remaining layers.
Hysteresis is counted in blocks, the protocol's unit, not by a fixed
timer (Section 6.3.6).</t>
</section>

<section anchor="repair-only-multicast-endpoints"><name>Repair-Only Multicast Endpoints</name>
<t>On a multicast endpoint the receiver cannot choose tracks; the
operator of the endpoint chooses which tracks that path carries.  Each
repair layer carried on an endpoint is listed with its own <tt>packetId</tt>
(<xref target="MOQ-MULTICAST"></xref> Section 4.1), exactly as a source track is, and a
receiver MUST route every such <tt>packetId</tt> to the decoder of the source
track that layer depends on.  Because every endpoint carries the same
source packets under the same block partition (Section 6.3.1), a
receiver that moves between endpoints, or that is side-fed over MoQ
unicast, mixes symbols from all of them in one decode.  Layers not
carried on any endpoint the receiver holds remain reachable over MoQ
unicast (Section 6.2) for receivers that have a return path.</t>
<t>An operator MAY carry the source track and its layers together on one
endpoint, or MAY place layers on endpoints of their own.  An endpoint
whose track list contains only <tt>fec-repair</tt> tracks is a repair-only
endpoint:</t>

<sourcecode type="json"><![CDATA[{
  "multicast": {
    "endpoints": [
      {
        "sourceAddress": "198.51.100.100",
        "groupAddress": "232.1.1.50",
        "port": 5000,
        "tracks": [
          { "name": "video",          "packetId": 1 },
          { "name": "video/repair",   "packetId": 2 }
        ]
      },
      {
        "sourceAddress": "198.51.100.100",
        "groupAddress": "232.1.1.51",
        "port": 5000,
        "tracks": [
          { "name": "video/repair/1", "packetId": 3 },
          { "name": "video/repair/2", "packetId": 4 }
        ]
      }
    ]
  }
}
]]></sourcecode>
<t>The first endpoint suits a regional path with low random loss.  The
second is repair-only: a receiver on a lossy path holds both, and
receives source packets once while adding layers 1 and 2 to the same
decode.</t>
<t>A repair-only endpoint is never a media tier.  A receiver MUST NOT
treat one as a rendition or quality choice, and endpoint or ladder
selection MUST exclude it on every path by which a receiver picks
what to render.  A repair-only endpoint's <tt>bandwidth</tt>
(<xref target="MOQ-MULTICAST"></xref> Section 4.1) is the cost of adding repair to a
stream the receiver has already selected, not the cost of an
alternative rendition, and MUST NOT be compared against a media
endpoint's <tt>bandwidth</tt> when choosing one.</t>
<t>A receiver joins a repair-only endpoint on measured loss: the rate at
which its FEC blocks fail to recover, and the margin by which
recovering blocks consume the repair symbols available to it.  A
receiver MUST NOT use goodput, throughput, or estimated available
bandwidth to decide whether to add or drop a repair layer.</t>
<t>Layer changes are make-before-break.  A receiver MUST join the
additional layer's endpoint and begin receiving from it before
leaving any endpoint it currently holds, so that no source block is
left with less coverage than the receiver already had.</t>
<t>Hysteresis MUST derive from the FEC block span, that is from
<tt>interleaveDepthMs</tt> together with <tt>reorderToleranceMs</tt>, and MUST NOT
come from a fixed timer or a fixed symbol count.  A receiver MUST
observe at least one full block span at the new layer set before
making a further layer change.</t>
<t>That loss measure and this hysteresis both need a block deadline,
which exists only for a positive <tt>interleaveDepthMs</tt> (Section 9).  On a
multicast or AMT leg, a receiver of a track whose catalog omits that
field or sets it to zero MUST NOT add or drop a repair layer of the
track on block-recovery evidence, and keeps its repair-layer selection
for the track fixed.</t>
</section>

<section anchor="interaction-with-the-interleave-window"><name>Interaction with the Interleave Window</name>
<t>Layers never change <tt>interleaveDepthMs</tt>, the stream's single
recovery-latency lever (Section 9).  A shallow window recovers bursts
only by per-block unicast repair (Sections 6.3.5 and 11.4.2), at about
one round trip; a deep window recovers them in band at that window's
latency.  Serving both requires two renditions (Section 6.3.1).</t>
</section>

<section anchor="compatibility"><name>Compatibility</name>
<t>A source track with a single repair track is the one-layer case
(O_0 = 0, RSB_length = <tt>repairSymbols</tt>).  A receiver that subscribes
only layer 0 decodes correctly whatever other layers exist: layer 0
alone is a valid layer set, and it uses RSB_length only as the
<tt>RS_ID &lt; RSB_length</tt> bound.  The keyframe overlay is the exception: a
receiver has to recognize its declaration, because its repair packets
belong to another FEC instance (Section 6.4.3).</t>
</section>

<section anchor="changing-the-layer-set-within-a-session"><name>Changing the Layer Set Within a Session</name>
<t>Publishing a layer is adding one <tt>tracks</tt> entry and withdrawing it is
removing one, but the two directions are not symmetric, because O_i is
a function of every lower layer's P (Section 6.3.2).  A change to the
set can therefore move the coordinates of a layer a receiver has
already joined.  This subsection states which changes are defined.</t>
<t>Layer sets are append-only.  A publisher MAY append a layer at the
next index above the highest published one.  It MUST NOT withdraw a
published layer, at any index, for the lifetime of the source
encoding.  An append changes O_i for no layer already published,
because no published layer's set of lower layers changes.  It does
raise the total, so RSB_length on the wire rises, which is benign for
the reason Section 6.3.8 gives: a receiver uses the total only as the
<tt>RS_ID &lt; RSB_length</tt> bound, so a receiver holding a catalog from
before an append reads a smaller bound that excludes only symbols of
layers it has not joined.</t>
<t>A publisher MUST NOT renumber the <tt>repairLayer</tt> of a published layer,
and MUST NOT change the <tt>repairSymbols</tt> of a published layer, while
any receiver may still be consuming the source track.  Rule 2 of
Section 6.3.4 requires <tt>repairLayer</tt> to be contiguous from 1 to n, so
withdrawing a layer that is not the highest would force exactly such a
renumbering.  A publisher that must retire any layer, including the
highest, retires the source encoding and publishes a separate
rendition.  Supporting withdrawal directly would require a catalog
generation identifier carried on the wire, that is in-session
signaling, which Section 5.2 does not define.</t>
<t>The prohibition is not editorial, and the worked catalog of
Section 5.1.2 shows why.  A receiver holding layers 0 and 2 holds,
for a full block, ESIs 64 to 71 and 88 to 119.  Renumber layer 2 to
layer 1 and the same track's offset becomes O = 8, so the publisher
now labels those symbols ESI 72 to 103 while the receiver still maps
them to 88 to 119.
The receiver feeds correctly received symbols into the decoder under
wrong coordinates.  RaptorQ does not detect this, because a repair
symbol is identified by its ESI alone: the result is not a reported
error but a decode that fails, or that resolves against coordinates
the symbols do not belong to.  Changing a published <tt>repairSymbols</tt>
does the same to every layer above the one changed.</t>
<t>Withdrawing the highest layer forces no renumbering, but it is barred
for a different reason: it is indistinguishable on the wire from the
renumbering above.  For the highest layer n, O_n + P_n is the total
identically, so withdrawing it drops the wire RSB_length strictly
below the bound derived by every receiver that had joined it, and the
check below cannot tell that case from a genuine coordinate
disagreement.  Both present as nothing but a smaller total.  The
receivers holding the highest layer are also the lossiest ones, and
they cannot recover by observation: absence of symbols is precisely
the loss condition the layer was joined to repair, so they learn of
the withdrawal only at the next catalog refresh, which this document
does not bound.</t>
<t>Append-only is what makes the check below sound.  RSB_length is
monotonically non-decreasing over the lifetime of a source encoding,
so a wire RSB_length below a held layer's O_i + P_i is always a
genuine violation: no operation this document defines produces one.</t>
<t>A receiver MUST fail closed when, for any layer i it holds, the
RSB_length carried on any repair packet of the same FEC instance is
less than O_i + P_i derived from its own catalog: its own layer's
RS_ID range does not fit under the bound the publisher is advertising,
so the two disagree about coordinates the receiver is actively using.
It MUST NOT treat such a packet as a symbol to discard.  In the
renumbering example above the total falls from 56 to 40 while the
receiver's O_2 + P_2 is 56, so the check catches it.</t>
<t>That check is a backstop and not a substitute for the publisher
requirement.  It does not catch a change that leaves the total at or
above the receiver's derived bound, for example an increase to a lower
layer's <tt>repairSymbols</tt>, which shifts every higher offset while
raising the total.  That case is silent on the wire, which is why the
protection is the prohibition on the publisher rather than validation
at the receiver.  A wire RSB_length larger than the receiver's derived
total is not an error in itself: that is the append case above.</t>
</section>
</section>

<section anchor="keyframe-overlay"><name>Keyframe Overlay</name>
<t>A source track MAY additionally be protected by a keyframe overlay: a
second, independent FEC instance whose source symbols are only the
fragments of Random Access Points of that source track.</t>
<t>Losing part of a Random Access Point makes every dependent frame
undecodable until the next one; the overlay protects RAP fragments
across a block of its own, which can be wider than the base window,
without changing the base instance's latency.</t>

<section anchor="overlay-instance"><name>Overlay Instance</name>
<t>An overlay is a separate FEC instance over the same source track.  It
has its own <tt>sourceSymbols</tt> (K_overlay) and its own <tt>repairSymbols</tt>,
declared on its own repair track, and it shares the source track's
<tt>algorithm</tt>, <tt>blockProfile</tt> and <tt>symbolSize</tt>.  It does not share the
base instance's K, its block partition, its SS_ID space, or its RS_ID
space.</t>
<t>Every per-block quantity of this document -- K, the total repair count
P, SS_ID, ESI, RS_ID, SS_Start, RSB_length, SSB_length, the
short-block rules of Section 7.4, the wrap epoch and repair group IDs
of Section 7.5, and the bounds of Section 6.3.4 -- is defined within
one FEC instance.  For the base instance, K is the
source track's <tt>fec.sourceSymbols</tt> and P is the sum of
<tt>repairSymbols</tt> over its published layers (Section 6.3.2); for an
overlay, K and P are the <tt>sourceSymbols</tt> and <tt>repairSymbols</tt> of its
own track.  A repair packet belongs to the instance of the track it
arrived on (Section 6.4.2).</t>
<t>An overlay is not a repair layer.  It carries no <tt>repairLayer</tt>, it is
not a member of the layer index chain, and it is excluded from the
contiguity and priority monotonicity rules of Section 6.3.4, which
order the base layer chain only.  Its <tt>priority</tt> is independent within
192 to 255, and MAY be numerically lower than a base enhancement
layer's so that a keyframe repair symbol is delivered before an
ordinary one.</t>
<t>Overlay ESIs never collide
with base ESIs because the two are different instances decoded by
different decoders; a receiver MUST NOT feed a repair symbol of one
instance to the decoder of the other, and MUST NOT reuse a source
symbol's coordinate in one instance as its coordinate in the other.
A RAP source packet is a source symbol of both instances, at an
unrelated coordinate in each (Section 6.4.2).</t>
<t>A source track has at most one overlay (Section 6.3.4, rule 10), a
wire constraint explained in Section 8.5.1.  An overlay is declared
only by the catalog, never in an in-band AL-FEC message, and only
where no FEC source or repair packet carries FFSRP_TS
(Section 8.5.1).</t>
</section>

<section anchor="overlay-membership"><name>Overlay Membership</name>
<t>The overlay's source symbols are the fragments of the source track
that belong to a Random Access Point, in transmission order.  A
publisher that declares an overlay MUST set <tt>RAP_flag</tt> on a source
packet of the track, MUST include the packet in the overlay instance,
and MUST carry the packet's overlay SS_ID in its 0x8B01 header
extension (Section 8.5.1), if and only if that packet's payload
belongs to a keyframe MFU covered by the overlay.</t>
<t>Overlay source symbols are numbered consecutively within the overlay
instance, in the order the publisher emits them: the overlay SS_ID is
0 at the first overlay source symbol of the stream and advances by one
per overlay source symbol, modulo 2^32 (Section 7.5).  It is the value
the RAP source packet carries in its 0x8B01 header extension
(Section 8.5.1).  It lives in the overlay instance's own SS_ID space,
independent of the base instance's, and the two IDs on one packet are
unrelated numbers.  An overlay source block holds at most K_overlay
overlay source symbols, and overlay blocks, including short ones, are
formed, located and wrapped exactly as base blocks are (Sections 7.4,
7.5 and 8.3), with K_overlay as the upper bound on their SSB_length.
Because a RAP is a small fraction of the media, an overlay block spans
many base blocks; the overlay's recovery latency is therefore its own
block span and is unrelated to <tt>interleaveDepthMs</tt>.</t>
<t>A receiver knows that a source packet is an overlay source symbol
because the packet carries the 0x8B01 header extension
(Section 8.5.1).  It knows that a repair packet belongs to the overlay
because it arrives on the repair track that the catalog declares with
<tt>&quot;scope&quot;: &quot;keyframe&quot;</tt> for this source track, and that track has its
own <tt>packet_id</tt>.  The instance is therefore fixed by the track the
packet arrived on; no field of the repair packet distinguishes the
two, and a receiver MUST NOT attempt to infer the instance from
SS_Start, RSB_length, or SSB_length, whose values are only
interpretable once the instance is known.</t>
</section>

<section anchor="receiver-behavior"><name>Receiver Behavior</name>
<t>A receiver that implements overlays and has joined the overlay repair
track decodes the two instances independently and MAY use the
recovered RAP fragments even when the base instance failed to recover
the block that carried them.</t>
<t>The overlay is the publisher-side half of keyframe protection.  The
receiver-side half is the repair policy of Section 11.4, under which a
receiver gives a keyframe-bearing base block that in-band decoding
leaves unrecovered priority unicast repair; Section 11.4.6 states how
the two combine.</t>
<t>A receiver that does not implement overlays MUST fail closed on a
catalog that declares one for a track it intends to consume, that is
on a <tt>fec-repair</tt> track carrying the unknown <tt>scope</tt> key, and MUST
NOT ignore the key and consume the source track anyway.  This is one
of the unknown-key exceptions of Section 5.1.1: a receiver that
ignored the key could not tell the overlay's repair track from a
repair layer of the base instance, and would feed the base decoder
repair symbols of another FEC instance (Section 6.4.2).</t>
<t>This mechanism is not backward compatible with receivers that predate
it, for the same reason.  A publisher that must serve such receivers
publishes the overlay on a separate source track, or does not publish
it.</t>
</section>
</section>
</section>

<section anchor="repair-object-format"><name>Repair Object Format</name>

<section anchor="repair-object-header"><name>Repair Object Header</name>
<t>Each object on a repair track is one complete MMTP repair packet
(packet type 0x03, FEC Type 2) carrying exactly one repair symbol.
Its layout is the ISO 23008-1 AL-FEC repair packet form --
the MMTP packet header followed by the 13-byte Repair FEC Payload
ID and the repair symbol data (<xref target="ISO.23008-1"></xref> Sections C.4.3 and
C.5.3; ssbg_mode1, one-stage FEC with N = 1, and ffsrpts_flag = 0, so
no FFSRP_TS, Section C.5.1) -- so the same repair packet is
valid on MoQ, multicast UDP, and native broadcast paths without
translation, and matches the repair-object depiction of
<xref target="MOQ-MMT"></xref> Section 7.  The layout below reproduces <xref target="ISO.23008-1"></xref>
Section C.5.3 for convenience:</t>

<artwork><![CDATA[Repair Object {
  MMTP Packet Header (96),      # packet type 0x03, FEC Type 2
  Repair FEC Payload ID {
    SS_Start (32),
    RSB_length (24),
    RS_ID (24),
    SSB_length (24),
  },
  Repair Symbol Data (..),      # exactly one symbol, T bytes
}
]]></artwork>
<t><strong>MMTP Packet Header</strong>: The standard 12-byte MMTP packet header
(<xref target="MOQ-MMT"></xref> Section 3.1) with packet type 0x03 (repair) and
FEC Type 2; its <tt>packet_id</tt> routes the repair flow.  Like every
packet of its MMTP packet flow, source and signaling packets
included, a repair packet has the packet counter flag C = 0
(<xref target="MOQ-MMT"></xref> Section 3.1; <xref target="ISO.23008-1"></xref> Clause 9.2.3).  A repair
packet MUST NOT carry a header extension (X = 0).  Because C = 0 and
X = 0, the Repair FEC Payload ID always begins at byte offset 12.</t>
<t><strong>SS_Start (32 bits)</strong>: The SS_ID of the first source symbol of the
protected source block (<xref target="ISO.23008-1"></xref> Section C.5.3).  The blocks of
an FEC instance are consecutive: the block after this one starts at
SS_Start + SSB_length, modulo 2^32 (Section 7.4), so this block is the
SS_ID range [SS_Start, SS_Start + SSB_length) and is identified by its
SS_Start.  Extended to 62 bits, SS_Start is also the MoQ Group ID of
the block's repair objects (Section 7.5).  Every field below is that
of the packet's FEC instance (Section 6.4.1).</t>
<t><strong>RSB_length (24 bits)</strong>: The number of repair symbols generated
for the block: the instance's total repair count P, identical on every
repair packet of the instance; a layer does not carry its own P_i.</t>
<t><strong>RS_ID (24 bits)</strong>: The zero-based index of this repair symbol
among the block's P repair symbols.  The RFC 6330 Encoding Symbol ID
is derived as ESI = SSB_length + RS_ID (Section 7.2).  Layer i of the
base instance carries RS_ID in [O_i, O_i + P_i) (Section 6.3.2).</t>
<t>The encoder performs one RaptorQ encoding pass per source block of
each instance, producing the total repair count, and then assigns the
disjoint RS_ID
ranges to the layer tracks according to O_i.  It MUST NOT run a
separate encoding per layer: separate encodings of the same block are
not symbols of a single code, so they could not be combined by a
receiver holding more than one layer, which is the property
Section 6.3.2 depends on.</t>
<t><strong>SSB_length (24 bits)</strong>: The number of source symbols in the
protected source block (<xref target="ISO.23008-1"></xref> Section C.5.3), from 1 to K,
where K is the instance's <tt>sourceSymbols</tt> (Section 5.1); it is K for
a full block.  It is authoritative for the block: the block is a
RaptorQ source block of SSB_length source symbols, its repair ESIs
start at SSB_length (Section 7.2), and its decoder is configured with
F = SSB_length x T (Section 4.2).  A value below K marks a short
source block, to which this document's framing adds no padding
symbols (Section 7.4).  A publisher MUST NOT send 0
or a value above K; a receiver discards a repair packet carrying
either (Section 7.4).</t>
<t><strong>Repair Symbol Data</strong>: Exactly one repair symbol of Symbol Size
(T) bytes, generated per Section 7.2.  Carrying one symbol per
object aligns the loss unit with the FEC symbol (Section 11.3) and
requires no symbol-count field.</t>
</section>

<section anchor="repair-symbols"><name>Repair Symbols</name>
<t>For RaptorQ, repair symbols are generated per <xref target="RFC6330"></xref> Section 5.3.
The source symbols of a block occupy ESIs 0 to SSB_length - 1 in
SS_ID order, and the Encoding Symbol ID (ESI) of a repair symbol
starts at SSB_length, the block's K in the notation of <xref target="RFC6330"></xref>
(<xref target="RFC6330"></xref> Section 5.3.1): ESI = SSB_length + RS_ID, both fields
taken from the Repair FEC Payload ID (Section 7.1).  The Internal
Symbol IDs of <xref target="RFC6330"></xref>, which start the repair symbols at that
document's K', are internal to its encoder and decoder and never
appear on the wire.</t>
<t>Repair symbol generation for extension algorithms (Section 4.3) is
not specified by this document.</t>
</section>

<section anchor="sub-blocks-and-ssbg-mode"><name>Sub-Blocks and ssbg_mode</name>
<t>Per ISO 23008-1 <xref target="ISO.23008-1"></xref> Section C.3.3 (signalled per C.6.3,
Table C.5), the FEC block structure is described by the source symbol
block generation (SSBG) mode (ssbg_mode).  The <tt>iso-ssbg1-v1</tt> block
profile (Section 5.1) uses ssbg_mode1, with the one-stage FEC coding
structure and FEC payload ID mode 0 (<xref target="ISO.23008-1"></xref> Clause C.1).</t>
<t><strong>ssbg_mode1</strong>: One MMTP source packet = one source symbol, which
records the packet's length.  Each MoQ object or multicast UDP
datagram carries exactly one FEC symbol.  Repair symbols are exactly
T bytes on the wire; a SOURCE packet MAY be shorter than T on the
wire -- the length field and the zero padding that complete its
T-byte source symbol are applied by the encoder and decoder as part of
the source symbol construction below and are NOT transmitted.  This
is the natural model for MMTP because packets are sized to fit in UDP
datagrams and no fragmentation or reassembly is needed at the FEC
layer.  Every source symbol is exactly T bytes, so a block of
SSB_length source symbols is exactly SSB_length x T bytes -- the property the derived
Transfer Length of Section 4.2 relies on.  This is ssbg_mode1 of
<xref target="ISO.23008-1"></xref>, not ssbg_mode0, which carries no length and requires
every packet of the flow to be exactly one symbol long.</t>
<t><strong>Source symbol construction</strong>: The protected packet of an FEC source
packet is the complete MMTP packet -- the MMTP packet header,
including any header extension, followed by the MMTP payload -- before
its 4-byte Source FEC Payload ID is appended (<xref target="ISO.23008-1"></xref>
Section C.4.2; Section 8.5).  Its T-byte source symbol is
(<xref target="ISO.23008-1"></xref> Section C.3.3):</t>

<artwork><![CDATA[Source Symbol {
  Length (16),                  # protected packet length, octets
  Protected Packet (..),        # Length octets
  Padding (..),                 # zero octets, up to T in total
}
]]></artwork>
<t>The Length field is in network byte order and every Padding octet is
zero, so the largest protected packet a symbol can carry is T - 2
octets.  A publisher MUST size every FEC source packet so that its
protected packet does not exceed T - 2 octets.  A receiver that
observes a source packet whose protected packet exceeds T - 2 octets
MUST NOT feed it to the decoder -- a truncated symbol would corrupt
recovery for the entire block -- but MAY still deliver the packet as
media.  On a RAP packet under a keyframe overlay (Section 6.4), the
base and the overlay instance form the symbol from the same protected
packet, so the two protect one identical T-byte symbol.</t>
<t>Recovery yields the block's SSB_length source symbols.  From each, the
receiver takes the Length octets that follow the Length field as the
recovered protected packet, and delivers that packet to the MMTP
parser.  A receiver MUST NOT deliver a recovered symbol whose Length
is less than 12, the size in bytes of the MMTP packet header
(<xref target="MOQ-MMT"></xref> Section 3.1), or points past the end of the symbol, or
whose Padding octets are not all zero: each means that the symbol is
not the one the publisher encoded.</t>
<t>A recovered packet carries no Source FEC Payload ID, of either
instance: the trailer is appended after FEC encoding and is not part
of the protected packet.  A receiver MUST NOT re-append a trailer
before delivering the recovered packet to the MMTP parser, and MUST
NOT expect the recovered bytes to end in a block coordinate.  This
holds identically for a symbol recovered by a keyframe overlay, which
the receiver delivers as media on the strength of the overlay
recovery alone.  The 0x8B01 header extension of a RAP packet under an
overlay (Section 8.5.1) is part of the protected packet, by contrast,
and is recovered with it.</t>
<t>The packet's base SS_ID was in the trailer, and this document defines
no mapping from an overlay coordinate to a base one: a receiver MUST
NOT place an overlay-recovered symbol into a base source block unless
it has determined that packet's base SS_ID independently.  Absent
that, an overlay recovery is usable as media but MUST NOT be counted
toward base block recovery, and in particular MUST NOT be treated as
reducing the number of erasures the base decoder still has to solve.
The other direction needs no such determination, because a RAP packet
recovered by the base instance still carries its overlay SS_ID
(Section 8.5.1).</t>
<t><strong>In-band signaling</strong>: An AL-FEC message (<xref target="MOQ-MMT"></xref> Section 8.3)
that describes a track under <tt>iso-ssbg1-v1</tt> carries the coding byte
0x14: <tt>fec_coding_structure</tt> 0001 (one-stage), <tt>ssbg_mode</tt> 01,
<tt>ffsrpts_flag</tt> 0 (no FFSRP_TS) and <tt>fec_payload_id_mode</tt> 0 (a Source
FEC Payload ID is appended to every FEC source packet), in that bit
order, per Table C.3 of <xref target="ISO.23008-1"></xref> as replaced by
<xref target="ISO.23008-1.AMD1"></xref>.  A message carrying any other value for such a
track contradicts the catalog (Section 5.2).</t>
<t><strong>Sub-blocks</strong>: When a single source block produces a large number
of source symbols, RFC 6330 permits dividing each block into N
sub-blocks (the Number of Sub-Blocks field of the OTI).  The derived
OTI of Section 4.2 fixes N = 1, so catalog-signaled sessions do not
use sub-blocks; sub-block operation by broadcast systems that carry
an explicit OTI is described informatively in Section 12.2.
A publisher using MMTP packaging under <tt>iso-ssbg1-v1</tt> therefore uses
ssbg_mode1 without sub-blocks, and never ssbg_mode2.</t>
</section>

<section anchor="short-source-blocks"><name>Short Source Blocks</name>
<t>A publisher MUST close a source block when it has assigned K source
symbols to it.  It MAY close a source block earlier, for example at an
access-unit, media-unit, or MoQ Group boundary, or to keep the actual
source/repair send span within a positive <tt>interleaveDepthMs</tt> when that
field is present (Section 5.1).  Such a block is a short source block, and it
is a block with a smaller source symbol count: every block holds
SSB_length source symbols,
1 &lt;= SSB_length &lt;= K (<xref target="ISO.23008-1"></xref> Section C.5.3), and K -- the catalog
<tt>sourceSymbols</tt>, carried in band as <tt>maximum_k_for_repair_flow</tt> -- is an upper bound on SSB_length, not the size of any particular
block.  A short block differs from a full one only in SSB_length:</t>

<ol>
<li><t>The publisher encodes the block as a RaptorQ source block of its
SSB_length source symbols (F = SSB_length x T, Section 4.2), at
ESIs 0 to SSB_length - 1 in SS_ID order, and MUST carry that count
in the SSB_length field of every repair packet of the block, on
every repair track of the instance.  This document's framing adds
no padding symbols to the block: none is transmitted, and none is
counted in SSB_length or F.  The padding of the block to K'
symbols in the notation of <xref target="RFC6330"></xref> (<xref target="RFC6330"></xref>
Section 5.3.1) is part of RaptorQ encoding and decoding, performed
inside the encoder and the decoder.</t>
</li>
<li><t>The next block starts at the SS_ID that follows the block's last
source symbol: its SS_Start is SS_Start + SSB_length, modulo 2^32.  No
SS_ID is skipped, so every SS_ID belongs to exactly one block.</t>
</li>
<li><t>The block's repair ESIs start at SSB_length: ESI = SSB_length + RS_ID
(Section 7.2).</t>
</li>
<li><t>The block is complete, and needs no repair, once the receiver
holds all SSB_length of its source symbols.  It is recoverable once the
source and repair symbols the receiver holds together number at
least SSB_length, plus the decoding overhead of Section 6.3.2.</t>
</li>
<li><t>Recovery yields the SSB_length source symbols, SSB_length x T bytes, each consumed
per the source symbol construction of Section 7.3.</t>
</li>
</ol>
<t>Source packets carry only SS_ID, so the (SS_Start, SSB_length) of a
repair packet is the only wire signal of a block's extent.  Until a
receiver has accepted a repair packet of a block it knows neither: it
holds the source packets of that block without placing them in any
block (Section 8.3), and a run of SS_IDs that it does not hold is a
run of lost source packets of one or more blocks it cannot yet
delimit.  It MUST NOT infer a block boundary, or SSB_length, from a gap in
SS_IDs, from a group or MPU boundary, from elapsed time, or from
<tt>sourceSymbols</tt>.  A block all of whose repair packets are lost
therefore remains undelimited until a repair packet of the block
arrives, including one obtained by unicast repair (Section 11.4),
which conveys (SS_Start, SSB_length) in the same way.  When the
receiver accepts a repair packet of a block that starts after the end
of the blocks it has delimited, the SS_IDs between the two belong to
one or more blocks of which it holds no repair packet.</t>
<t>A receiver MUST fail closed on inconsistent block signaling.  It
MUST discard a repair packet whose SSB_length is 0 or exceeds K.  It
MUST discard a repair packet whose SSB_length differs from the value
it has already accepted for the block with the same SS_Start, and one
whose range [SS_Start, SS_Start + SSB_length) overlaps a different
block that it has already accepted, in each case leaving the state of
every block unchanged.</t>
</section>

<section anchor="ss-id-wrap-and-repair-group-ids"><name>SS_ID Wrap and Repair Group IDs</name>
<t>SS_ID and SS_Start are 32-bit values that start from an arbitrary
value and wrap to 0 after their maximum (<xref target="ISO.23008-1"></xref>
Section C.5.2).  Every comparison, distance and range test on them in
this document, block membership (Section 8.3) included, uses serial
number arithmetic <xref target="RFC1982"></xref> with SERIAL_BITS = 32.  A block can span
the wrap: a block with SS_Start 2^32 - 3 and SSB_length 4 holds the
SS_IDs 2^32 - 3, 2^32 - 2, 2^32 - 1 and 0, and the next block starts
at SS_ID 1.</t>
<t>A MoQ Group ID is a 62-bit integer, and the groups of a track are
ordered by it <xref target="I-D.ietf-moq-transport"></xref>, so the repair objects of a
block are grouped not under its 32-bit SS_Start, which wraps, but
under its extended SS_Start:</t>

<artwork><![CDATA[ext(SS_Start) = (wrap_epoch << 32) | SS_Start
]]></artwork>
<t><tt>wrap_epoch</tt>, from 0 to 2^30 - 1, counts the times that SS_Start has
wrapped in the FEC instance before this block: it is 0 for the first
block of the FEC instance's source encoding, and increases by one at each block
whose SS_Start is numerically below its predecessor's.  Equivalently,
the ext(SS_Start) of a block is that of its predecessor plus the
predecessor's SSB_length.  On every repair track of the instance, the
repair objects of a block form the MoQ Group whose Group ID is the
block's ext(SS_Start) (Section 6.3.2).  Repair Group IDs are
therefore sparse, one per block at the block's first SS_ID, and
strictly increasing.</t>
<t>A repair object received over MoQ thus carries its block's start
twice: in the SS_Start of its Repair FEC Payload ID and in its Group
ID.  The SS_Start is authoritative.  A receiver MUST discard a repair
object whose Group ID modulo 2^32 differs from its SS_Start and, once
it has established the wrap epoch, one whose Group ID differs from
ext(SS_Start) or whose SS_Start it cannot extend (below), in each
case leaving the state of every block unchanged.  The Group ID of a
discarded repair object is not a reference value r.</t>
<t>A receiver establishes the wrap epoch of an FEC instance in one of
the following ways, and MUST NOT assume a wrap epoch that it has not
established in one of them:</t>

<ol>
<li><t>From the Group ID of a repair object of the instance that it has
received over MoQ and not discarded (above).  That Group ID is the
reference value r.  The publisher assigns it and MoQ delivers it
unaltered, so it stands on the same footing as the Largest
Location of way 2: the modulo 2^32 test above screens out an
object to discard, and does not verify the epoch.</t>
</li>
<li><t>From the Largest Location that a TRACK_STATUS request for a repair
track of the instance reports (<xref target="I-D.ietf-moq-transport"></xref>
Section 9.13).  The publisher answers TRACK_STATUS with a
REQUEST_OK, which that document calls TRACK_STATUS_OK, carrying
the parameters that it would set in a SUBSCRIBE_OK, among them the
LARGEST_OBJECT parameter (<xref target="I-D.ietf-moq-transport"></xref>
Section 9.20.18).  The receiver reads the Group of the Location
that LARGEST_OBJECT carries, whichever name the reply bears, and
that Group is the reference value r.  A reply without
LARGEST_OBJECT reports a repair track on which no object has been
published, and establishes no epoch.</t>
</li>
<li><t>As epoch 0, when the receiver has observed the instance from its
first block, whose <tt>wrap_epoch</tt> is 0 (above).  The reference value
r is then that block's SS_Start.</t>
</li>
</ol>
<t>A reference value r is an extended SS_Start, and the epoch is r
shifted right by 32 bits.  The receiver relates its own SS_IDs to it
with serial arithmetic: it extends a later 32-bit SS_Start or SS_ID x
relative to an extended value r that it already holds -- its
reference value, or a value it extended before -- to the 62-bit value
congruent to x modulo 2^32 that is nearest r in serial order: r
advanced by the serial distance from the low 32 bits of r to x when x
follows them, r moved back by the serial distance from x to them when
x precedes them, and r itself when the two are equal.  A receiver
MUST NOT extend an x that lies exactly 2^31 from the low 32 bits of
r, a pair that <xref target="RFC1982"></xref> leaves unordered, or one whose extension
falls outside [0, 2<sup>62).</sup></t>
<t>Serial arithmetic cannot detect an x that lies more than 2^31 SS_IDs
from r: it extends such an x into the wrong epoch without error.  A
receiver therefore extends values relative to an r only while it can
bound the number of SS_IDs between them below 2^31, and MUST
re-establish the wrap epoch, in one of the ways above, after any gap
that it cannot so bound, such as one that spans a rejoin of a
multicast group or a reconnection of its MoQ session.</t>
<t>A receiver that has lost the source packet with SS_ID x, and holds no
repair packet of the block that contains x, requests that block's
repair by a FETCH <xref target="I-D.ietf-moq-transport"></xref> of the absolute,
inclusive Group range</t>

<artwork><![CDATA[[ max(ext(S_prev) + 1, ext(x) - (K - 1)), ext(x) ]
]]></artwork>
<t>on each repair track it requests from, where:</t>

<ul spacing="compact">
<li>K is the instance's <tt>sourceSymbols</tt> (Section 5.1), the largest
SSB_length that a block can have (Section 7.4), so the block that
contains x starts at most K - 1 SS_IDs before x;</li>
<li>S_prev is the SS_Start of the last block that the receiver has
delimited that ends before x.  When the receiver has delimited no
such block, the first term is absent and the range is
[ max(ext(x) - (K - 1), 0), ext(x) ];</li>
<li>ext(x) is x extended relative to ext(S_prev) when S_prev exists,
and otherwise relative to the reference value r of the receiver's
wrap epoch.</li>
</ul>
<t>Repair Group IDs sit at block starts, so the range returns the repair
of every block that starts within it, up to and including the block
that contains x, and the last Group it returns is that block.  The
range is never empty: it always contains ext(x).  A receiver that has
not established the wrap epoch, or that may not extend x, has no
range to request until it establishes one.  A receiver that holds a
repair packet of the block requests the one Group ext(SS_Start)
instead.</t>
<t>The 32-bit wrap of SS_ID and SS_Start is that of <xref target="ISO.23008-1"></xref>.  The
extended SS_Start, and its use as a MoQ Group ID, are defined by this
document, outside <xref target="ISO.23008-1"></xref>.</t>
</section>
</section>

<section anchor="block-and-group-alignment"><name>Block and Group Alignment</name>
<t>FEC blocks are partitions of the source-packet sequence, independent
of MoQ Group boundaries.  The publisher assigns consecutive <tt>SS_ID</tt>
values to source packets and chooses each block's <tt>SSB_length</tt> subject
to <tt>1 &lt;= SSB_length &lt;= K</tt> (Section 7.4).  It signals the chosen
partition in the <tt>(SS_Start, SSB_length)</tt> fields of the block's repair
packets.  A block MAY end at an access-unit, media-unit, or Group
boundary, MAY span Groups, and MAY end because it reaches K.  K
exhaustion closes a block.  A Group MAY contain more than one block.
A positive <tt>interleaveDepthMs</tt> limits the elapsed source/repair send
span; it does not change this partitioning rule.</t>

<section anchor="blocks-within-a-group"><name>Blocks Within a Group</name>
<t>For example, a source Group can contain two consecutive blocks:</t>

<artwork><![CDATA[Group G:    SS_ID s   .. s+a-1      -> block A, SS_Start = s
            SS_ID s+a .. s+a+b-1    -> block B, SS_Start = s+a
Group G+1:  SS_ID s+a+b ..          -> next block or continuation
...
]]></artwork>
</section>

<section anchor="blocks-across-groups"><name>Blocks Across Groups</name>
<t>A block can also span a Group boundary:</t>

<artwork><![CDATA[Group G:    SS_ID s   .. s+a-1      -> block A, still open
Group G+1:  SS_ID s+a .. s+L-1     -> block A completes
            SS_ID s+L ..            -> next block
...
]]></artwork>
<t>A block's repair objects form the repair-track Group whose Group ID is
the block's extended SS_Start (Section 7.5), a number space unrelated
to the source track's Group IDs.  No fixed number of MoQ Groups is
required for a block, and no Group boundary can be used to infer
<tt>SSB_length</tt>.</t>
</section>

<section anchor="source-symbol-location"><name>Source Symbol Location</name>
<t>Under <tt>iso-ssbg1-v1</tt>, every FEC source packet carries a Source FEC
Payload ID (Section 8.5), and a receiver that parses the packet takes
each source symbol's SS_ID from that field on every path that
delivers the packet with its trailer.  The SS_ID is also carried
alongside the packet where the packaging says so: on the MoQ path
every object carrying a source symbol carries it in the FEC Source
Info Object Property (Section 5.3), under the same value and the same
definition, whether or not that object also delivers the trailer.  A
receiver that does not parse the FEC source packet -- a relay, or a
MoQ receiver with no MMTP parser -- takes the SS_ID from there.  The
SS_ID advances by one per
FEC source packet, modulo 2^32, in the order the publisher emits the
packets (<xref target="ISO.23008-1"></xref> Section C.5.2), and the blocks of an FEC
instance are consecutive: each starts at the SS_ID that follows the
last source symbol of its predecessor (Section 7.4).</t>
<t>A source symbol is located by range membership.  It belongs to the
block whose Repair FEC Payload ID (Section 7.1) carries an (SS_Start,
SSB_length) such that the symbol's SS_ID lies in [SS_Start,
SS_Start + SSB_length) under the serial arithmetic of Section 7.5,
and its ESI is its serial distance from SS_Start:</t>

<artwork><![CDATA[ESI = (SS_ID - SS_Start) mod 2^32,   0 <= ESI < SSB_length
]]></artwork>
<t>No source symbol's block can be computed from its SS_ID alone,
because blocks differ in length (Section 7.4), and this document
defines no block number.  A receiver holds a source symbol whose
block it has not yet delimited, and places it when it accepts a
repair packet of that block.  Because consecutive FEC source packets
carry consecutive SS_IDs, a lost source packet is visible as a
missing SS_ID even before its block is delimited, and a run of SS_IDs
that a receiver holds in full needs no repair, whatever its block
boundaries.</t>
<t>An object that a packaging profile defines as carrying no source
symbol -- for example, the in-band AL-FEC signaling object of
<xref target="MOQ-MMT"></xref> Section 8 -- carries no SS_ID, has no ESI, and is not
counted in K or in any block.  This document defines no derivation
of a source symbol's position from MoQ Group or Object IDs: on the
mmtp packaging of <xref target="MOQ-MMT"></xref>, Object IDs are not positions in the FEC
block, and a packaging profile that defines source objects carrying neither a
Source FEC Payload ID nor a FEC Source Info Object Property
(Section 5.3) needs a block profile of its own (Section 5.1).</t>
<t>Every transport path yields the same SS_ID for the same packet,
because each path carries the same MMTP packet, so receivers MAY
combine symbols from any transport path toward the same FEC block
recovery.  Within one FEC instance (Section 6.4.1), a receiver
deduplicates source symbols by SS_ID and repair symbols by
(SS_Start, RS_ID).</t>
</section>

<section anchor="encoder-constraints"><name>Encoder Constraints</name>
<t>For FEC block alignment and timing to be deterministic, encoders MUST:</t>

<ol>
<li><t>Assign consecutive <tt>SS_ID</tt> values in source-packet emission order,
close a block at K source symbols or earlier as permitted by
Section 7.4, and publish the resulting <tt>(SS_Start, SSB_length)</tt> in
every repair packet for that block.  A publisher MAY close at an
access-unit, media-unit, or Group boundary, but MUST NOT use any
boundary or elapsed-time observation as a substitute for that
wire signaling.</t>
</li>
<li><t>Signal the catalog-authored group duration and frame rate in the MoQ
catalog: for mmtp-packaged tracks, publish a positive duration as
<tt>groupDurationMs</tt> when its integer-millisecond form is exact, or as
the exact positive <tt>groupDurationTicks</tt>; when both are present,
<tt>groupDurationTicks</tt> wins and <tt>groupDurationMs</tt> is informational.
Signal the keyframe cadence in <tt>keyframeIntervalMs</tt> (or
<tt>keyframeIntervalTicks</tt>), and the frame rate in the <tt>framerate</tt> field
(<xref target="MOQ-MMT"></xref> Sections 4.4.2, 4.4.3 and 12.1).  The ISO 23008-1
AL-FEC message has no field for either value (<xref target="ISO.23008-1"></xref>
Table C.3), so an encoder signals neither there, and a receiver
takes neither from it.</t>
</li>
<li><t>If frame rate or GOP size changes mid-session, update the MoQ
catalog and signal a manifest discontinuity for DASH/HLS.</t>
</li>
<li><t>When <tt>interleaveDepthMs</tt> is positive, choose it so that the actual
elapsed send span from the first source or repair packet of every
block to its last does not exceed the signaled value.  A zero value
is usable only with the ISO <tt>protection_window_size</tt> alternative
described in Section 5.1.  The value is not derived from a group
count, frame count, or per-symbol interval.</t>
</li>
</ol>
</section>

<section anchor="source-fec-payload-id-and-atsc-3-0-signed-region"><name>Source FEC Payload ID and ATSC 3.0 Signed Region</name>
<t>Exactly one 4-byte Source FEC Payload ID (SS_ID; ffsrpts_flag = 0, so
no FFSRP_TS, <xref target="ISO.23008-1"></xref> Section C.5.1) is appended at the END of
each MMTP FEC source packet -- following the MMTP payload, outside
the MMTP packet header -- with or without a keyframe overlay
(Section 8.5.1).  Per
ATSC A/360 Section 5.2.2.5, the ATSC 3.0 Signed Application (A3SA)
signing mechanism covers signaling messages and MA3 messages
(packet type 0x2) but excludes asset packets (type 0x00 MPU and
type 0x03 repair).</t>
<t>Neither <xref target="ISO.23008-1"></xref> nor <xref target="ATSC-A331"></xref> carries the SS_ID inside
the A3SA signed region.  In particular the MMT hint sample does not:
neither its ISO syntax (<xref target="ISO.23008-1"></xref> Clause 8.3.2) nor the ATSC
<tt>MMTHSampleATSC3</tt> syntax (<xref target="ATSC-A331"></xref> Section 7.2.4.2.2.3) has a
Source FEC Payload ID field, and hint samples travel as MPU-mode data
units on the Asset's own packet_id (<xref target="ATSC-A331"></xref> Section 7.2.4.2.3),
that is in asset packets, which A3SA does not sign.  This document
therefore defines no A3SA-authenticated FEC block assignment: block
assignment taken from the trailing Source FEC Payload ID of an A3SA
verified packet is unauthenticated.  A receiver that requires
authenticated FEC block assignment MUST obtain it from an integrity
mechanism, other than A3SA signing, whose coverage includes the
complete MMTP packet, the trailer included.  The bc-provenance profile
is not such a mechanism: its authenticated bytes exclude the Source
FEC Payload ID (<xref target="MOQ-MULTICAST"></xref> Section 7.2.4).</t>
<t>For MoQ-only receivers (no A3SA verification), the trailing 4-byte
Source FEC Payload ID remains the canonical identifier by which a
source packet is placed in its block (Section 8.3).  QUIC transport
encryption provides equivalent integrity protection.</t>
<t>Whatever the receiver's verification posture, the FEC Source Info
Object Property of Section 5.3 carries the same value for a receiver
that does not parse the packet; where an object delivers both and
they disagree, the trailer is the one that is canonical, because it
is the field the FEC encoder emitted and the one Section 8.3 locates
the symbol by.  The Property restates it at the MoQ layer.</t>

<section anchor="overlay-ss-id-header-extension"><name>Overlay SS_ID Header Extension</name>
<t>When the catalog declares a keyframe overlay for a source track
(Section 6.4), a source packet of that track carrying a Random Access
Point fragment is a source symbol of two FEC instances.  It carries
its base SS_ID in the one Source FEC Payload ID trailer that every FEC
source packet carries (Section 8.5), and its overlay SS_ID
(Section 6.4.2) in an MMTP header extension (<xref target="ISO.23008-1"></xref>
Clause 9.2.3) of type 0x8B01:</t>

<artwork><![CDATA[Source Packet with Overlay {
  MMTP Packet Header {
    ...,                          # X = 1, RAP_flag = 1
    Header Extension {
      Type (16) = 0x8B01,
      Length (16) = 4,
      Overlay SS_ID (32),
    },
  },
  MMTP Payload (..),
  Source FEC Payload ID (32),     # base instance SS_ID
}
]]></artwork>
<t>A publisher that declares an overlay MUST carry this extension as the
header extension, with X = 1, of exactly the source packets that it
includes in the overlay instance, that is the packets on which it
sets <tt>RAP_flag</tt> (Section 6.4.2), and of no other packet of the track.
An MMTP packet carries at most one header extension (<xref target="ISO.23008-1"></xref>
Clause 9.2.3), so the RAP packets of a track under an overlay carry no
other MMTP header extension, and a publisher that needs another
header extension on those packets cannot use the overlay for that
track.
<xref target="ISO.23008-1"></xref> specifies no particular header extension and no
registry of header extension types; this document uses the type
0x8B01 for the overlay SS_ID (Section 15.1).</t>
<t>The trailer is never more than one Source FEC Payload ID.  On a packet
with or without the extension, the last four bytes are the base
SS_ID, as <xref target="ISO.23008-1"></xref> Section C.4.2 places it, so a receiver that
does not implement overlays locates the trailer and the payload as on
any other packet, stepping over the extension by its Length field.
The extension lies inside the MMTP packet header, so it is part of
the protected packet of both instances (Section 7.3), which protect
one identical source symbol.  The permission of <xref target="ISO.23008-1"></xref>
Clause 9.2.3 to discard a header extension therefore extends only to
a receiver's own processing: a node that forwards the packet MUST NOT
remove or alter the extension.  A RAP packet recovered by either
instance carries its overlay SS_ID, so a receiver MAY place a RAP
packet that the base instance recovered into the overlay block that
the extension locates; Section 7.3 states why the converse requires
the packet's base SS_ID.</t>
<t>A receiver that implements overlays takes a packet's overlay SS_ID
from this extension and from nothing else.  It MUST NOT feed the
overlay decoder a source packet that lacks the extension, whatever its
<tt>RAP_flag</tt>, or one whose extension has a Length other than 4, and MUST
NOT infer an overlay SS_ID from <tt>RAP_flag</tt>, from the packet's
position, or from its base SS_ID.</t>
<t>A source track has at most one overlay (Section 6.3.4, rule 10)
because a source packet has one header extension, and so carries one
overlay SS_ID; relaxing that bound would be a revision of this
document and a change to the source packet layout, not a catalog-only
change.</t>
<t>The overlay is declared only by the catalog.  A publisher MUST NOT
describe the overlay's repair flow in an AL-FEC message (<xref target="MOQ-MMT"></xref>
Section 8.3): the message identifies an FEC source flow by packet_id
(<xref target="ISO.23008-1"></xref> Clause C.6.3) and cannot describe the RAP subset
that the overlay protects, so a receiver that consumes the flow
without the catalog uses the base instance alone.  An overlay is
defined only without FFSRP_TS: a publisher MUST NOT declare an
overlay for a source track whose FEC source or repair packets carry
FFSRP_TS (ffsrpts_flag = 1, <xref target="ISO.23008-1"></xref> Section C.5.1), and the
extension carries an SS_ID alone.</t>
<t>Section 8.5 applies to the overlay SS_ID as to the base one: A3SA
signing authenticates neither, and a receiver that requires
authenticated block assignment treats each as Section 8.5 requires.</t>
</section>
</section>
</section>

<section anchor="interleaving"><name>Interleaving</name>
<t>Interleaving spreads source symbols across time to protect against
burst loss.  The interleave window (Interleave Depth, in
milliseconds) bounds the elapsed send span of a source block when the
field is positive.  It does not define the block's membership or imply
a number of Groups.  Block membership is the consecutive <tt>SS_ID</tt> range
identified by <tt>(SS_Start, SSB_length)</tt> (Sections 7.4 and 8.3).</t>

<artwork><![CDATA[Groups:         M0             M1             M2
                 |              |              |
Blocks:       [Block 0] [Block 1] [Block 2] [Block 3]
SS_ID:           S0  S1  S2  S3  S4  S5  S6  S7  ...
                 |       |       |       |
Repair Groups:  ext(S0) ext(S2) ext(S4) ext(S6)
]]></artwork>
<t>A burst loss can therefore erase symbols from several adjacent blocks;
each block is recovered with the repair symbols identified by its own
<tt>SS_Start</tt> and <tt>SSB_length</tt>.  With P repair symbols for a block, the
usual RaptorQ recovery condition applies independently to that block.</t>
<t>Publishers SHOULD choose the interleave window based on:</t>

<ul spacing="compact">
<li>Expected burst loss duration</li>
<li>Acceptable recovery latency</li>
<li>Available bandwidth for repair overhead</li>
</ul>
<t>The receiver's block-abandonment timeout -- how long it waits for a
block's source and repair symbols before declaring the block
unrecoverable -- follows the ISO receiver-buffer model <xref target="ISO.23008-1"></xref>
Section 11.2.  The timer is anchored at the timestamp <tt>ts</tt> of the
first source or repair packet of the block when the receiver received
that packet, not at block creation or the first repair receipt.  A
block whose first packet the receiver did not receive is one that it
first learns of from a later signal -- a later source or repair
packet of the block, a packet of a successor block, or a FETCH
response that covers the block (Section 7.5) -- and its <tt>ts</tt> is the
arrival time of that signal.  When <tt>interleaveDepthMs</tt> is positive,
the base FEC deadline is:</t>

<artwork><![CDATA[base_deadline = ts + interleaveDepthMs
]]></artwork>
<t>Here a positive <tt>interleaveDepthMs</tt> is the complete first-to-last
source/repair send span of the block, which bounds source and repair
production at the media cadence and their serialization.  An absent
value supplies no elapsed-time base deadline.  A zero value invokes the
ISO <tt>protection_window_size</tt> alternative; this catalog profile supplies
no packet-count window, so a catalog-only receiver has no elapsed-time
base deadline from that value.  If an applicable count window is
accepted in-band, it governs separate count-based processing and is not
converted to milliseconds without an independently defined time
mapping.</t>
<t>The block assignment rule in Section 8.3 means that implementations do
not derive a full-block span or an FEC deadline from K, a Group count, a
per-symbol interval, or by a multiplier.  When the field is positive, a
deadline adds <tt>interleaveDepthMs</tt> and, where used,
<tt>reorderToleranceMs</tt>, each exactly once.</t>
<t>A receiver uses the catalog <tt>reorderToleranceMs</tt> allowance, when
present, for network jitter, one-way delay, reordering, and local
processing before abandoning the block.  That allowance is additive to
the base span and MUST be applied exactly once.  If
<tt>interleaveDepthMs</tt> is absent or zero, no elapsed-time deadline is
derived from this FEC window.  An applicable ISO packet-count window
accepted in-band governs separate count-based processing; it does not
become a millisecond deadline without an independently defined time
mapping.  When an elapsed-time deadline exists, the receiver moves the
block onward at that deadline and attempts FEC processing according to
its buffering model.  What a receiver of a multicast or AMT leg does
with a block that is still unrecovered at that deadline -- unicast
repair, a stall, or concealment -- is specified in Section 11.4.</t>
<t>A receiver MUST bound the state it holds for open blocks by a
receiver-local policy, for example a memory cap, a local timeout, or a
later block that has itself passed its FEC deadline or local timeout.
The bound is needed even when no FEC deadline exists: a receiver that
loses every repair packet of a block never learns its SSB_length
(Section 7.4).  For a block that has an FEC deadline, the policy MUST
NOT discard the block before that deadline, or while a unicast repair
FETCH for it is outstanding (Section 11.4.2), except under a memory
cap.  A block so discarded is treated from then on as having reached
its FEC deadline unrecovered and, on a track whose blocks Section
11.4.1 classifies, of unknown class.  The
policy is not signaled, and a receiver MUST keep it separate from the
catalog values: it does not change <tt>interleaveDepthMs</tt>,
<tt>reorderToleranceMs</tt>, or a deadline derived from them, and discarding
a block under it does not create an FEC deadline (Section 11.4).</t>
<t>The code is systematic (Section 4.1): a receiver plays source objects
on arrival, and the window adds latency only when a lossy leg forces
it to wait for recovery.  The <tt>interleaveDepthMs</tt> value is the
worst-case source/repair send-span budget when it is present.</t>
<t>Typical values are deployment choices for that send-span budget:</t>
<table>
<thead>
<tr>
<th>Application</th>
<th>interleaveDepthMs</th>
<th>Meaning</th>
<th>Recovery Latency</th>
</tr>
</thead>

<tbody>
<tr>
<td>Interactive (gaming, WebRTC)</td>
<td>33-133</td>
<td>Short source/repair span</td>
<td>33-133ms</td>
</tr>

<tr>
<td>Low-latency live</td>
<td>1000-2000</td>
<td>One-to-two second span</td>
<td>1-2s</td>
</tr>

<tr>
<td>Broadcast</td>
<td>4000</td>
<td>Four-second burst-spreading span</td>
<td>4s</td>
</tr>

<tr>
<td>ATSC 3.0 default</td>
<td>8000</td>
<td>Eight-second burst-spreading span</td>
<td>8s</td>
</tr>
</tbody>
</table><t><strong>Conformance cases.</strong></t>
<t>These cases exercise the boundary rules without deriving a block from a
Group count:</t>
<t>The first case uses this numeric vector:</t>

<sourcecode type="json"><![CDATA[{
  "fps": 30,
  "gopFrames": 30,
  "groupDurationMs": 1000,
  "accessUnitsPerBlock": 4,
  "accessUnitStartMs": [0, 33.333, 66.667, 100.0],
  "sourcePacketsPerAccessUnit": [2, 3, 1, 4],
  "K": 16,
  "SSB_length": 10,
  "interleaveDepthMs": 133,
  "firstSourceOrRepairMs": 0,
  "lastSourceOrRepairMs": 133,
  "sourceRepairSpanMs": 133
}
]]></sourcecode>

<ol spacing="compact">
<li>A 30 fps track with a 30-frame (1000 ms) GOP may close a block after
four access units (a four-frame access-unit interval).  With the send
schedule in the vector, <tt>interleaveDepthMs = 133</tt>.  An access unit
can produce multiple source packets, so the block is closed after
those access units, not after an assumed packet count.  For this
concrete vector, the four access
units begin at 0, 33.333, 66.667, and 100 ms, produce 2, 3, 1, and
4 source packets respectively, and therefore have <tt>SSB_length = 10
&lt;= K = 16</tt> as shown above:</li>
</ol>
<t>The publisher sends the last source or repair packet for that block
   by 133 ms; a later send would require a larger signaled window.  The
   one MoQ Group containing the GOP can therefore contain several such
   blocks.  Each repair packet still carries the actual
   <tt>(SS_Start, SSB_length)</tt>; the 133 ms value does not mean four MoQ
   Groups per block and is not a rounded four-frame duration.
2. With <tt>K = 4</tt>, one Group containing three source packets followed by
   a Group containing three source packets may be encoded as blocks of
   lengths 3 and 3, or as a block of length 4 spanning the Group
   boundary followed by a block of length 2.  Both are valid; the
   repair fields identify which partition was used.</t>

<sourcecode type="json"><![CDATA[   {
     "K": 4,
     "groupPacketCounts": [3, 3],
     "blockPartitions": [[3, 3], [4, 2]],
     "SS_Starts": [[0, 3], [0, 4]]
   }
]]></sourcecode>

<ol spacing="compact" start="3">
<li>If the stream ends with two source packets in the current block, the
publisher sends a short block with <tt>SSB_length = 2</tt>, <tt>F = 2 x T</tt>,
and no padding or skipped <tt>SS_ID</tt>.  There is no following block.</li>
</ol>
</section>

<section anchor="priority-and-congestion"><name>Priority and Congestion</name>
<t>Priorities in this document are expressed in the MoQ Transport
priority scale <xref target="I-D.ietf-moq-transport"></xref>: an 8-bit value (0-255)
in which a numerically LOWER value is delivered with HIGHER
precedence.  Repair tracks SHOULD use a numerically greater
(lower-precedence) priority than the source tracks they protect, so
that repair data is dropped first under congestion.  The
RECOMMENDED assignment places a repair track's priority value at
least 64 above its source track's (e.g. repair 240 against a source
track at the common default of 128):</t>
<table>
<thead>
<tr>
<th>Track Type</th>
<th>Priority (0-255, lower value = delivered first)</th>
<th>Notes</th>
</tr>
</thead>

<tbody>
<tr>
<td>Control/Signaling (incl. catalog)</td>
<td>0-63</td>
<td>Delivered first</td>
</tr>

<tr>
<td>Source Media</td>
<td>64-191 (e.g. 128)</td>
<td>Protected</td>
</tr>

<tr>
<td>Repair layer 0</td>
<td>192-255, default 240</td>
<td>Dropped first</td>
</tr>

<tr>
<td>Repair layer 1</td>
<td>192-255, &gt;= layer 0</td>
<td>Declared on the track</td>
</tr>

<tr>
<td>Repair layer n</td>
<td>192-255, &gt;= layer n-1</td>
<td>Monotonic by layer</td>
</tr>

<tr>
<td>Keyframe overlay</td>
<td>192-255, independent</td>
<td>Outside the layer order</td>
</tr>
</tbody>
</table><t>Layer priorities and the layer-0 default follow Section 6.3.4,
rule 3, so under congestion the highest layer is shed first and a
receiver degrades through its layer set in order; a keyframe
overlay's priority is independent of that order (Section 6.4.1).</t>
<t>Publishers and relays convey these priorities through the priority
fields and scheduling rules of <xref target="I-D.ietf-moq-transport"></xref>
(subscriber and publisher priority); QUIC itself defines no
wire-visible stream priority mechanism.</t>
<t>Under congestion, this priority separation ensures:</t>

<ol spacing="compact">
<li>Source media is preserved as long as possible</li>
<li>Repair overhead is gracefully shed</li>
<li>Receivers degrade to QUIC retransmission when FEC is unavailable</li>
</ol>
<t>On a multicast or AMT leg, the priorities of on-demand unicast repair
requests are set by Section 11.4.5.</t>
</section>

<section anchor="hybrid-unicast-and-multicast-delivery"><name>Hybrid Unicast and Multicast Delivery</name>
<t>This FEC mechanism is designed to support hybrid delivery architectures
where the same media stream is delivered via multiple transport paths
simultaneously.  Multicast delivery paths, TreeDN
integration, and the transport hierarchy (all Section 3) are
defined in <xref target="MOQ-MULTICAST"></xref>; this section covers
FEC-specific considerations for hybrid delivery.</t>

<section anchor="multicast-and-amt-delivery"><name>Multicast and AMT Delivery</name>
<t>IP multicast (including Source-Specific Multicast per <xref target="RFC4607"></xref>) and
Automatic Multicast Tunneling (AMT per <xref target="RFC7450"></xref>) provide efficient
one-to-many delivery but are inherently unreliable.  FEC enables receivers
to recover from packet loss without retransmission:</t>

<ul spacing="compact">
<li><strong>Native SSM</strong>: Receivers join multicast group directly</li>
<li><strong>AMT Tunneling</strong>: Receivers without native multicast connect via AMT
relays discovered through DRIAD (<xref target="RFC8777"></xref>)</li>
<li><strong>TreeDN Distribution</strong>: Hierarchical multicast trees per <xref target="RFC9706"></xref>,
with FEC protection at each hop</li>
</ul>
<t>The same MoQ objects (source and repair) can be transmitted over both
unicast (QUIC/WebTransport) and multicast (UDP/SSM/AMT) paths.  Receivers
on reliable unicast paths can skip FEC decoding (Section 3), while
receivers on lossy multicast paths use FEC for recovery and apply the
receiver repair policy of Section 11.4 to any block that FEC does not
recover.</t>

<artwork><![CDATA[Publisher
    |
    v
+----------------+
|   MoQ Relay    |
| (Origin/Root)  |
+-------+--------+
        |
   +----+----+--------------------+
   |         |                    |
   v         v                    v
Unicast   SSM Multicast      AMT Tunnel
(QUIC)    (Native)           (Encapsulated)
   |         |                    |
   v         v                    v
[Web]    [Native SSM         [Mobile/
Client    Clients]            Remote]

FEC:      FEC:                FEC:
Optional  Expected            Expected
]]></artwork>
</section>

<section anchor="deployment-applicability"><name>Deployment Applicability</name>
<t>The repair overhead this mechanism adds is justified only where the
delivery path actually loses packets, and multicast loss characteristics
differ by orders of magnitude across access technologies.  FEC strength
(P and Interleave Depth) is a per-path deployment choice, expressed by
which tracks each endpoint carries, not a protocol constant.</t>

<ul>
<li><t><strong>Engineered low-loss segments.</strong>  On managed PON or DOCSIS delivered
over a provisioned VLAN, steady-state loss is typically far below
10^-6.  Disabling FEC for such a path is signaled by omitting the
repair track from the tracks that path's endpoints carry.  Adding
repair symbols
on such a path spends bandwidth to recover losses that do not occur.</t>
</li>
<li><t><strong>FEC-capable broadcast PHYs.</strong>  ATSC 3.0, DVB-S2/S2X, and 5G broadcast
already apply bit-error correction on their own radio link (e.g.,
LDPC/BCH in ATSC 3.0 and DVB-S2/S2X).
Application-layer FEC is NOT a duplicate of that correction: it recovers
<em>packet erasures</em> the PHY cannot address -- bursts when reception falls
below the PHY threshold (rain fade, mobility, indoor reception), and
losses on upstream aggregation or backbone hops that the last-hop PHY
never sees.  Its value on these paths comes primarily from Interleave
Depth spreading a burst across the time domain, not from the code rate.
On a one-way broadcast downlink with no return path, application-layer
FEC is the only available erasure-recovery mechanism -- which is why
ATSC 3.0 (see Section 12) specifies it above the PHY.</t>
</li>
<li><t><strong>Public Internet and AMT tunnels.</strong>  Loss is real and bursty; a
non-trivial repair count with interleaving is RECOMMENDED.</t>
</li>
</ul>
</section>

<section anchor="interaction-with-multicast-quic"><name>Interaction with Multicast QUIC</name>
<t><xref target="QUIC-MULTICAST"></xref> defines a one-way QUIC transport in which a multicast
channel carries QUIC packets bearing STREAM or DATAGRAM frames, recovering
loss via unicast repair (the MC_CHANNEL_ACK mechanism) and defining no
Forward Error Correction of its own.  This FEC scheme MAY be used as the
recovery layer on such a channel, and is RECOMMENDED over unicast repair
for broadcast-scale audiences, where per-receiver retransmission does not
scale.</t>
<t>When this scheme is carried over a multicast QUIC channel:</t>

<ol>
<li><t><strong>Symbol-to-datagram mapping.</strong>  Each source or repair symbol (one MMTP
packet, per <xref target="MOQ-MMT"></xref>) SHOULD be carried in exactly one QUIC DATAGRAM
frame.  This aligns the erasure unit (a lost QUIC packet) with the FEC
symbol, so one lost packet erases exactly one source symbol.  STREAM
framing SHOULD NOT be used for FEC-protected media on a multicast
channel: a lost packet then spans a byte range crossing symbol
boundaries, defeating symbol-aligned recovery.</t>
</li>
<li><t><strong>Crypto boundary.</strong>  FEC encoding operates on application-layer
objects, ABOVE the QUIC packet protection of <xref target="QUIC-MULTICAST"></xref>.
Unlike bare multicast UDP -- which lacks QUIC's integrity guarantees
(see Section 14.4) -- the multicast QUIC binding applies a shared-key
AEAD per packet.  A sender computes source and repair symbols over the
unencrypted objects; the channel then applies its AEAD; a receiver
decrypts each surviving packet and recovers erased objects from the
decrypted source and repair symbols.  A lost packet cannot be
decrypted, but its object is reconstructed from other verified symbols,
so recovery does not depend on possessing it.</t>
</li>
<li><t><strong>Integrity of recovered objects.</strong>  The integrity frames of
<xref target="QUIC-MULTICAST"></xref> authenticate the bytes of each delivered packet.  A
FEC-reconstructed object was never carried in a single packet and is
therefore NOT individually covered by a packet hash; it inherits trust
transitively from the verified surviving symbols used to reconstruct
it.  Deployments requiring per-object authentication of recovered data
SHOULD additionally apply an object-level scheme (for example the
manifest-based bc-provenance profile of <xref target="MOQ-MULTICAST"></xref>
Section 7.2) computed below the FEC layer, which survives
reconstruction.</t>
</li>
<li><t><strong>Repair channel versus unicast repair.</strong>  A publisher using this
scheme broadcasts repair symbols on the multicast channel (the repair
track) rather than relying on unicast retransmission.  Receivers
covered by the repair flow SHOULD NOT drive unicast repair for losses
the FEC recovers, preserving the O(1) sender cost that motivates
broadcast FEC.  Unicast repair MAY be retained as a last resort for
losses exceeding the repair budget.  Section 11.4 specifies that last resort.</t>
</li>
</ol>
<t>Symbols delivered over a multicast QUIC channel are deduplicated by
their FEC coordinates, source symbols by SS_ID and repair symbols by
(SS_Start, RS_ID); <xref target="QUIC-MULTICAST"></xref> normatively requires only this
deduplication, and Section 8.3 permits combining them with symbols
received from other paths.</t>
</section>

<section anchor="receiver-repair-policy"><name>Receiver Repair Policy</name>
<t>This section specifies what a receiver of a multicast or AMT leg does
with a base-instance block of a source track that in-band FEC has not
recovered by the block's FEC deadline (Section 9).  A receiver on a
reliable MoQ/QUIC leg relies on transport retransmission (Section 3)
and does not need it, and nothing in this section adds a deadline or
a timer to such a leg.</t>
<t>Every step of this section is keyed on a block's FEC deadline, which
exists only when the track's catalog carries a positive
<tt>interleaveDepthMs</tt> (Section 9).  On a multicast or AMT leg, this
section therefore requires a positive <tt>interleaveDepthMs</tt>: a receiver
of a track whose catalog omits it or sets it to zero MUST disable the
block classification and unicast repair of this section for that
track.  The receiver still decodes in-band FEC from the symbols that
arrive (Section 8.3), with open-block state bounded by the local
policy of Section 9.  Media still missing at its presentation time is
lost: the loss of a RAP, or of a data unit that governs one, is
handled as for an unrecoverable keyframe-bearing block
(Section 11.4.2), and other loss is concealed as in Sections 11.4.3
and 11.4.4.</t>
<t>Every block receives in-band FEC processing.  A receiver MUST attempt
to recover every block, whatever its class, from the source and repair
symbols received on its multicast and AMT paths, together with any it
receives on other paths (Section 8.3), up to the block's FEC deadline.
The rest of this section governs only a block that is still
unrecovered at that deadline: the receiver does not hold all of its
SSB_length source symbols (Section 7.4), and decoding from the
symbols it holds has not recovered them.</t>
<t>A run of SS_IDs that the receiver lacks and that lies in no block it
has delimited belongs to one or more blocks of which it holds no
repair packet (Section 7.4).  For this section the receiver treats
such a run as one block of the instance: Section 11.4.1
classifies it from the source packets the receiver holds on either
side of it, and its repair is requested by the Group range of
Section 7.5, whose response also delimits the blocks it covers.</t>
<t>The policy distinguishes keyframe-bearing blocks, whose loss can stop
video decoding until the next Random Access Point (RAP), from other
blocks, whose loss damages only frames up to the next RAP.
Keyframe-bearing blocks are protected by priority unicast repair and
are the only blocks whose loss may stall video.  Other blocks are
repaired on a best-effort basis and, when repair fails, concealed.
Every frame and audio sample a receiver presents MUST be presented at
its authored time on the presentation clock shared by its tracks, and
a receiver MUST NOT stall video or pause that clock except for a
keyframe-bearing block (Section 11.4.2).</t>

<section anchor="block-classification"><name>Block Classification</name>
<t>A base block of a video source track is keyframe-bearing if it
carries, or may carry, any part of a RAP: a fragment of a RAP MFU, or
of the FT=0 or FT=1 data unit that governs it (<xref target="MOQ-MMT"></xref>
Sections 4.3 and 5.1).  The receiver classifies each block when the
block reaches its FEC deadline, from two inputs and only from them:
in-band evidence in the source packets it holds, and the
catalog-authored timing of the track, that is its group structure,
one MPU per group of the catalog group duration (<xref target="MOQ-MMT"></xref>
Sections 4.3 and 4.4.2), and its keyframe interval (<xref target="MOQ-MMT"></xref>
Section 4.4.3).  The block's SS_Start and SSB_length, once known
(Section 7.4), fix which SS_IDs belong to the block, and a positive
<tt>interleaveDepthMs</tt> with <tt>reorderToleranceMs</tt> fixes the elapsed-time
deadline at which the class is taken (Section 9).</t>
<t>The receiver first bounds what the block's missing source symbols can
carry.  The lower bounding packet is the last source packet it holds,
in SS_ID order, before the block's first missing source symbol; the
upper bounding packet is the first source packet it holds after the
block's last missing source symbol.  Either may lie in an adjacent
block.  Only FEC source symbols count: the AL-FEC signaling object of
<xref target="MOQ-MMT"></xref> Section 8 carries no SS_ID and is never a bounding
packet.  A publisher MUST assign the base SS_IDs of a track's source
packets in increasing order along the authored order of <xref target="MOQ-MMT"></xref>
Section 4.3, so every data unit the missing symbols can carry lies
between the data units of the two bounding packets, those two
included.</t>
<t>The block is keyframe-bearing if any of the following holds:</t>

<ol>
<li><t>A source packet the receiver holds from the block sets <tt>RAP_flag</tt>,
carries the 0x8B01 overlay header extension (Section 8.5.1), or is
an FT=0 packet, or two source packets it holds from the block carry
different MPU sequence numbers.</t>
</li>
<li><t>The two bounding packets carry different MPU sequence numbers, or
the lower bounding packet is the FT=0 packet or the first FT=1
packet of its MPU, or belongs to the first FT=2 sample of its MPU.
The missing symbols can then carry part of a group-start RAP, or of
the metadata that governs it (<xref target="MOQ-MMT"></xref> Section 4.3).</t>
</li>
<li><t>The catalog carries a usable keyframe interval, and the closed
interval between the authored decode times (<xref target="MOQ-MMT"></xref>
Section 5.1) of the samples of the two bounding packets contains an
instant a positive whole number of keyframe intervals after the
decode time of the first sample of their MPU.  Where a bounding
packet is an FT=1 packet, its time is the decode time of the first
sample it describes.  The interval is <tt>keyframeIntervalTicks</tt>, or
<tt>keyframeIntervalMs</tt> converted to the track timescale where that
conversion is exact; an inexact <tt>keyframeIntervalMs</tt> gives no usable
interval.</t>
</li>
</ol>
<t>The block is non-keyframe-bearing only when none of these holds, the
catalog carries a usable keyframe interval, the receiver holds both
bounding packets, and it can determine every value item 3 needs.
Every other block is of unknown class, and a receiver MUST treat a
block of unknown class as keyframe-bearing.  In particular:</t>

<ul>
<li><t>A block for which the receiver holds no lower or no upper bounding
packet at its FEC deadline is of unknown class, as is one for which
it cannot determine a decode time that item 3 needs.  So is a block
discarded before its FEC deadline under a memory cap (Section 9).</t>
</li>
<li><t>On a video track whose catalog entry carries no usable keyframe
interval, the receiver cannot exclude a keyframe after the group
start from any span, so every block of the track is keyframe-bearing
or of unknown class.</t>
</li>
<li><t>A block's keyframe classification uses its actual source-packet
range.  A block MAY contain a complete Group, span a Group boundary,
or close inside a Group; none of those shapes is inferred from
<tt>interleaveDepthMs</tt> or from the catalog's group duration.</t>
</li>
</ul>
<t>A receiver MUST NOT classify a block from any input other than those
this section names; in particular, the absence of <tt>RAP_flag</tt> on the
packets it holds says nothing about a packet that was lost.  A
publisher that wants receivers to be able to
apply the non-keyframe treatment of Section 11.4.3 publishes an exact
keyframe interval, which then binds every keyframe of the track
(<xref target="MOQ-MMT"></xref> Section 4.4.3).</t>
<t>The blocks of a track that the catalog identifies as audio are
treated by Section 11.4.4, not classified by this section.  A track
that the receiver cannot identify from its catalog entry is treated as
video.</t>
</section>

<section anchor="keyframe-bearing-blocks"><name>Keyframe-Bearing Blocks</name>
<t>When a keyframe-bearing block is still unrecovered at its FEC
deadline, a receiver that holds a MoQ session with a relay serving the
block's repair track MUST request on-demand unicast repair for it,
with the priority of Section 11.4.5.  The request is a standalone
FETCH <xref target="I-D.ietf-moq-transport"></xref>, over QUIC, of the block's
repair-track group, whose Group ID is the block's extended SS_Start,
or, for a run that the receiver has not delimited, of the Group range
that Section 7.5 derives from a lost SS_ID x of the run, with the
wrap epoch established as Section 7.5 specifies, for
instance by a TRACK_STATUS request when the receiver has received no repair-track
Group ID over MoQ (Sections 6.3.2 and 6.3.5): on layer 0, and on further layers in layer order where the
receiver needs more symbols than layer 0 carries.  The FETCH of a
single group MAY be limited to the object range that covers the
block's shortfall.  The repair symbols it returns are deduplicated
against the symbols already held by (SS_Start, RS_ID) (Section 8.3)
and fed to the same decoder; their SS_Start and SSB_length also
delimit a block the receiver had not delimited (Section 7.4).  The
receiver MUST NOT delay this request behind any non-keyframe or audio
repair; Section 11.4.6 covers its interplay with a keyframe overlay.
A FETCH completes or fails by MoQ Transport events, its last object
or an error; a receiver MUST NOT declare it failed on a locally chosen
timeout.</t>
<t>Only a keyframe-bearing block may stall video.  While its unicast
repair is outstanding, the receiver MAY hold video presentation for
it.  The block is unrecoverable when its unicast repair fails or
completes without recovering it, or when the receiver holds no MoQ
session through which to request it (for example a receiver that
consumes an MMTP stream without a MoQ session, <xref target="MOQ-MULTICAST"></xref>
Section 1.1).
If the data of an unrecoverable block that the receiver could not
recover includes, or may include, any part of a RAP (Section 11.4.1),
the receiver treats the track as discontinuous, MAY stall video, and
does not resume video before the next RAP (<xref target="MOQ-MMT"></xref> Section 6.1,
step 6).  Otherwise, as when it holds or has recovered every part of
the block's RAPs (including through a keyframe overlay,
Section 11.4.6), it conceals the block's remaining loss as for a
non-keyframe block (Section 11.4.3).</t>
<t>If the next RAP arrives complete before a keyframe repair completes,
the repair is moot: the receiver resumes from that RAP and SHOULD
cancel the FETCH.</t>
</section>

<section anchor="other-video-blocks"><name>Other Video Blocks</name>
<t>For a non-keyframe-bearing block of a video track, in-band FEC remains
the primary repair.  A receiver MAY also request unicast repair for
it, in the form of Section 11.4.2, but only on the terms of
Section 11.4.5: never ahead of or concurrently with keyframe repair,
and only within the budget that keyframe repair leaves unspent.</t>
<t>When such a block is unrecovered -- at its FEC deadline without
unicast repair, or when its unicast repair has not completed by the
presentation time of the first media it would repair -- the receiver
MUST NOT stall.  It conceals the affected frames, and every frame that
depends on them, until the next RAP, and keeps presentation and
audio/video synchronization running:</t>

<ul>
<li><t>Concealment fills the presentation interval of the frames it
replaces and ends at the authored presentation time of the next
frame the receiver presents.  The receiver MUST NOT drop later
frames to absorb the loss.  It derives no
timing for the frames it replaces (<xref target="MOQ-MMT"></xref> Section 5.1).</t>
</li>
<li><t>The concealment method is an implementation choice: for example
holding or replaying the last presented frame, or presenting decoder
output in which missing reference data is filled (commonly visible
as a solid or green fill).  The receiver MUST NOT submit to the
decoder a sample that the packaging's reassembly rules have
invalidated (<xref target="MOQ-MMT"></xref> Section 5.2).</t>
</li>
<li><t>The next RAP ends concealment, and the receiver resumes normal
decoding from it.</t>
</li>
</ul>
</section>

<section anchor="audio-blocks"><name>Audio Blocks</name>
<t>In-band FEC applies to the blocks of an audio track as to every block,
and a receiver MAY
request unicast repair for an audio block on the same best-effort
terms as for a non-keyframe video block (Section 11.4.5).  <tt>RAP_flag</tt>
on an audio packet does not make its block keyframe-bearing; that
class applies to video tracks only.</t>
<t>When an audio block is unrecovered, the receiver MUST conceal the lost
audio, for example with silence or packet-loss concealment, from the
end of the last audio it presented to the authored presentation time
of the next audio it presents, and MUST keep the audio clock advancing
through the loss.  It MUST NOT stall audio presentation waiting for a
repair that has not completed by the presentation time of the lost
audio.</t>
</section>

<section anchor="unicast-repair-budget-and-priority"><name>Unicast Repair Budget and Priority</name>
<t>A receiver's unicast repair budget is derived from the catalog, not
from a receiver-local rate or byte constant.  It is kept per MoQ
session and counted in bytes of repair symbol data, a repair symbol of
a track counting as that track's <tt>symbolSize</tt> T (Section 5.1).</t>

<ul>
<li><t>Each block that Section 11.4.1 treats as keyframe-bearing, including
a block of unknown class, credits the budget with P_t x T bytes when
it reaches its FEC deadline, where P_t is the total repair count of
its base instance (Section 6.4.1) and T is its track's
<tt>symbolSize</tt>.</t>
</li>
<li><t>A credit expires when the next keyframe-bearing block of the same
source track reaches its FEC deadline, so unspent budget never
accumulates beyond one block's credit per source track.</t>
</li>
<li><t>Every unicast repair FETCH debits the budget with the repair symbol
bytes it requests.  A FETCH of a Group range (Section 7.5) requests
every Group that starts in the range, a number the receiver learns
only from the response, and is debited with the repair symbol bytes
of every Group it returns.</t>
</li>
</ul>

<ol>
<li><t>A receiver does not withhold a keyframe-bearing block's repair for
lack of credit.  For a block that it has delimited, it requests at
most one repair-track Group per base repair layer, that is at most
the P_t x T bytes that the block itself credits.  For a run of
blocks that it has not delimited, it issues the one Group range
FETCH of Section 7.5 per base repair layer.  Each Group that FETCH
returns is the repair of one block of the run, and every block
holds at least one SS_ID of a range that spans at most K SS_IDs
(Section 7.5), so these FETCHes cost at most K x P_t x T bytes in
all, which can exceed the credit.  A debit that exceeds the remaining credit exhausts it:
the budget never falls below zero, and no deficit carries over to a
later credit.  A receiver MUST NOT have more than one repair FETCH
outstanding for the same block and repair layer.</t>
</li>
<li><t>Non-keyframe and audio repair MAY spend only unexpired credit that
keyframe-bearing blocks left unspent, and a receiver MUST NOT issue
a non-keyframe or audio repair FETCH that the remaining credit does
not cover.  Because the cost of a Group range FETCH is not known
before it is issued, a receiver MUST NOT request non-keyframe or
audio repair by a Group range.</t>
</li>
<li><t>A receiver MUST NOT issue a non-keyframe or audio repair FETCH
while a keyframe repair FETCH is outstanding on the same session,
and SHOULD cancel its outstanding non-keyframe and audio repair
FETCHes when a keyframe-bearing block reaches its FEC deadline
unrecovered.</t>
</li>
</ol>
<t>Priorities follow the ranges of Section 10.  A keyframe repair FETCH
MUST carry a subscriber priority <xref target="I-D.ietf-moq-transport"></xref> in the
Source Media range, numerically at most 191, and numerically no
greater than the priority of the source track it repairs where the
receiver knows that priority, so that it is delivered ahead of every
repair track and is not shed with repair data under congestion.  A
non-keyframe or audio repair FETCH MUST carry a priority numerically
no lower than that of the repair track it fetches, and so at least
192, so that it is shed first.</t>
</section>

<section anchor="relationship-to-the-keyframe-overlay"><name>Relationship to the Keyframe Overlay</name>
<t>The keyframe overlay of Section 6.4 and this policy are
complementary.  The overlay is publisher-side and proactive: it
protects RAP fragments across a block of its own, needs no return
path, and so also serves sessionless receivers.  This policy is
receiver-side and reactive: it spends unicast repair only on
keyframe-bearing blocks that in-band FEC actually failed to recover,
and it needs a MoQ session.  A receiver that holds both:</t>

<ul>
<li><t>classifies blocks by Section 11.4.1 whether or not it holds the
overlay;</t>
</li>
<li><t>MUST NOT defer the unicast repair of a keyframe-bearing block to
wait for overlay recovery, whose latency is the overlay's own block
span (Section 6.4.2), not the base deadline;</t>
</li>
<li><t>ends its wait for a RAP with whichever of base decoding, overlay
decoding, or unicast repair supplies the RAP's fragments first; and</t>
</li>
<li><t>having recovered a block's RAP MFU fragments through the overlay,
and holding the FT=0 and FT=1 data units that govern them, conceals
the rest of that block's loss as for a non-keyframe block
(Section 11.4.3) and SHOULD cancel any outstanding keyframe repair
FETCH for it.  The overlay covers only packets that set <tt>RAP_flag</tt>
(Section 6.4.2), so it does not by itself recover a lost FT=0 or
FT=1 data unit.</t>
</li>
</ul>
</section>
</section>
</section>

<section anchor="atsc-3-0-compatibility"><name>ATSC 3.0 Compatibility</name>
<t>This specification is designed for interoperability with ATSC A/331
<xref target="ATSC-A331"></xref> Application-Layer FEC.</t>

<section anchor="mapping-to-a-331-al-fec"><name>Mapping to A/331 AL-FEC</name>
<table>
<thead>
<tr>
<th>ATSC A/331 Concept</th>
<th>MoQ FEC Equivalent</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>&lt;FECParameters&gt;</tt></td>
<td>Catalog <tt>fec</tt> field</td>
</tr>

<tr>
<td><tt>&lt;RepairFlow&gt;</tt></td>
<td>Repair track subscription</td>
</tr>

<tr>
<td><tt>fecOTI</tt> (in S-TSID)</td>
<td>Derived OTI (Section 4.2)</td>
</tr>

<tr>
<td>Source TOI range</td>
<td>Group ID range per Section 8</td>
</tr>

<tr>
<td><tt>maximumDelay</tt></td>
<td>No direct mapping to <tt>interleaveDepthMs</tt>; calculate the source-to-associated-repair delivery delay from the ROUTE schedule (<xref target="MOQ-MMT"></xref> Sections 12.2-12.3)</td>
</tr>

<tr>
<td><tt>overhead</tt></td>
<td>From P and K (<xref target="MOQ-MMT"></xref> Sections 12.2-12.3)</td>
</tr>
</tbody>
</table><t><tt>overhead</tt> is not carried in the catalog; it is converted to and from
<tt>repairSymbols</tt> by the informative rules of <xref target="MOQ-MMT"></xref> Sections 12.2
and 12.3.</t>
<t>Publishers ingesting ATSC 3.0 broadcasts SHOULD preserve the original
FEC parameters and pass them through in the catalog <tt>fec</tt> field.
<tt>overhead</tt> in particular is not passed through verbatim: the catalog
carries P rather than a percentage, and <tt>overhead</tt> is converted as
above.</t>
</section>

<section anchor="sub-blocks-in-broadcast-systems"><name>Sub-Blocks in Broadcast Systems</name>
<t>This subsection is informative broadcast-interoperability guidance,
not an interoperability requirement of this document.  Sub-block
operation (Section 7.3) remains available to broadcast systems that
carry an explicit OTI, such as the A/331 S-TSID <tt>fecOTI</tt>; the
ISO 23008-1 AL-FEC message carries no OTI, and the split source
blocks of <xref target="ISO.23008-1"></xref> are the two-stage FEC coding structure of
Clause C.2.2, which this document does not use.  The number of
source symbols per sub-block (K_sub &lt;= K) is derived from the
signaled parameters: K_sub = ceil(K / N), where K is the block's
source symbol count, at most the catalog <tt>sourceSymbols</tt>, and N is the
Number of Sub-Blocks field of the explicitly signaled OTI.</t>
<t>When sub-blocks are used:</t>

<ol>
<li><t>When positive, <tt>interleaveDepthMs</tt> keeps its Section 5.1 meaning,
the span of the FULL block.  A sub-block's own span can be estimated
as <tt>interleaveDepthMs * K_sub / K</tt> for partial-recovery scheduling;
the estimate never replaces the full-block field or deadline
(Section 9).  A zero value uses the ISO packet-count alternative and
supplies no millisecond span.  This enables faster partial recovery
at the cost of higher repair overhead (P repair symbols per
sub-block instead of per block).</t>
</li>
<li><t>The receiver tracks source symbol arrivals per sub-block (keyed
by the block's SS_Start and the sub-block index) and can emit
recovered data as soon as each sub-block completes, without waiting
for the full block.</t>
</li>
<li><t>The receiver uses the derived sub-block length K_sub (not K
from the catalog) for per-sub-block recovery when K_sub &lt; K.</t>
</li>
</ol>
<t>Sub-blocks are primarily useful for large-K configurations (K &gt;= 64)
where full-block recovery latency exceeds acceptable limits.</t>
</section>
</section>

<section anchor="interaction-with-cmaf-packaging"><name>Interaction with CMAF Packaging</name>
<t>This section is informative.</t>
<t>This specification's signaling (Section 5) is container-agnostic,
and a repair track can sit alongside a source track carrying CMAF
content in MMTP packaging in the same namespace:</t>

<artwork><![CDATA[+-------------------------------------------------+
|              MoQ Track Namespace                |
+-------------------------------------------------+
|                                                 |
|  Source Track (CMAF content, MMTP packaged)     |
|  +-----------------------------------------+    |
|  | Object 0: MMTP packet carrying FT=0     |    |
|  | Object 1: MMTP packet carrying FT=1     |    |
|  | Object 2: MMTP packet carrying FT=2     |    |
|  | ...                                     |    |
|  +-----------------------------------------+    |
|                                                 |
|  Repair Track (this specification)              |
|  +-----------------------------------------+    |
|  | Object 0: Repair for Block 0            |    |
|  | Object 1: Repair for Block 1            |    |
|  | ...                                     |    |
|  +-----------------------------------------+    |
|                                                 |
+-------------------------------------------------+
]]></artwork>
<t>The symbol construction, however, is not container-agnostic: the
only source-symbol construction this document specifies is the
MMTP-packet construction of Section 7.3.  Applying FEC
directly to CMAF chunk payloads (<xref target="I-D.ietf-moq-cmsf"></xref>) would
require a companion specification defining the chunk-to-symbol
segmentation, padding, length framing, and ESI mapping, under a block
profile of its own (Section 5.1); none is
defined here, and this section sketches the intended track
relationship only.  A CMAF deployment wanting FEC protection
carries the media as mmtp-packaged tracks (an MPU corresponds to a
CMAF Fragment; see <xref target="MOQ-MMT"></xref>).</t>
<t>A publisher MAY choose a segment duration equal to <tt>interleaveDepthMs</tt>
and close blocks at segment boundaries, so that a segment holds one
chosen block's source symbols and a CDN relay can perform FEC recovery
at the segment level before forwarding to FEC-unaware HLS/DASH clients.
The boundary is an explicit publisher choice; the duration alone does
not create or identify a block.</t>
</section>

<section anchor="security-considerations"><name>Security Considerations</name>

<section anchor="fec-does-not-provide-confidentiality"><name>FEC Does Not Provide Confidentiality</name>
<t>FEC repair symbols are derived from source data.  If source data is
encrypted, repair symbols will also be encrypted by virtue of
operating on ciphertext.  However, FEC itself provides no
confidentiality guarantees.</t>
</section>

<section anchor="repair-symbol-manipulation"><name>Repair Symbol Manipulation</name>
<t>An attacker who can modify repair symbols could cause receivers to
reconstruct incorrect source data.  Integrity protection of repair
tracks is RECOMMENDED, using the same mechanisms as source tracks
(e.g., QUIC packet protection).</t>
</section>

<section anchor="amplification"><name>Amplification</name>
<t>FEC repair symbols represent additional bandwidth.  Publishers MUST
NOT generate excessive repair symbols that could be used for bandwidth
amplification attacks.  The repair overhead (P/K) SHOULD be limited
to reasonable values (e.g., &lt;= 50%).  The bound applies per FEC
instance (Section 6.4.1).</t>
<t>Layering changes the shape of the amplification exposure, because the
attacker's lever is now which layers a victim can be made to receive
rather than only whether it receives repair at all.  Each layer i adds
P_i x T bytes per source block, so a receiver induced to hold more
layers receives proportionally more repair traffic.  Deployments
SHOULD bound the number of layers any single receiver may hold, and
SHOULD apply the same join authorization to repair-layer endpoints as
to media endpoints; a repair-only endpoint (Section 6.3.6) is not
less sensitive than a media one merely because it carries no media.</t>
<t>A receiver MUST NOT be made to receive a repair layer it did not
join.  A publisher or relay MUST NOT push a repair-layer endpoint to
a receiver that has not joined it, and MUST NOT add a layer to an
endpoint a receiver has already joined as a way of raising that
receiver's protection.</t>
</section>

<section anchor="multicast-fec-security"><name>Multicast FEC Security</name>
<t>When FEC is used over multicast (SSM/AMT), additional considerations
apply:</t>

<ol>
<li><t><strong>No QUIC Protection</strong>: Multicast UDP lacks QUIC's integrity
guarantees.  Publishers SHOULD use DTLS-SRTP or equivalent for
payload encryption when confidentiality is required.</t>
</li>
<li><t><strong>Repair Injection</strong>: Attackers could inject malicious repair
symbols on multicast networks.  Receivers SHOULD verify FEC block
consistency by checking that decoded data matches expected patterns
(e.g., valid media container structure).</t>
</li>
<li><t><strong>Source Authentication</strong>: See <xref target="MOQ-MULTICAST"></xref> Section 7.1.</t>
</li>
<li><t><strong>Block Integrity</strong>: Receivers MAY implement block-level checksums
to detect corrupted recovery.  If decoded source data fails
integrity checks, receivers SHOULD request retransmission via
unicast fallback.</t>
</li>
<li><t><strong>Repair Policy Inputs</strong>: The in-band evidence that Section 11.4.1
classifies blocks from, and the SSB_length by which Section 7.4
completes a short block, are unauthenticated on bare multicast.
An injected packet that marks a block keyframe-bearing costs at
most the unicast repair that block's own credit covers
(Section 11.4.5).  An injected source packet inside a block's gap
can instead narrow the bounds of Section 11.4.1 until a
keyframe-bearing block is classified otherwise, and an injected
repair packet carrying a false SS_Start or SSB_length, accepted
before the genuine ones, can mis-delimit a block, mark it complete
early, or cause its genuine repair packets to be discarded as
inconsistent (Section 7.4).  Deployments
exposed to injection SHOULD authenticate source and repair packets
(<xref target="MOQ-MULTICAST"></xref> Section 7.2).</t>
</li>
</ol>
</section>

<section anchor="atsc-3-0-signed-region-a3sa-considerations"><name>ATSC 3.0 Signed Region (A3SA) Considerations</name>
<t>The Source FEC Payload ID falls outside the A3SA signed region, and
neither <xref target="ISO.23008-1"></xref> nor <xref target="ATSC-A331"></xref> provides a carriage of the
SS_ID inside it (Section 8.5).  An attacker who can modify it without
detection could redirect source symbols to incorrect FEC blocks,
causing recovery failures or corrupted output.  A receiver that
requires authenticated FEC block assignment therefore treats the
trailer as Section 8.5 requires.  On multicast networks without A3SA
verification, receivers SHOULD cross-check the SS_ID against the MMTP
packet_sequence_number to detect obvious tampering (e.g., an SS_ID
that advances further than the packet_sequence_number of the same
packet_id, whereas SS_ID advances by one per FEC source packet,
Section 8.3).</t>
</section>
</section>

<section anchor="iana-considerations"><name>IANA Considerations</name>

<section anchor="moq-registrations"><name>MoQ Registrations</name>
<t>This document requests one registration in the MOQT Properties
registry of <xref target="I-D.ietf-moq-transport"></xref>:</t>
<table>
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Scope</th>
<th>Specification</th>
</tr>
</thead>

<tbody>
<tr>
<td>0x11</td>
<td>FEC_SOURCE_INFO</td>
<td>Object</td>
<td>This document, Section 5.3</td>
</tr>
</tbody>
</table><t>The type is odd, so under the key-value parity rule of
<xref target="I-D.ietf-moq-transport"></xref> the Property is length-prefixed and
byte-valued (Section 5.3).  The scope is Object: FEC Source Info
describes the individual object it tags, and carries no track-wide
meaning.</t>
<t>0x11 lies in the range 0x00 to 0x77, for which
<xref target="I-D.ietf-moq-transport"></xref> states a registration policy of Standards
Action or IESG Approval.  That policy is not reachable by an
individual draft, so this document asks for 0x11 as a provisional
registration in the table <xref target="I-D.ietf-moq-transport"></xref> maintains for
other active drafts in the MoQ working group, on the same terms as
the existing entries for draft-ietf-moq-loc and
draft-ietf-moq-secure-objects.  That ask is contingent on this
document being adopted.  If 0x11 is not available on those terms,
an odd value in the range 0x80 to 0x37FF, whose policy is
Specification Required, is obtainable by this document on its own;
it costs one additional byte per tagged object and changes nothing
else in this specification.</t>
<t>The even value 0x10, used by deployed implementations for this
purpose, is deliberately not requested, and this document could not
reserve it in any case: <xref target="I-D.ietf-moq-transport"></xref> already lists
0x10 as the TIMESTAMP Object Property of draft-ietf-moq-loc, at
Object scope in the same Property Type space.  Section 5.3 gives the
resulting collision and its consequences.</t>
<t>This document requests no registration in any MoQ message type
registry.  FEC signaling uses no MoQ control message (Section 5.2);
no document in this suite requests a control-message codepoint.  The
header extension type 0x8B01 of Section 8.5.1 is an MMTP value, not a
MoQ one; <xref target="ISO.23008-1"></xref> Clause 9.2.3 defines no registry of MMTP
header extension types, so its use requires no IANA action.</t>
</section>

<section anchor="fec-algorithm-registry"><name>FEC Algorithm Registry</name>
<t>This document requests creation of a &quot;MoQ FEC Algorithms&quot; registry
with the following initial values:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Algorithm</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td>0x00</td>
<td>None</td>
<td>This document</td>
</tr>

<tr>
<td>0x01</td>
<td>RaptorQ</td>
<td><xref target="RFC6330"></xref></td>
</tr>

<tr>
<td>0x02</td>
<td>Reed-Solomon</td>
<td><xref target="RFC5510"></xref></td>
</tr>

<tr>
<td>0x03-0xFF</td>
<td>Unassigned</td>
<td></td>
</tr>
</tbody>
</table><t>New registrations require Specification Required policy.</t>
<t>Only &quot;None&quot; (0x00) and RaptorQ (0x01) are specified for
interoperation by this document; other registered values, including
Reed-Solomon (0x02), are extension points whose interoperable use
requires their own specifications (Section 4.3).</t>
</section>

<section anchor="catalog-packaging-value"><name>Catalog Packaging Value</name>
<t>This document defines the catalog <tt>packaging</tt> value &quot;fec-repair&quot;
(Section 5.1) for repair tracks, extending the allowed packaging
values of the MoQ Streaming Format <xref target="I-D.ietf-moq-msf"></xref>
Section 5.2.4.  If a registry of packaging values is established
for that format, this document requests registration of:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td>&quot;fec-repair&quot;</td>
<td>Repair objects protecting a source track</td>
<td>This document</td>
</tr>
</tbody>
</table></section>
</section>

</middle>

<back>
<references><name>References</name>
<references><name>Normative References</name>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-moq-msf.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-moq-transport.xml"/>
<reference anchor="ISO.23008-1" target="">
  <front>
    <title>Information technology - High efficiency coding and media delivery in heterogeneous environments - Part 1: MPEG media transport (MMT)</title>
    <author>
      <organization>ISO/IEC</organization>
    </author>
    <date year="2023"></date>
  </front>
  <seriesInfo name="ISO/IEC" value="23008-1:2023"></seriesInfo>
</reference>
<reference anchor="ISO.23008-1.AMD1" target="">
  <front>
    <title>Information technology - High efficiency coding and media delivery in heterogeneous environments - Part 1: MPEG media transport (MMT) - Amendment 1: Signalling of adaptive FEC scheme</title>
    <author>
      <organization>ISO/IEC</organization>
    </author>
    <date year="2025" month="May"></date>
  </front>
  <seriesInfo name="ISO/IEC" value="23008-1:2023/Amd 1:2025"></seriesInfo>
</reference>
<reference anchor="MOQ-MMT" target="">
  <front>
    <title>MPEG Media Transport (MMT) Packaging for Media over QUIC</title>
    <author fullname="Omar Ramadan" initials="O." surname="Ramadan">
      <organization>Blockcast</organization>
    </author>
    <date year="2026"></date>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-ramadan-moq-mmt-00"></seriesInfo>
</reference>
<reference anchor="QUIC-MULTICAST" target="https://datatracker.ietf.org/doc/draft-jholland-quic-multicast/">
  <front>
    <title>Multicast Extension for QUIC</title>
    <author fullname="Jake Holland" initials="J." surname="Holland">
      <organization>Akamai Technologies, Inc.</organization>
    </author>
    <author fullname="Lucas Pardue" initials="L." surname="Pardue"></author>
    <author fullname="Max Franke" initials="M." surname="Franke">
      <organization>TU Berlin</organization>
    </author>
    <author fullname="Kyle Rose" initials="K." surname="Rose">
      <organization>Akamai Technologies, Inc.</organization>
    </author>
    <date year="2026" month="July" day="6"></date>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-jholland-quic-multicast-09"></seriesInfo>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.1982.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6330.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
</references>
<references><name>Informative References</name>
<reference anchor="ARIB-B60" target="">
  <front>
    <title>MMT-Based Media Transport Scheme in Digital Broadcasting Systems</title>
    <author>
      <organization>ARIB</organization>
    </author>
    <date></date>
  </front>
  <seriesInfo name="ARIB STD-B60" value="Version 1.14"></seriesInfo>
</reference>
<reference anchor="ATSC-A331" target="https://www.atsc.org/atsc-documents/3312017-signaling-delivery-synchronization-error-protection/">
  <front>
    <title>Signaling, Delivery, Synchronization, and Error Protection</title>
    <author>
      <organization>ATSC</organization>
    </author>
    <date year="2026" month="February"></date>
  </front>
  <seriesInfo name="ATSC" value="A/331:2026-02"></seriesInfo>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-moq-cmsf.xml"/>
<reference anchor="MOQ-MULTICAST" target="">
  <front>
    <title>Multicast Delivery and Endpoint Discovery for Media over QUIC</title>
    <author fullname="Omar Ramadan" initials="O." surname="Ramadan">
      <organization>Blockcast</organization>
    </author>
    <date year="2026"></date>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-ramadan-moq-multicast-00"></seriesInfo>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4607.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5510.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7450.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8777.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9706.xml"/>
</references>
</references>

<section anchor="example-message-flows"><name>Example Message Flows</name>

<section anchor="catalog-driven-fec"><name>Catalog-Driven FEC</name>
<t>The subscriber learns the complete FEC configuration from the
track's catalog entry before subscribing:</t>

<sourcecode type="json"><![CDATA["fec": {
  "algorithm": "raptorq",
  "blockProfile": "iso-ssbg1-v1",
  "sourceSymbols": 32,
  "repairSymbols": 8,
  "symbolSize": 1312,
  "interleaveDepthMs": 1000,
  "reorderToleranceMs": 40,
  "repairTrack": "video/repair"
}
]]></sourcecode>

<artwork><![CDATA[Publisher                              Subscriber
    |                                       |
    |  (catalog obtained; fec field read)   |
    |                                       |
    |  SUBSCRIBE(sub_id=1, track=video)     |
    |<--------------------------------------|
    |                                       |
    |  SUBSCRIBE_OK(sub_id=1)               |
    |-------------------------------------->|
    |                                       |
    |  SUBSCRIBE(sub_id=2,                  |
    |    track=video/repair)                |
    |<--------------------------------------|
    |                                       |
    |  SUBSCRIBE_OK(sub_id=2)               |
    |-------------------------------------->|
    |                                       |
    |  [Source objects of group 0]          |
    |-------------------------------------->|
    |                                       |
    |  [Repair objects, group=0, obj=0..7]  |
    |-------------------------------------->|
    |                                       |
]]></artwork>
<t>In this flow the track is mmtp-packaged with a one-second group
duration (one MPU per MoQ Group, <xref target="MOQ-MMT"></xref> Section 4.3).  That group
duration describes the MoQ grouping; it does not derive an FEC block.
For example, if the first block starts at SS_ID 0 and is full, its
repair Group is its extended SS_Start, 0 (Section 7.5), the next block
starts at SS_ID 32, and its repair Group is 32.  A publisher MAY choose
shorter blocks inside a Group or a block that crosses the Group
boundary; each repair packet carries the actual <tt>SSB_length</tt>.  The
subscriber's decoder configuration is derived from the catalog fields
and each block's <tt>SSB_length</tt> (Section 4.2): for a full block
(<tt>SSB_length = K = 32</tt>), Transfer Length F = SSB_length x T = 32 x
1312 = 41,984 bytes, Symbol Size T = 1312, Z = 1, N = 1, Al = 8.  No
in-session message is required, and this track carries no AL-FEC
signaling object (<xref target="MOQ-MMT"></xref> Section 8).</t>
</section>
</section>

<section anchor="catalog-example"><name>Catalog Example</name>
<t>Complete catalog with FEC and multicast configuration:</t>

<sourcecode type="json"><![CDATA[{
  "version": "draft-01",
  "tracks": [
    {
      "name": "video",
      "packaging": "mmtp",
      "mmtpMode": "mfu",
      "timescale": 90000,
      "presentationAnchorTicks": 0,
      "groupDurationMs": 1000,
      "codec": "avc1.64001f",
      "width": 1920,
      "height": 1080,
      "framerate": 30,
      "bitrate": 4990000,
      "fec": {
        "algorithm": "raptorq",
        "blockProfile": "iso-ssbg1-v1",
        "sourceSymbols": 625,
        "repairSymbols": 125,
        "symbolSize": 1000,
        "interleaveDepthMs": 1000,
        "reorderToleranceMs": 40,
        "repairTrack": "video/repair"
      }
    },
    {
      "name": "video/repair",
      "packaging": "fec-repair",
      "depends": ["video"],
      "repairSymbols": 125,
      "priority": 240
    },
    {
      "name": "audio",
      "packaging": "mmtp",
      "mmtpMode": "mfu",
      "timescale": 48000,
      "presentationAnchorTicks": 0,
      "groupDurationMs": 1000,
      "codec": "mp4a.40.2",
      "samplerate": 48000,
      "channelConfig": "2",
      "bitrate": 128000,
      "fec": {
        "algorithm": "raptorq",
        "blockProfile": "iso-ssbg1-v1",
        "sourceSymbols": 32,
        "repairSymbols": 8,
        "symbolSize": 512,
        "interleaveDepthMs": 1000,
        "reorderToleranceMs": 40,
        "repairTrack": "audio/repair"
      }
    },
    {
      "name": "audio/repair",
      "packaging": "fec-repair",
      "depends": ["audio"],
      "repairSymbols": 8,
      "priority": 240
    }
  ],
  "multicast": {
    "endpoints": [{
      "sourceAddress": "198.51.100.100",
      "groupAddress": "232.1.1.50",
      "port": 5000,
      "tracks": [
        { "name": "video",        "packetId": 1 },
        { "name": "video/repair", "packetId": 2 },
        { "name": "audio",        "packetId": 3 },
        { "name": "audio/repair", "packetId": 4 }
      ]
    }]
  }
}
]]></sourcecode>
<t>Parameter consistency: both tracks use one-second MMTP groups (one
MPU per MoQ Group), and each has a 1000 ms source/repair send-span
budget.  The group duration does not determine the FEC partition.  A
worked capacity check must include the MMTP and MPU-mode headers, not
only the media bitrate.  With no MMTP header extension, a timed FT=2
packet has the following media capacity, depending on whether it
starts a data unit (<xref target="MOQ-MMT"></xref> Section 5.2):</t>

<artwork><![CDATA[FI=0 or FI=1: T - 2 (length) - 12 (MMTP) - 8 (MPU) - 14 (DU) = T - 36
FI=2 or FI=3: T - 2 (length) - 12 (MMTP) - 8 (MPU)           = T - 22
]]></artwork>
<t>The source packet also carries a 4-byte Source FEC Payload ID on the
wire, outside the protected packet and therefore outside these symbol
budgets.  FT=0/FT=1 metadata consumes source packets but does not carry
sample bytes, and any MMTP extension consumes additional space.  Every
protected MMTP packet still MUST fit within <tt>T - 2</tt>.  Using the larger
continuation capacity gives a media ceiling, not a packetization plan:</t>

<ul spacing="compact">
<li>Video: 4,990,000 bit/s x 1.0 s / 8 = 623,750 bytes of media per
one-second group.  <tt>K x (T - 22) = 625 x 978 = 611,250</tt> bytes is
an upper bound on the media capacity of one full block.  The media
therefore needs at least
<tt>ceil(623,750 / 978) = 638</tt> source packets and at least two K=625
blocks; MMTP metadata, fragmentation, and authored packet boundaries
can require more.  Repair overhead is <tt>P / K = 125 / 625 = 20%</tt>.</li>
<li>Audio: 128,000 bit/s x 1.0 s / 8 = 16,000 bytes of media per group;
the upper-bound capacity of one full block is
<tt>K x (T - 22) = 32 x 490 = 15,680</tt> bytes.  The media therefore
needs at least <tt>ceil(16,000 / 490) = 33</tt> source packets and at least
two K=32 blocks; packetization and metadata can require more.  Repair
overhead is <tt>P / K = 8 / 32 = 25%</tt>.</li>
</ul>
<t>The publisher MUST choose the actual source-packet count and block
boundaries so that every packet, including FT=0 and FT=1 metadata,
fits the selected symbol size and every block's repair fields describe
the actual <tt>(SS_Start, SSB_length)</tt> partition.  These calculations are
capacity examples, not a rule that one FEC block equals one Group.</t>
<t>The catalog envelope is the MSF root (<xref target="I-D.ietf-moq-msf"></xref>
Section 5.1); track entries carry the flat base track fields of
<xref target="I-D.ietf-moq-msf"></xref> Section 5.2 (<tt>codec</tt>, <tt>width</tt>, <tt>samplerate</tt>,
...) alongside the <tt>fec</tt> object this document defines, and inherit
the namespace of the catalog track (<xref target="I-D.ietf-moq-msf"></xref>
Section 5.2.2).  The <tt>multicast</tt> field uses the multicast endpoint format defined in
<xref target="MOQ-MULTICAST"></xref> Section 4.1: a one-element <tt>endpoints</tt> array.  Per
<xref target="MOQ-MULTICAST"></xref> Section 5, all multicast delivery uses MMTP packets
regardless of a track's unicast packaging, so each track listed on
the endpoint carries a <tt>packetId</tt> that routes its MMTP packets on the
multicast UDP path.</t>
</section>

</back>

</rfc>
