<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.11 (Ruby 3.2.4) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-lcurley-moq-transfork-00" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.21.0 -->
  <front>
    <title abbrev="moqtf">Media over QUIC - Transfork</title>
    <seriesInfo name="Internet-Draft" value="draft-lcurley-moq-transfork-00"/>
    <author fullname="Luke Curley">
      <organization>Discord</organization>
      <address>
        <email>kixelated@gmail.com</email>
      </address>
    </author>
    <date year="2024" month="May" day="27"/>
    <area>wit</area>
    <workgroup>moq</workgroup>
    <abstract>
      <?line 25?>

<t>TODO Abstract</t>
    </abstract>
    <note removeInRFC="true">
      <name>Discussion Venues</name>
      <t>Discussion of this document takes place on the
    Media Over QUIC Working Group mailing list (moq@ietf.org),
    which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/moq/"/>.</t>
      <t>Source for this draft and an issue tracker can be found at
    <eref target="https://github.com/kixelated/moq-transfork"/>.</t>
    </note>
  </front>
  <middle>
    <?line 30?>

<section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
      <?line -18?>

</section>
    <section anchor="fork">
      <name>Fork</name>
      <t>This draft is based on moq-transport-03 <xref target="moqt"/>.
The concepts, motivations, and terminology are very similar on purpose.
When in doubt, refer to the original draft.</t>
      <t>I absolutely believe in the motivation and potential of Media over QUIC.
The layering is phenomenal and addresses many of the problems with current live media protocols.
I fully support the goals of the working group and the IETF process.</t>
      <t>However, there are some flaws with MoqTransport that I'd like to address.
It's been years and we're still unable to align on the most critical property of the transport... how to utilize QUIC.
The draft supports multiple different approaches, but it does so by leaving important properties dynamic or undefined.
In our RUSH to standardize a protocol, the QUICR solutions have led to WARP in ideals.</t>
      <t>This fork is meant to be constructive; an alternative vision.
We've been arguing about some of these issues for years now and I don't expect that will change any time soon.
I'd like to try leading by example, demonstrating that it's possible to simplify the protocol and still support a documented set of use-cases.</t>
      <t>Here's an overview of the notable differences between MoqTransport and MoqTransfork:</t>
      <section anchor="object-model">
        <name>Object Model</name>
        <t>The object model is an abstraction exposed to the application, forming the basis of the transport API.</t>
        <t>The MoqTransport object model vaguely maps to media concepts, where a Group is a Video GoP and an Object is a Video Frame.
However, there's no agreed upon way to utilize QUIC, leading to the compromise that the publisher chooses a "delivery preference" for each track.
As a the result the properties of the object model change dynamically at runtime, as the properties of a QUIC stream (or datagram) are moved between a track, group, or object.
The number of permutations quickly becomes unmanageable and every conversion has to be caveated with "when using a stream per X".</t>
        <t>The MoqTransfork object model is instead static and maps directly to QUIC.
A Group is always an ordered set of bytes, served via a QUIC stream or datagram depending on the subscription.
This simplification is able to support all of the documented use-cases; see the Appendix.</t>
      </section>
      <section anchor="prioritization">
        <name>Prioritization</name>
        <t>Prioritization is important for low-latency, ensuring the publisher sends the most important media first during congestion.</t>
        <t>MoqTransport uses producer chosen priorities via send order.
As the original proponent of this approach, I'm ashamed to admit that I was wrong.
Reality is more nuanced; both the subscriber and publisher need to work together.</t>
        <t>MoqTransfork instead delegates the priority decision for the last mile to the subscriber.
This is done via a <tt>Track Priority</tt> and <tt>Group Order</tt> field within <tt>SUBSCRIBE</tt>.
If there's a single viewer, then this priority can be used all the way to origin.
However when there are multiple conflicting viewers, then a relay should use the producer's preference as advertised in <tt>INFO</tt>.</t>
      </section>
      <section anchor="control-streams">
        <name>Control Streams</name>
        <t>At the core of any transport are control messages.</t>
        <t>MoqTransport control messages are fine, but have the potential for head-of-line blocking as they share a single stream.
There's also just a lot of messages for state transitions such as <tt>UNSUBSCRIBE</tt>, <tt>SUBSCRIBE_ERROR</tt>, <tt>SUBSCRIBE_DONE</tt>, etc.</t>
        <t>MoqTransfork continues the trend of leveraging QUIC with separate control streams, like one stream per subscription.
These control streams are terminated when endpoints close or reset (including an error code) the stream in order to directly leverage QUIC's stream state machine.
This removes any messages that start with <tt>UN</tt> or end with <tt>_DONE</tt>, <tt>_ERROR</tt>, <tt>_RESET</tt>, etc.</t>
      </section>
      <section anchor="byte-offsets">
        <name>Byte Offsets</name>
        <t>When a connection or subscription is severed, it's often desirable to resume where it left off.</t>
        <t>MoqTransport implements this via subscriptions that can start/end at an object ID within a group.
This is an okay approach, however it results in redownloading partial objects and results in a fragmented cache at parsed boundaries.</t>
        <t>MoqTransfork instead utilizes FETCH to serve incomplete Groups starting at a byte offset.
QUIC streams are tail dropped when reset so there's no need for a more complex mechanism.
This means a relay doesn't need to parse frame/object boundaries and it can even forward STREAM frames out-of-order.</t>
      </section>
      <section anchor="datagrams">
        <name>Datagrams</name>
        <t>Datagrams are useful when payloads are small, overhead is important, and the desired latency is below the RTT.</t>
        <t>MoqTransport supports sending objects as QUIC datagrams via a publisher track preference.
This can work for real-time viewers but results in a poor experience for higher latency viewers subscribed to the same track.</t>
        <t>MoqTransfork instead lets the subscriber indicate if it wants to receive a subscription via streams or datagrams.
Datagrams should only be used when Groups are smaller than the MTU and the desired latency is smaller than the RTT.
In doing so, Groups sent via datagrams may be silently dropped for whatever reason, saving a few bytes on the wire (~10 per Group) which is desirable for audio use-cases.</t>
      </section>
      <section anchor="use-cases">
        <name>Use-Cases</name>
        <t>It's boring, but you should write down what you're trying to accomplish before you start designing a protocol especially by committee.</t>
        <t>MoqTransport is intentionally vague and doesn't mention any use-cases.
This has caused unnecessary or incomplete features, as it's impossible to argue against a feature or suggest alternatives when "some application might need it".</t>
        <t>MoqTransfork instead includes an Appendix contains a number of media use-cases and recommended approaches that are by no means required or comprehensive.
