<?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.29 (Ruby 3.4.4) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-lcurley-moq-hang-00" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.30.0 -->
  <front>
    <title abbrev="hang">Media over QUIC - Hang</title>
    <seriesInfo name="Internet-Draft" value="draft-lcurley-moq-hang-00"/>
    <author fullname="Luke Curley">
      <organization/>
      <address>
        <email>kixelated@gmail.com</email>
      </address>
    </author>
    <date year="2025" month="July" day="22"/>
    <area>wit</area>
    <workgroup>moq</workgroup>
    <abstract>
      <?line 26?>

<t>Hang is a real-time conferencing protocol built on top of moq-lite.
A room consists of multiple participants who publish media tracks.
All updates are live, such as a change in participants or media tracks.</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-drafts"/>.</t>
    </note>
  </front>
  <middle>
    <?line 32?>

<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="terminology">
      <name>Terminology</name>
      <t>Hang is built on top of moq-lite <xref target="moql"/> and uses much of the same terminology.
A quick recap:</t>
      <ul spacing="normal">
        <li>
          <t><strong>Broadcast</strong>: A collection of Tracks from a single publisher.</t>
        </li>
        <li>
          <t><strong>Track</strong>: An series of Groups, each of which can be delivered and decoded <em>out-of-order</em>.</t>
        </li>
        <li>
          <t><strong>Group</strong>: An series of Frames, each of which must be delivered and decoded <em>in-order</em>.</t>
        </li>
        <li>
          <t><strong>Frame</strong>: A sized payload of bytes representing a single moment in time.</t>
        </li>
      </ul>
      <t>Hang introduces additional terminology:</t>
      <ul spacing="normal">
        <li>
          <t><strong>Room</strong>: A collection of participants, publishing under a common prefix.</t>
        </li>
        <li>
          <t><strong>Participant</strong>: A moq-lite broadcaster that may produce any number of media tracks.</t>
        </li>
        <li>
          <t><strong>Catalog</strong>: A JSON document that describes each available media track, supporting live updates.</t>
        </li>
        <li>
          <t><strong>Container</strong>: A tiny header in front of each media payload containing the timestamp.</t>
        </li>
      </ul>
    </section>
    <section anchor="discovery">
      <name>Discovery</name>
      <t>The first requirement for a real-time conferencing application is to discover other participants in the same room.
Hang does this using moq-lite's ANNOUNCE capabilities.</t>
      <t>A room consists of a path.
Any participants within the room <bcp14>MUST</bcp14> publish a broadcast with the room path as a prefix and it <bcp14>SHOULD</bcp14> end with the <tt>.hang</tt> suffix.</t>
      <t>For example:</t>
      <artwork><![CDATA[
/room/alice.hang
/room/bob.hang
/other/zoe.hang
]]></artwork>
      <t>A participant issues an ANNOUNCE_PLEASE message to discover any other participants in the same room.
The server (relay) will then respond with an ANNOUNCE message for any matching broadcasts, including their own.</t>
      <t>For example:</t>
      <artwork><![CDATA[
ANNOUNCE_PLEASE prefix=/room/
ANNOUNCE suffix=alice.hang active=true
ANNOUNCE suffix=bob.hang   active=true
]]></artwork>
      <t>If a publisher no longer wants to participant, or is disconnected somehow, their presence will be unannounced.
Publishers and subscribers <bcp14>SHOULD</bcp14> terminate any subscriptions once a participant is unannounced.</t>
      <artwork><![CDATA[
ANNOUNCE suffix=alice.hang active=false
]]></artwork>
    </section>
    <section anchor="catalog">
      <name>Catalog</name>
      <t>The catalog describes the available media tracks for a single participant.
It's a JSON document that extends the the W3C WebCodecs specification.</t>
      <t>The catalog is published as a <tt>catalog.json</tt> track within the broadcast so it can be updated live as the participant's media tracks change.
A participant <bcp14>MAY</bcp14> forgo publishing a catalog if it does not wish to publish any media tracks now and in the future.</t>
      <t>The catalog track consists of multiple groups, one for each update.