This also serves to illustrate the careful layering of Media over QUIC which has otherwise not been documented.</t>
      </section>
    </section>
    <section anchor="concepts">
      <name>Concepts</name>
      <t>Many of the concepts are borrowed from MoqTransport so I'm not going to fully rehash them here; a future draft will.</t>
      <section anchor="object-model-1">
        <name>Object Model</name>
        <t>The MoqTransfork object model consists of:</t>
        <ul spacing="normal">
          <li>
            <t><strong>Broadcast</strong>: A collection of Tracks from a single producer.</t>
          </li>
          <li>
            <t><strong>Track</strong>: A series of Groups within a Broadcast.</t>
          </li>
          <li>
            <t><strong>Group</strong>: A series of Frames within a Track, served in order.</t>
          </li>
          <li>
            <t><strong>Frame</strong>: A sized payload of bytes within a Group.</t>
          </li>
        </ul>
        <section anchor="broadcast">
          <name>Broadcast</name>
          <t>A Broadcast is a collection of tracks from a single producer, identified by a unique name within the session.</t>
          <t>Each subscription is scoped to a single Broadcast and Track within it.
A publisher may advertise available broadcasts via an ANNOUNCE message or an out-of-band mechanism.</t>
          <t>The MoqTransport draft refers to this as "track namespace".
I couldn't help but bikeshed.</t>
        </section>
        <section anchor="track">
          <name>Track</name>
          <t>A Track is a series of Groups within a Broadcast, identified by a unique name within the Broadcast.</t>
          <t>Each subscription is scoped to a single Track and starts/ends at a Group boundary.
A subscriber chooses the priority of each subscription, dictating which Track arrives first during congestion.</t>
          <t>There is currently no way to discover tracks within a broadcast; it must be negotiated out-of-band.</t>
        </section>
        <section anchor="group">
          <name>Group</name>
          <t>A Group is an ordered stream of Frames within a Track.</t>
          <t>A Group may be served via a QUIC stream or datagram, depending on the subscription.
If the Group is dropped for any reason, a subscriber may FETCH it again starting at a given byte offset.</t>
        </section>
        <section anchor="frame">
          <name>Frame</name>
          <t>A Frame is a payload of bytes within a Group.</t>
          <t>Frames currently only provides framing, hence the name.
Framing is useful in some applications but can also be redundant or increase memory usage, as the size must be known upfront.</t>
          <t>Frame will be removed in a future version of the draft and delegated to a higher layer.
However, it's useful when being compared to an Object in MoqTransport.</t>
        </section>
      </section>
      <section anchor="streams-vs-datagrams">
        <name>Streams vs Datagrams</name>
        <t>MoqTransfork supports two primary methods of transmitting data: QUIC streams and datagrams.
The difference between the two is subtle but important.</t>
        <t>Delivering a Group via a stream ensures the Group is fully delivered or explicitly dropped.
QUIC streams do not have an upfront size, allowing the Group to be transmitted in Frame chunks over time until a STREAM_FIN marker.
This is the preferred mechanism for delivering Groups as the QUIC library will automatically provide fragmentation, retransmissions, and flow control.</t>
        <t>Delivering a Group via a datagram instead means a Group will be transmitted once and can be silently dropped for any reason.
Each Group <bcp14>MUST</bcp14> have an upfront size that is smaller than network MTU, limiting them in both size and duration.
These restrictions allow the Group to be delivered with less overhead than a stream (~10 bytes per group) which is significant for some real-time use-cases.</t>
        <t>A subscriber is responsible for choosing if a subscription is served via streams or datagrams.</t>
      </section>
    </section>
    <section anchor="workflow">
      <name>Workflow</name>
      <t>This section outlines the flow of messages within a MoqTransfork session.
See the section for Messages section for the specific encoding.</t>
      <section anchor="establishment">
        <name>Establishment</name>
        <t>MoqTransfork runs on top of either WebTransport or QUIC.</t>
        <t>After a connection is established, the endpoints perform a MoqTransfork handshake to negotiate the version and other parameters.
The client opens the Session Stream and sends a SESSION_CLIENT message and the server replies with a SESSION_SERVER message.</t>
      </section>
      <section anchor="bidirectional-streams">
        <name>Bidirectional Streams</name>
        <t>Bidirectional streams are primarily used for control streams.</t>
        <t>Note that QUIC bidirectional streams have both a send and recvieve direction that can be closed or reset (with an error code) independently.
This is used to indicate completion or errors respectively.</t>
        <t>The first byte of each stream indicates the Stream Type.
Streams may only be created by the indicated role, otherwise the session <bcp14>MUST</bcp14> be closed with a ROLE_VIOLATION.</t>
        <table>
          <thead>
            <tr>
              <th align="right">Byte</th>
              <th align="left">Type</th>
              <th align="left">Role</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="right">0x0</td>
              <td align="left">Session</td>
              <td align="left">Client</td>
            </tr>
            <tr>
              <td align="right">0x1</td>
              <td align="left">Announce</td>
              <td align="left">Publisher</td>
            </tr>
            <tr>
              <td align="right">0x2</td>
              <td align="left">Subscribe (Streams)</td>
              <td align="left">Subscriber</td>
            </tr>
            <tr>
              <td align="right">0x3</td>
              <td align="left">Subscribe (Datagrams)</td>
              <td align="left">Subscriber</td>
            </tr>
            <tr>
              <td align="right">0x4</td>
              <td align="left">Fetch</td>
              <td align="left">Subscriber</td>
            </tr>
            <tr>
              <td align="right">0x5</td>
              <td align="left">Info</td>
              <td align="left">Subscriber</td>
            </tr>
          </tbody>
        </table>
        <section anchor="session">
          <name>Session</name>
          <t>The Session stream contains all messages that are session level.</t>
          <t>The client <bcp14>MUST</bcp14> open a single Session Stream immediately after establishing the QUIC/WebTransport session.
The client sends a SESSION_CLIENT message and the server replies with a SESSION_SERVER message.</t>
          <t>Afterwards, both endpoints <bcp14>MAY</bcp14> send SESSION_INFO messages containing information about the session.
The endpoint <bcp14>SHOULD</bcp14> send an updated SESSION_INFO message, such as after a significant change in the session bitrate.</t>
          <t>The session remains active until the Session Stream is closed or reset by either endpoint.</t>
        </section>
        <section anchor="announce">
          <name>Announce</name>
          <t>A publisher can open an Announce Stream to advertise a broadcast.
This is optional, as the application determine the broadcast name out-of-band.</t>
          <t>The publisher <bcp14>MUST</bcp14> start the stream with an ANNOUNCE message.
The subscriber <bcp14>MUST</bcp14> reply with an ANNOUNCE_OK message or reset the stream.
The announcement is active until the stream is closed or reset by either endpoint.</t>
          <t>There is currently no expectation that a relay will forward an ANNOUNCE message downstream.
A future draft may introduce a mechanism to discover broadcasts matching a prefix.</t>
        </section>
        <section anchor="subscribe">
          <name>Subscribe</name>
          <t>A subscriber can open a Subscribe Stream to request a named track within a broadcast.
The Stream Type indicates if the subscription is served via QUIC streams or datagrams.</t>
          <t>The SUBSCRIBE message contains a requested Broadcast and Track.
It also contains prioritization information and a range of Groups, all of which <bcp14>MAY</bcp14> be updated by the subscriber via a SUBSCRIBE_UPDATE message.
The subscription is active until the either endpoint closes or resets the stream.</t>
          <t>The subscriber <bcp14>MUST</bcp14> start a Info Stream with a SUBSCRIBE message followed by any number SUBSCRIBE_UPDATE messages.
The publisher <bcp14>MUST</bcp14> reply with an INFO message followed by any number of GROUP_DROPPED messages (streams only).
A publisher <bcp14>MAY</bcp14> reset the stream at any point if it is unable to serve the subscription.</t>
          <t><strong>When QUIC streams are used</strong>, the publisher <bcp14>MUST</bcp14> transmit a complete Group Stream or a GROUP_DROPPED message for each Group within the subscription range.
This means the publisher <bcp14>MUST</bcp14> transmit a GROUP_DROPPED if a Group Stream is reset.
The subscriber <bcp14>SHOULD</bcp14> close the subscription when all GROUP and GROUP_DROP messages have been received, and the publisher <bcp14>MAY</bcp14> close the subscription after all messages have been acknowledged.</t>
          <t><strong>When QUIC datagrams are used</strong>, the publisher <bcp14>MAY</bcp14> transmit a Group/Frame Datagram for each Group within the subscription range.
The publisher <bcp14>MUST NOT</bcp14> transmit a GROUP_DROPPED message.
The publisher <bcp14>SHOULD</bcp14> close the subscription after all Group/Frame Datagrams have been transmitted, and the subscriber <bcp14>MAY</bcp14> close the subscription after all Groups have been received.</t>
        </section>
        <section anchor="fetch">
          <name>Fetch</name>
          <t>A subscriber can open a Fetch Stream to receive a single Group at a specified offset.
This is primarily used to recover from an abrupt stream termination, causing the truncation of a Group.</t>
          <t>The subscriber <bcp14>MUST</bcp14> start a Fetch Stream with a FETCH message.
The publisher <bcp14>MUST</bcp14> reply with a GROUP message followed by the rest of a Group Stream, except starting at the specified offset.</t>
          <t>The fetch is active until both endpoints close the stream, or either endpoint resets the stream.</t>
        </section>
        <section anchor="info">
          <name>Info</name>
          <t>A subscriber can open an Info Stream to request information about a track.
This is not often necessary as SUBSCRIBE will trigger an INFO reply.</t>
          <t>The subscriber <bcp14>MUST</bcp14> start the stream with a INFO_REQUEST message.
The publisher <bcp14>MUST</bcp14> reply with an INFO message or reset the stream.
Both endpoints <bcp14>MUST</bcp14> close the stream afterwards.</t>
        </section>
      </section>
      <section anchor="unidirectional">
        <name>Unidirectional</name>
        <t>Unidirectional streams are used for subscription data.</t>
        <table>
          <thead>
            <tr>
              <th align="right">ID</th>
              <th align="left">Stream</th>
              <th align="left">Role</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="right">0x0</td>
              <td align="left">Group</td>
              <td align="left">Publisher</td>
            </tr>
          </tbody>
        </table>
        <section anchor="group-1">
          <name>Group</name>
          <t>A publisher creates Group Streams in response to a Subscribe Stream.</t>
          <t>A Group Stream <bcp14>MUST</bcp14> start with a GROUP message and <bcp14>MAY</bcp14> be followed by any number of FRAME messages.
An application <bcp14>MAY</bcp14> use zero length Group or Frames to signal gaps.</t>
          <t>Both the publisher and subscriber <bcp14>MAY</bcp14> reset the stream at any time.
When a Group stream is reset, the publisher <bcp14>MUST</bcp14> send a GROUP_DROP message on the corresponding Subscribe stream.
A future version of this draft may utilize reliable reset instead.</t>
        </section>
      </section>
      <section anchor="datagrams-1">
        <name>Datagrams</name>
        <t>Datagrams are used for subscription data.</t>
        <table>
          <thead>
            <tr>
              <th align="right">ID</th>
              <th align="left">Type</th>
              <th align="left">Role</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="right">0x0</td>
              <td align="left">Group</td>
              <td align="left">Publisher</td>
            </tr>
            <tr>
              <td align="right">0x1</td>
              <td align="left">Frame</td>
              <td align="left">Publisher</td>
            </tr>
          </tbody>
        </table>
        <section anchor="group-datagram">
          <name>Group Datagram</name>
          <t>A Group Datagram consists of a GROUP message followed by one or more FRAME messages.
These contents are identical to a Group Stream.</t>
        </section>
        <section anchor="frame-datagram">
          <name>Frame Datagram</name>
          <t>A Frame Datagram consists of a GROUP message followed by the Frame Payload.
This saves 1-2 bytes by skipping the FRAME header when there's a only single Frame, as the datagram itself contains a length.</t>
        </section>
      </section>
    </section>
    <section anchor="encoding">
      <name>Encoding</name>
      <t>This section covers the encoding of each message.</t>
      <t>Note that none of these message have a type identifier.
The message is determined by the stream type and the current state.</t>
      <section anchor="sessionclient">
        <name>SESSION_CLIENT</name>
        <t>TODO copy from moq-transport.</t>
        <t>This contains:</t>
        <ul spacing="normal">
          <li>
            <t>supported versions</t>
          </li>
          <li>
            <t>the client's role</t>
          </li>
          <li>
            <t>any extensions</t>
          </li>
        </ul>
      </section>
      <section anchor="sessionserver">
        <name>SESSION_SERVER</name>
        <t>TODO copy from moq-transport</t>
        <t>This contains:</t>
        <ul spacing="normal">
          <li>
            <t>the selected version</t>
          </li>
          <li>
            <t>the server's role</t>
          </li>
          <li>
            <t>any extensions</t>
          </li>
        </ul>
      </section>
      <section anchor="sessioninfo">
        <name>SESSION_INFO</name>
        <artwork><![CDATA[
SESSION_INFO Message {
  Session Bitrate (i)
}
]]></artwork>
        <t><strong>Session Bitrate</strong>:
The estimated bitrate of the QUIC connection in bits per second.
This <bcp14>SHOULD</bcp14> be sourced directly from the QUIC congestion controller.
A value of 0 indicates that this information is not available.</t>
      </section>
      <section anchor="announce-1">
        <name>ANNOUNCE</name>
        <t>A publisher sends an ANNOUNCE message to advertise a broadcast.</t>
        <artwork><![CDATA[
ANNOUNCE Message {
  Broadcast Name (b),
}
]]></artwork>
      </section>
      <section anchor="announceok">
        <name>ANNOUNCE_OK</name>
        <t>A subscriber replies to an ANNOUNCE with an ANNOUNCE_OK message.</t>
        <artwork><![CDATA[
ANNOUNCE_OK Message {
  Cool = 0x1
}
]]></artwork>
      </section>
      <section anchor="subscribe-1">
        <name>SUBSCRIBE</name>
        <t>SUBSCRIBE is sent by a subscriber to start a subscription.</t>
        <artwork><![CDATA[
SUBSCRIBE Message {
  Subscribe ID (i)
  Broadcast Name (b)
  Track Name (b)
  Track Priority (i)
  Group Order (i)
  Group Expires (i)
  Group Sequence Min (i)
  Group Sequence Max (i)
}
]]></artwork>
        <t><strong>Track Priority</strong>:
The transmission priority of the subscription relative to all other active subscriptions within the session.
The publisher <bcp14>SHOULD</bcp14> transmit <em>lower</em> values first during congestion.</t>
        <t><strong>Group Order</strong>:
The transmission order of the Groups within the subscription.
The publisher <bcp14>SHOULD</bcp14> transmit groups based on their sequence number in default (0), ascending (1), or descending (2) order.</t>
        <t><strong>Group Expires</strong>:
A duration in milliseconds that applies to all Groups within the subscription.
The group <bcp14>SHOULD</bcp14> be dropped if this duration has elapsed after group has finished, including any time spent cached.
A GROUP's Group Expires value <bcp14>SHOULD</bcp14> be used instead when smaller.</t>
        <t><strong>Group Sequence Min</strong>:
The minimum group sequence number plus 1.
A value of 0 indicates the latest Group Sequence as determined by the publisher.</t>
        <t><strong>Group Sequence Max</strong>:
The maximum group sequence number plus 1.
A value of 0 indicates there is no maximum and the subscription continues indefinitely.</t>
      </section>
      <section anchor="subscribeupdate">
        <name>SUBSCRIBE_UPDATE</name>
        <t>A subscriber can modify a subscription with a SUBSCRIBE_UPDATE message.</t>
        <artwork><![CDATA[
SUBSCRIBE_UPDATE Message {
  Track Priority (i)
  Group Order (i)
  Group Sequence Min (i)
  Group Sequence Max (i)
}
]]></artwork>
        <t><strong>Group Sequence Min</strong>:
The new minimum group sequence, or 0 if there is no update.
This value <bcp14>MUST NOT</bcp14> be smaller than prior SUBSCRIBE and SUBSCRIBE_UPDATE messages.</t>
        <t><strong>Group Sequence Max</strong>:
The new maximum group sequence, or 0 if there is no update.
This value <bcp14>MUST NOT</bcp14> be larger than prior SUBSCRIBE or SUBSCRIBE_UPDATE messages.</t>
      </section>
      <section anchor="info-1">
        <name>INFO</name>
        <t>The INFO message contains the current information about a track.</t>
        <artwork><![CDATA[
INFO Message {
  Latest Group (i)
  Default Track Priority (i)
  Default Group Order (i)
}
]]></artwork>
        <t><strong>Latest Group</strong>:
The latest group as currently known by the publisher.
A relay without an active subscription <bcp14>SHOULD</bcp14> forward this request upstream</t>
        <t><strong>Default Track Priority</strong>:
The default priority of this track within the broadcast.
Note that this is slightly different than SUBSCRIBE, which is scoped to a session not broadcast.
The publisher <bcp14>SHOULD</bcp14> transmit subscriptions with <em>lower</em> values first during congestion.</t>
        <t><strong>Default Group Order</strong>:
The default order of the groups within the subscription: none (0), ascending (1), or descending (2).</t>
      </section>
      <section anchor="inforequest">
        <name>INFO_REQUEST</name>
        <t>The INFO_REQUEST message is used to request an INFO response.</t>
        <artwork><![CDATA[
INFO_REQUEST Message {
  Broadcast Name (b)
  Track Name (b)
}
]]></artwork>
      </section>
      <section anchor="fetch-1">
        <name>FETCH</name>
        <t>A subscriber can request a byte offset within a Group with a FETCH message.</t>
        <artwork><![CDATA[
FETCH Message {
  Broadcast Name (b)
  Track Name (b)
  Track Priority (i)
  Group Sequence (i)
  Group Offset (i)
}
]]></artwork>
        <t><strong>Track Priority</strong>:
The priority of the group relative to all other FETCH and SUBSCRIBE requests within the session.
The publisher should transmit <em>lower</em> values first during congestion.</t>
        <t><strong>Group Offset</strong>:
The requested offset in bytes <em>after</em> the GROUP message.</t>
      </section>
      <section anchor="group-2">
        <name>GROUP</name>
        <t>The GROUP message contains information about a Group, as well as a reference to the subscription being served.</t>
        <artwork><![CDATA[
GROUP Message {
  Subscribe ID (i)
  Group Sequence (i)
  Group Expires (i)
}
]]></artwork>
        <t><strong>Group Expires</strong>:
A duration in milliseconds.
The group <bcp14>SHOULD</bcp14> be dropped if this duration has elapsed after group has finished, including any time spent cached.
The SUBSCRIBE Group Expires value <bcp14>SHOULD</bcp14> be used instead when smaller.</t>
      </section>
      <section anchor="groupdrop">
        <name>GROUP_DROP</name>
        <t>A publisher transmits a GROUP_DROP message when it is unable to serve a group for a SUBSCRIBE.</t>
        <artwork><![CDATA[
GROUP_DROP {
  Group Sequence Start (i)
  Group Sequence Count (i)
  Group Error Code (i)
}
]]></artwork>
        <t><strong>Group Sequence Start</strong>:
The sequence number for the first group within the dropped range.</t>
        <t><strong>Group Sequence Count</strong>:
The number of additional groups after the first.
This value is 0 when only one group is dropped.</t>
        <t><strong>Error Code</strong>:
An error code indicated by the application.</t>
      </section>
      <section anchor="frame-1">
        <name>FRAME</name>
        <t>The FRAME message consists of a length followed by that many bytes.</t>
        <artwork><![CDATA[
FRAME Message {
  Payload (b)
}
]]></artwork>
        <t><strong>Payload</strong>:
An application specific payload.
A generic library or relay <bcp14>MUST NOT</bcp14> inspect or modify the contents unless otherwise negotiated.</t>
      </section>
    </section>
    <section anchor="appendix-media-use-cases">
      <name>Appendix: Media Use-Cases</name>
      <t>These are some recommended ways to use MoqTransfork for media delivery.</t>
      <section anchor="video">
        <name>Video</name>
        <t>Video encoding involves complex dependencies between frames/slices.
The terminology in this section stems from H.264 but is applicable to most modern codecs.</t>
        <t>Each frame of video is encoded as one or more slices but to simplify the discussion, we'll refer to a slice as a frame.
There are three types of frames:</t>
        <ul spacing="normal">
          <li>
            <t><strong>I-Frame</strong>: A frame that can be decoded independently.</t>
          </li>
          <li>
            <t><strong>P-Frame</strong>: A frame that depends on previous frames.</t>
          </li>
          <li>
            <t><strong>B-Frame</strong>: A frame that depends on previous or future frames.</t>
          </li>
        </ul>
        <section anchor="group-of-pictures">
          <name>Group of Pictures</name>
          <t>A simple application can ignore the complexity of P/B frames and focus on I-Frames.
This is the optimal approach for many encoding configurations.</t>
          <t>Each I-Frame begins a Group of Pictures (GoP).
A GoP is a set of frames that <bcp14>MAY</bcp14> depend on each other and <bcp14>MUST NOT</bcp14> depend on other GoPs.
Each frame has a decode order (DTS) and a frame <bcp14>MUST NOT</bcp14> depend on frames with a higher DTS.</t>
          <t>This perfectly maps to a QUIC stream, as they too are independent and ordered.
The easiest way to use MoqTransfork is to send each GoP as a GROUP with each frame as a FRAME, hence the names.</t>
          <t>Given the nature of QUIC streams and GoPs, all actions are done at Group boundaries.
Each SUBSCRIBE starts at a Group to ensure that it starts with an I-Frame.
A FETCH can be used to start at a byte offset instead, assuming some of the Group has already been received.
Each Group is delivered in decode order ensuring that all frames are decodable (no artifacts).</t>
          <t>A subscriber can choose the Group Order based on the desired user experience:</t>
          <ul spacing="normal">
            <li>
              <t><tt>SUBSCRIBE order=DESC</tt>: Transmits new Groups first to allow skipping, intended for low-latency live streams.</t>
            </li>
            <li>
              <t><tt>SUBSCRIBE order=ASC</tt>: Transmits old Groups first to avoid skipping, intended for VOD and reliable live streams.</t>
            </li>
          </ul>
          <t>A publisher or subscriber can skip the remainder of a Group by resetting a Group Stream or by issuing a SUBSCRIBE_UPDATE.
This truncates the Group and a subscriber can issue a FETCH if it wants to resume at a byte offset.</t>
        </section>
        <section anchor="layers">
          <name>Layers</name>
          <t>An advanced application can subdivide a GoP into layers.</t>
          <t>The most comprehensive way to do this is with Scalable Video Coding (SVC).
There is a base layer and one or more enhancement layers that depend on lower layers.
For example, a 4K stream could be broken into 4K, 1080p, and 360p (base) layers.
However, SVC has limited support and is complex to encode.</t>
          <t>Another approach is to use temporal scalability via something like B-pyramids.
The frames within a GoP are sub-divided based on their dependencies, intentionally creating a hierarchy.
For example, even frames could be prevented from referencing odd frames, creating a base 30fps layer and an enhancement 60fps layer.
This is effectively a custom SVC scheme, however it's limited to time (can't change resolution) and the enhancement layer will be significantly smaller than the base layer.</t>
          <t>The purpose of these layers is to support degrading the quality of the broadcast.
A subscriber could limit bandwidth usage by choose to only receive the base layer or a subset of the enhancements layers.
During congestion, the base layer can be prioritized while the enhancement layers can be deprioritized/dropped.
However, the cost is a small increase in bitrate (10%) as limiting potential references can only hurt the compression ratio.</t>
          <t>When using MoqTransfork, each layer is delivered as a separate Track.
This allows the subscriber to choose which layers to receive and how to prioritize them in SUBSCRIBE.
It also enables layers to be prioritized within the layer application, for example Alice's base layer is more important than Bob's enhancement layer.</t>
          <t>The application is responsible for determining the relationship between layers, since they're unrelated tracks as MoqTransport is concerned.
The application could use a catalog to advertise the layers and how to synchronize them, for example based on the Group Sequence.</t>
        </section>
        <section anchor="non-reference-frames">
          <name>Non-Reference Frames</name>
          <t>While not explicitly stated, I believe the complexity in MoqTransport stems almost entirely from a single use-case: the ability to drop individual non-reference frames in the middle of a group.</t>
          <t>A non-reference frame cannot be referenced by other frames and is effectively a leaf node in the dependency graph.
In theory, non-reference frames can be dropped during congestion without affecting the decodability of other frames.
This idea sounds good on paper but it's a trap.</t>
          <t>Good encoders try to avoid non-reference frames because they fundamentally reduce the compression ratio; they are dead-end bits that can't be used for prediction.
You can configure the encoder to produce non-reference frames but the result is a higher bitrate for the ability to drop a small amount during congestion.
But the main problem is the complexity introduced into the transport, as each frame must be transmitted as an individual QUIC stream based on a dependency graph that is not available to relays, and difficult for both broadcasters and viewers to parse.</t>
          <t>The ability to drop individual non-reference frames in the middle of a group is an explicit non-goal for MoqTransfork.
An alternative is to put them into a separate layer, such that the tail of the layer could be dropped.</t>
        </section>
      </section>
      <section anchor="audio">
        <name>Audio</name>
        <t>Unlike video, audio is simple and yet has perhaps more potential for optimization.</t>
        <section anchor="frames">
          <name>Frames</name>
          <t>Audio samples are very small and for the sake of compression, are grouped into a frame.
This depends on the codec and the sample rate but each frame is typically 10-50ms of audio.</t>
          <t>Audio frames are independent and ordered, again making them a good fit for QUIC streams.