Each group contains a single frame with UTF-8 JSON.
A publisher <bcp14>MUST NOT</bcp14> write multiple frames to a group until a future specification includes a delta-encoding mechanism.</t>
      <section anchor="root">
        <name>Root</name>
        <t>The root of the catalog is a JSON document with the following schema:</t>
        <artwork><![CDATA[
type Catalog = {
        "audio": AudioTrack[],
        "video": VideoTrack[],
}
]]></artwork>
        <t>When there are multiple audio or video tracks, they <bcp14>SHOULD</bcp14> describe the same content.
For example, different resolutions, codecs, bitrates, etc.
If a participant wants to publish unrelated content, for example sharing the screen in addition to a webcam, it <bcp14>SHOULD</bcp14> publish a separate broadcast (and catalog).</t>
        <t>Additional fields <bcp14>MAY</bcp14> be added based on the application.
The catalog <bcp14>SHOULD</bcp14> be mostly static, delegating any dynamic content to other tracks.
Additionally, a catalog <bcp14>SHOULD</bcp14> describe optional content, allowing the client to decide if it wants to subscribe.</t>
        <t>For example, a <tt>"chat"</tt> field should include the name of a chat track, not individual chat messages.
This way catalog updates are rare and a client <bcp14>MAY</bcp14> choose to not subscribe.</t>
      </section>
      <section anchor="video">
        <name>Video</name>
        <t>A video track contains the necessary information to decode a video stream.</t>
        <t>Hang uses the <eref target="https://www.w3.org/TR/webcodecs/#video-decoder-config">VideoDecoderConfig</eref>.
Any Uint8Array fields are hex-encoded into a string.</t>
        <t>The <tt>track</tt> field includes the name and priority of the track within the broadcast.</t>
        <artwork><![CDATA[
type VideoTrack = {
        "track": {
                "name": string,
                "priority": number,
        },
        "config": VideoDecoderConfig,
}
]]></artwork>
        <t>For example:</t>
        <artwork><![CDATA[
{
        "track": {
                "name": "video",
                "priority": 2
        },
        "config": {
                "codec": "avc1.64001f",
                "codedWidth": 1280,
                "codedHeight": 720,
                "bitrate": 6000000,
                "framerate": 30.0
        }
}
]]></artwork>
      </section>
      <section anchor="audio">
        <name>Audio</name>
        <t>An audio track contains the necessary information to decode an audio stream.</t>
        <t>The <tt>track</tt> field includes the name and priority of the track within the broadcast.</t>
        <t>The <tt>config</tt> field contains an <eref target="https://www.w3.org/TR/webcodecs/#audio-decoder-config">AudioDecoderConfig</eref>.
Any Uint8Array fields are hex-encoded into a string.</t>
        <artwork><![CDATA[
type AudioTrack = {
        "track": {
                "name": string,
                "priority": number,
        },
        "config": AudioDecoderConfig,
}
]]></artwork>
        <t>For example:</t>
        <artwork><![CDATA[
{
        "track": {
                "name": "audio",
                "priority": 1
        },
        "config": {
                "codec": "opus",
                "sampleRate": 48000,
                "numberOfChannels": 2,
                "bitrate": 128000
        }
}
]]></artwork>
      </section>
    </section>
    <section anchor="media">
      <name>Media</name>
      <t>Media tracks are split into groups and further into frames.</t>
      <t>A group consists of one or more frames in decode order.
Each group <bcp14>MUST</bcp14> start with a keyframe.
If a codec supports delta frames (video), then all subsequent frames <bcp14>MUST</bcp14> be delta frames.
Otherwise, a group <bcp14>MAY</bcp14> consist of multiple keyframes (audio).</t>
      <t>Each "frame" consists of a tiny "container" containing the timestamp and codec specific payload.
The timestamp is the presentation timestamp in microseconds encoded as a QUIC variable-length integer (62-bit max).
The remainder of the frame payload is codec specific.</t>
    </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="moql">
        <front>
          <title>*** BROKEN REFERENCE ***</title>
          <author>
            <organization/>
          </author>
          <date/>
        </front>
      </reference>
      <reference anchor="moqt">
        <front>
          <title>Media over QUIC Transport</title>
          <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>
          <author fullname="Alan Frindell" initials="A." surname="Frindell">
            <organization>Meta</organization>
          </author>
          <date day="7" month="July" year="2025"/>
          <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-13"/>
      </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 232?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
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

-->

</rfc>