Each audio frame can be transmitted as a GROUP with a single FRAME.</t>
        </section>
        <section anchor="groups">
          <name>Groups</name>
          <t>It may also be desirable to group audio frames into larger units.</t>
          <t>For example, if an application wants reliable playback and A/V synchronization, then audio and video could be aligned.
An application could then subscribe to video and audio starting at group X for both tracks, instead of trying to maintain a mapping between the two based on timestamp.
This is quite common in HLS/DASH as there's no reason to subdivide audio segments at frame boundaries.</t>
          <t>This can be accomplished with MoqTransfork by using multiple audio FRAMEs within a GROUP.
This limits the ability to drop individual audio frames during congestion (tail drop only) but that's up to the application.</t>
        </section>
        <section anchor="fec">
          <name>FEC</name>
          <t>Real-time audio applications often use Forward Error Correction (FEC) to conceal packet loss.
Audio frames are a good candidate for FEC given that they are small and independent.</t>
          <t>In an ideal world, FEC would be performed by QUIC based on the properties of the hop.
However this is not currently not supported and FEC is left to the application.</t>
          <t>In MoqTransfork, each FEC packet is transmitted as a separate GROUP with a single FRAME.
A real-time subscriber issues a <tt>SUBSCRIBE</tt> with an aggressive <tt>Group Expires</tt> value in the milliseconds range.
The publisher will drop any Groups that have not been transmitted or acknowledged within this time frame, potentially causing them to be lost.</t>
          <t>The subscriber can choose if it wants to use datagrams or streams for a subscription.
I recommend using streams if the RTT is smaller than <tt>Group Expires</tt>, as it gives retransmissions a chance even when FEC is used.</t>
        </section>
      </section>
      <section anchor="metadata">
        <name>Metadata</name>
        <t>There's a number of non-media use cases that can be served by MoqTransfork.</t>
        <section anchor="catalog">
          <name>Catalog</name>
          <t>Originally part of the transport itself, the catalog is a list of all tracks within a broadcast.
It's since been delegated to the application and is now just another track with a well-known name.</t>
          <t>The proposed MoQ catalog format supports live updates.
It does this by encoding a base JSON blob and then applying JSON patches over time.
If the number of deltas becomes too large, the producer can start over with a new base JSON blob.</t>
          <t>In MoqTransfork, the base and all deltas are a single GROUP.
The base is the first FRAME and all deltas are subsequent FRAMEs.
The producer can create a new GROUP to start over, repeating the process.</t>
        </section>
        <section anchor="timeline">
          <name>Timeline</name>
          <t>Another track that is commonly pitched is a timeline track.
This records the presentation timestamp of each Group, giving a VOD viewer to seek to a specific time.</t>
          <t>The <tt>timeline</tt> track is a single Group containing a Frame for each timestamp.
The live nature of the timeline track is great for DVR applications while being concise enough for VOD.
Timed metadata would use a similar approach or perhaps leverage this track.</t>
        </section>
        <section anchor="interaction">
          <name>Interaction</name>
          <t>Another common use-case is to transmit user interactions, such as controller inputs or chat messages.
It's up to the application to determine the format and encoding of these messages.</t>
          <t>Let's take controller input as an example.
The application needs to determine its loss vs latency tolerance, as reordering or dropping inputs will lead to a poor user experience.</t>
          <ul spacing="normal">
            <li>
              <t>If you don't want loss, then use a single GROUP with a FRAME per input.</t>
            </li>
            <li>
              <t>If you don't want latency, then use a GROUP per input with a single FRAME.</t>
            </li>
            <li>
              <t>If you want a hybrid, then use form of clustering inputs into GROUPs and FRAMEs based on time.</t>
            </li>
          </ul>
          <t>A publisher could monitor the session RTT or stream acknowledgements to get a sense of the latency and create Groups accordingly.
However, this only applies to the first hop and won't be applicable when relays are involved.</t>
        </section>
      </section>
      <section anchor="latency">
        <name>Latency</name>
        <t>One explicit goal of MoqTransfork is to support multiple latency targets.</t>
        <t>This is accomplished by using the same Tracks and Group for all viewers, but slightly changing the behavior based on the subscription.
This is driven by the subscriber, allowing them to choose the trade-off between latency and reliability.
This may be done on the fly via SUBSCRIBE_UPDATE, for example if a high-latency viewer wishes to join the stage and suddenly needs real-time latency.</t>
        <t>The below examples assume one audio and one video track.
See the next section for more complicated broadcasts.</t>
        <section anchor="real-time">
          <name>Real-Time</name>
          <t>Real-time latency is accomplished by prioritizing the most important media during congestion and skipping the rest.</t>
          <t>This is slightly different from other media protocols which instead opt to drop packets.
The end result is similar, but prioritization means utilizing all available bandwidth as determined by the congestion controller.
A subscriber or publisher can reset groups to avoid wasting bandwidth on old data.</t>
          <t>A real-time viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=DESC group_expires=100ms
SUBSCRIBE track=video priority=1 order=DESC group_expires=100ms
]]></artwork>
          <t>In this example, audio is higher priority than video, and newer groups are higher priority than older groups.
Suppose a viewer fell behind after a burst of congestion and has to decide which groups to deliver next.
This configuration would result in the transmission order:</t>
          <artwork><![CDATA[
GROUP track=audio sequence=102
GROUP track=audio sequence=101
GROUP track=audio sequence=100
GROUP track=video sequence=5
GROUP track=video sequence=4
]]></artwork>
          <t>The user experience depends on the amount of congestion:</t>
          <ul spacing="normal">
            <li>
              <t>If there's no congestion, all audio and video is delivered.</t>
            </li>
            <li>
              <t>If there's moderate congestion, the tail of the old video group is dropped.</t>
            </li>
            <li>
              <t>If there's severe congestion, all video will be late/dropped and some audio groups/frames will be dropped.</t>
            </li>
          </ul>
          <t>The value of <tt>group_expires</tt> is optional.
In this example it means that the publisher automatically resets each group 100ms after they are no longer the latest.
It's recommended to use the maximum jitter buffer size.</t>
        </section>
        <section anchor="unreliable-live">
          <name>Unreliable Live</name>
          <t>Unreliable live is a term I made up.
Basically we want low latency, but we don't need it at all costs and we're willing to skip some video to achieve it.
This is useful for broadcasts where latency is important but so is picture quality.</t>
          <t>An unreliable live viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=ASC
SUBSCRIBE track=video priority=1 order=DESC group_expires=3s
]]></artwork>
          <t>This example is different from the real-time one in that audio is fully reliable and delivered in order.
Of course this is optional and up to the application, as it will result in buffering during significant congestion.
If the viewer goes through a tunnel and then comes back online, they won't miss any audio.</t>
          <t>A key difference is that our jitter buffer is much larger for video, 3s in this example.
The player will tolerate up to 3s of latency before it starts skipping past video frames.
Note that the <tt>group_expires</tt> value can be increased during buffering by issuing a SUBSCRIBE_UPDATE.</t>
        </section>
        <section anchor="reliable-live">
          <name>Reliable Live</name>
          <t>Reliable live is another term I made up.
This is when we have a live stream but primarily care about picture quality.
A good example is a sports game where you want to see every frame.</t>
          <t>A reliable live viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=ASC
SUBSCRIBE track=video priority=0 order=ASC
]]></artwork>
          <t>This will deliver both audio and video in order, and with the same priority.
The viewer won't miss any content unless the publisher resets a group.
However, this can result in buffering during congestion and provides a similar user experience to HLS/DASH.</t>
        </section>
        <section anchor="vod-dvr">
          <name>VOD / DVR</name>
          <t>Video on Demand (VOD) and Digital Video Recorder (DVR) both involve seeking backwards in a live stream.
MoqTransfork can serve this use-case too, don't worry.</t>
          <t>A VOD viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=ASC start=345 end=396
SUBSCRIBE track=video priority=0 order=ASC start=123 end=134
]]></artwork>
          <t>The application is responsible for determining the group sequence numbers based on the desired timestamp.
This could be done via a <tt>timeline</tt> track or out-of-band.</t>
          <t>A subscriber will need a specific <tt>end</tt> or else it will download too much data at once, as old media is transmitted at network speed and not encode speed.
It will need to issue an updated SUBSCRIBE to expand the range as playback continues and the buffer depletes.
A subscriber could use SUBSCRIBE_UPDATE, however there are race conditions involved.</t>
          <t>A DVR player does the same thing but can automatically support joining the live stream.
It's perfectly valid to specify a <tt>end</tt> in the future and it will behave like reliable live viewer once it reaches the live playhead.</t>
          <t>Alternatively, a DVR player could prefetch the live playhead by issuing a parallel SUBSCRIBE at a lower priority.
This would allow playback to immediately continue after clicking the "Go Live" button, canceling or deprioritizing the VOD subscription.</t>
          <artwork><![CDATA[
SUBSCRIBE track=video priority=0 order=ASC start=123 end=134
SUBSCRIBE track=video priority=1 order=DESC
]]></artwork>
        </section>
        <section anchor="upstream">
          <name>Upstream</name>
          <t>All of these separate viewers could be watching the same broadcast.
How is a relay supposed to fetch the content from upstream?</t>
          <t>MoqTransfork addresses this by providing a Default Track Priority and Default Group Order in the INFO message.
This is the intended behavior for the first hop and dictates which viewers are preferred.</t>
          <t>For example, suppose the producer chooses:</t>
          <artwork><![CDATA[
INFO track=audio default_priority=0 default_order=DESC
INFO track=video default_priority=1 default_order=DESC
]]></artwork>
          <t>If Alice is watching a VOD and issues:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=ASC
SUBSCRIBE track=video priority=0 order=ASC
]]></artwork>
          <t>If Bob is watching real-time and issues:</t>
          <artwork><![CDATA[
SUBSCRIBE track=audio priority=0 order=DESC
SUBSCRIBE track=video priority=1 order=DESC
]]></artwork>
          <t>For any congestion on the first mile, then the relay will improve Bob's experience by following the producer's preference.
However any congestion on the last mile will always use the viewer's preference.</t>
          <t>A relay should use the default priority/order only when there's a conflict.
If viewers have the same priority/order, then the relay should use the viewer's preference and it can always issue a SUBSCRIBE_UPDATE when this changes.</t>
        </section>
      </section>
      <section anchor="broadcast-1">
        <name>Broadcast</name>
        <t>A broadcast is a collection of tracks from a single producer.
This usually includes an audio track and/or a video track, but there are reasons to have more than that.</t>
        <section anchor="abr">
          <name>ABR</name>
          <t>Virtually all mass fanout use-cases rely on Adaptive Bitrate (ABR) streaming.
The idea is to encode the same content at multiple bitrates and resolutions, allowing the viewer to choose based on their unique situation.</t>
          <t>MoqTransfork unsurprisingly supports this via multiple Tracks, but relies on the application to determine the relationship between them.
This is often done via a <tt>catalog</tt> track that details each track's name, bitrate, resolution, and codec.
This includes how a group in one track corresponds to a group in another track.
A common approach is to use the same Group Sequence number for all tracks, or perhaps utilize a <tt>timeline</tt> track to map between Group Sequences and presentation timestamps.</t>
          <t>The viewer may limit the available tracks based on capabilities or preferences.
For example, the device may not support the 4K track since it uses AV1, or the screen size may be too small to justify the bandwidth.
This is easy enough to support; just ignore these tracks in the catalog.</t>
          <t>The primary reason to use ABR is to adapt to changing network conditions.
The viewer learns about the estimated bandwidth via the SESSION_INFO message, or by measuring network traffic and can then choose the appropriate track based on bitrate.</t>
          <t>Transitioning between tracks can be done seamlessly by utilizing prioritization.
For example, suppose a viewer is watching the 360p track and wants to switch to 1080p at group 69.</t>
          <t>A real-time or unreliable live viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE_UPDATE track=360p  priority=1 order=DESC end=69
SUBSCRIBE        track=1080p priority=0 order=DESC start=69
]]></artwork>
          <t>A reliable live or VOD viewer could issue:</t>
          <artwork><![CDATA[
SUBSCRIBE_UPDATE track=360p  priority=0 order=ASC end=69
SUBSCRIBE        track=1080p priority=1 order=ASC start=69
]]></artwork>
          <t>The difference between them is whether to prioritize the old track or the new track.
In both scenarios, the subscription will seamlessly switch at group 69 even if it's seconds in the future.
The same behavior can be used to switch down.</t>
        </section>
        <section anchor="svc">
          <name>SVC</name>
          <t>We touched on SVC before, but it's worth mentioning as an alternative to ABR.
I want to see it used more often but I doubt it will be.</t>
          <t>Instead of choosing the track based on the bitrate, the viewer subscribes to them all:</t>
          <artwork><![CDATA[
SUBSCRIBE track=360p  priority=0 order=DESC
SUBSCRIBE track=1080p priority=1 order=DESC
SUBSCRIBE track=4k    priority=2 order=DESC
]]></artwork>
          <t>During congestion, the 4k enhancement layer will be deprioritized followed by the 1080p enhancement layer.
This is a more efficient use of bandwidth than ABR, but it requires more complex encoding.</t>
        </section>
      </section>
      <section anchor="conferences">
        <name>Conferences</name>
        <t>Some applications involve multiple producers, such as a conference calls or a live events.
Even though these are separate broadcasts from potentially separate origins, MoqTransfork can still serve them over the same session.</t>
        <section anchor="discovery">
          <name>Discovery</name>
          <t>The first step to joining a conference is to discover the available broadcasts.</t>
          <t>There is currently no discovery mechanism in MoqTransfork.
However, an application can build one on top of a MoqTransfork track (of course!).</t>
          <t>For example, suppose we have a conference room called <tt>room.12345</tt>.
An index service could produce a <tt>room.12345</tt> track that lists all broadcasts within the room.
When Alice joins and ANNOUNCES <tt>room.12345.alice</tt>, the index service could update the <tt>room.12345</tt> track to add a new FRAME <tt>+alice</tt>.
The same can be done to remove her when she leaves.</t>
        </section>
        <section anchor="participants">
          <name>Participants</name>
          <t>Extending the idea that audio is more important than video, we can prioritize tracks regardless of the source.
This works because <tt>SUBSCRIBE priority</tt> is scoped to the session and not the broadcast.</t>
          <artwork><![CDATA[
SUBSCRIBE track=alice.audio priority=1
SUBSCRIBE track=frank.audio priority=1
SUBSCRIBE track=alice.video priority=3
SUBSCRIBE track=frank.video priority=3
]]></artwork>
          <t>When Alice starts talking or is focused, we can actually issue a SUBSCRIBE_UPDATE to increase her priority:</t>
          <artwork><![CDATA[
SUBSCRIBE_UPDATE track=alice.audio priority=0
SUBSCRIBE_UPDATE track=alice.video priority=2
]]></artwork>
          <t>Note that audio is still more important than video, but Alice is now more important than Frank. (poor Frank)</t>
          <t>This concept can further be extended to work with SVC or ABR:</t>
          <artwork><![CDATA[
SUBSCRIBE track=alice.360p priority=1
SUBSCRIBE track=frank.360p priority=2
SUBSCRIBE track=alice.720p priority=3
SUBSCRIBE track=frank.720p priority=4
]]></artwork>
        </section>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>TODO Security</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="moqt">
        <front>
          <title>Media over QUIC Transport</title>
          <author fullname="Luke Curley" initials="L." surname="Curley">
            <organization>Discord</organization>
          </author>
          <author fullname="Kirill Pugin" initials="K." surname="Pugin">
            <organization>Meta</organization>
          </author>
          <author fullname="Suhas Nandakumar" initials="S." surname="Nandakumar">
            <organization>Cisco</organization>
          </author>
          <author fullname="Victor Vasiliev" initials="V." surname="Vasiliev">
            <organization>Google</organization>
          </author>
          <author fullname="Ian Swett" initials="I." surname="Swett">
            <organization>Google</organization>
          </author>
          <date day="4" month="March" year="2024"/>
          <abstract>
            <t>   This document defines the core behavior for Media over QUIC Transport
   (MOQT), a media transport protocol designed to operate over QUIC and
   WebTransport, which have similar functionality.  MOQT allows a
   producer of media to publish data and have it consumed via
   subscription by a multiplicity of endpoints.  It supports
   intermediate content distribution networks and is designed for high
   scale and low latency distribution.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-moq-transport-03"/>
      </reference>
      <reference anchor="RFC2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
          <abstract>
            <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
          <abstract>
            <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
    </references>
    <?line 968?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA8V963bbVpLufz4Fxlln2fKhZMl2Mt3KZHpoSU40bVseSXam
16xZFkSAJNogwACgZHan+1nmWc6TnaqvqvYFhBQ7OTMnP7otAtiXqtp1r9q7
u7ujrujK/DB58DrPijSpb/Im+bd3p0fJbnLZpFU7q5uPD0bp9XWT39Bby/qn
bvZgNE27fF43m8OkqGb1aJTV0ypd0jBZk8663XK6bsp8s0tv73Y2yu7+/qhd
Xy+Lti3qqtus6PXTk8uXSfJVkpZtTaMXVZavcvqfqnswTh7Qirq6KdKS/zid
vKD/qxv61/nlywejar28zpvDUUZLORzR2p6N0iZPD5Pbohvd0nzzpl6vDhNa
w2iUrrtFTS8nu6OE/puty1LW+2r9MU+OsFo8qZt5WhV/STta4mFyXLTTusnw
JF+mRXmYfCw+5SVNmf3LnH/Ym9bL0aiqmyV9ckMLSXjCjna2e7xX5N3Mw2BV
N91oxPByL492d3eT9Lql51N6dnl2fJZM3J94uiyyrMxHo6+So7q6IcDQwtok
rbLkOJ8VVYG/R5eLPPmYbxLad9YSLt9dXDLM+P+TN2f49/kJofX85Jj/ffHD
5NUr94+RvnHxw9m7V8f+X/7Lo7PXr0/eHMvH9GsS/TR68HryJ3rCi3pw9vby
9OzN5NUDooykWxRtQrSxXtLCE0JP0tXJdU6PurxZNTmBMUnbUZa306a4pj/o
mxdHb//Pfx08T/761384f3n09ODg93/7m/7xu4N/fE5/3C7ySmarq3Kjf3YL
wmC6WuVpw6OkZZlM01XREWXRu23SLurbKlnkTb43Gj3+D4bMfx4m/3Q9XR08
/2f9gTcc/Wgwi34EzLZ/2fpYgDjw08A0DprR7z1Ix+ud/Cn62+Ae/PhPfyiL
Kk92D373h38maiISeknHgmiFkcLnNKF/XKdtzoBMIjrd3X+W/AcT8n/ugbam
dTXNVx2BclkT6eJ4tIIDwuSyqOqynm+AYWIgm6QtlkVJmKBxV+tmVbcE9R8J
T4yarF5fd+OkyWfEaogeCHN07Ip5UaWlrIswdMrHoi7XXU4Yvs7LIr/JhaLy
YAlYwKru+FjQx/Us6XExWX2ZbvKmqOa83xWtoiZypNf54zTLmrxt8zZZptWG
R+AZVk19XebLlnnJIiFm1jD9lnRmkyUmoBe6elqX7R6tlLkJbXm9Ysjh+3lN
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

-->

</rfc>
