<?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-01" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.31.0 -->
  <front>
    <title abbrev="hang">Media over QUIC - Hang</title>
    <seriesInfo name="Internet-Draft" value="draft-lcurley-moq-hang-01"/>
    <author fullname="Luke Curley">
      <organization/>
      <address>
        <email>kixelated@gmail.com</email>
      </address>
    </author>
    <date year="2025" month="November" day="12"/>
    <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 which <bcp14>SHOULD</bcp14> end with the <tt>.hang</tt> suffix.</t>
      <t>For example:</t>
      <artwork><![CDATA[
/room123/alice.hang
/room123/bob.hang
/room456/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.</t>
      <t>A publisher <bcp14>MUST NOT</bcp14> write multiple frames to a group until a future specification includes a delta-encoding mechanism (via JSON Patch most likely).</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": AudioSchema | undefined,
        "video": VideoSchema | undefined,
        // ... any custom fields ...
}
]]></artwork>
        <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.</t>
        <t>For example, a <tt>"chat"</tt> section 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>
        <t>This specification currently only defines audio and video tracks.</t>
      </section>
      <section anchor="video">
        <name>Video</name>
        <t>A video track contains the necessary information to decode a video stream.</t>
        <artwork><![CDATA[
type VideoSchema = {
        "renditions": Map<TrackName, VideoDecoderConfig>,
        "priority": u8,
        "display": {
                "width": number,
                "height": number,
        } | undefined,
        "rotation": number | undefined,
        "flip": boolean | undefined,
}
]]></artwork>
        <t>The <tt>renditions</tt> field contains a map of track names to video decoder configurations.
See the <eref target="https://www.w3.org/TR/webcodecs/#video-decoder-config">WebCodecs specification</eref> for specifics and registered codecs.
Any Uint8Array fields are hex-encoded as a string.</t>
        <t>For example:</t>
        <artwork><![CDATA[
{
        "renditions": {
                "720p": {
                        "codec": "avc1.64001f",
                        "codedWidth": 1280,
                        "codedHeight": 720,
                        "bitrate": 6000000,
                        "framerate": 30.0
                },
                "480p": {
                        "codec": "avc1.64001e",
                        "codedWidth": 848,
                        "codedHeight": 480,
                        "bitrate": 2000000,
                        "framerate": 30.0
                }
        },
        "priority": 2,
        "display": {
                "width": 1280,
                "height": 720
        },
        "rotation": 0,
        "flip": false,
}
]]></artwork>
      </section>
      <section anchor="audio">
        <name>Audio</name>
        <t>An audio track contains the necessary information to decode an audio stream.</t>
        <artwork><![CDATA[
type AudioSchema = {
        "renditions": Map<TrackName, AudioDecoderConfig>,
        "priority": u8,
}
]]></artwork>
        <t>The <tt>renditions</tt> field contains a map of track names to audio decoder configurations.
See the <eref target="https://www.w3.org/TR/webcodecs/#audio-decoder-config">WebCodecs specification</eref> for specifics and registered codecs.
Any Uint8Array fields are hex-encoded as a string.</t>
        <t>For example:</t>
        <artwork><![CDATA[
{
        "renditions": {
                "stereo": {
                        "codec": "opus",
                        "sampleRate": 48000,
                        "numberOfChannels": 2,
                        "bitrate": 128000
                },
                "mono": {
                        "codec": "opus",
                        "sampleRate": 48000,
                        "numberOfChannels": 1,
                        "bitrate": 64000
                }
        },
        "priority": 1,
}
]]></artwork>
      </section>
    </section>
    <section anchor="container">
      <name>Container</name>
      <t>Audio and video tracks use a lightweight container to encapsulate the media payload.</t>
      <t>Each moq-lite group <bcp14>MUST</bcp14> start with a keyframe.
If codec does not support delta frames (ex. audio), then a group <bcp14>MAY</bcp14> consist of multiple keyframes.
Otherwise, a group <bcp14>MUST</bcp14> consist of a single keyframe followed by zero or more delta frames.</t>
      <t>Each frame starts with a timestamp, a QUIC variable-length integer (62-bit max) encoded in microseconds.
The remainder of the payload is codec specific; see the WebCodecs specification for specifics.</t>
      <t>For example, h.264 with no <tt>description</tt> field would be annex.b encoded, while h.264 with a <tt>description</tt> field would be AVCC encoded.</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>Media over QUIC - Lite</title>
          <author fullname="Luke Curley" initials="L." surname="Curley">
         </author>
          <date day="22" month="July" year="2025"/>
          <abstract>
            <t>   moq-lite is designed to fanout live content from publishers to any
   number of subscribers across the internet.  Liveliness is achieved by
   using QUIC to prioritize the most important content, potentially
   starving or dropping other content, to avoid head-of-line blocking
   while respecting encoding dependencies.  While designed for media, it
   is an agnostic transport, allowing relays and CDNs to forward content
   without knowledge of codecs, containers, or encryption keys.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-lcurley-moq-lite-01"/>
      </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="20" month="October" 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-15"/>
      </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 247?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9VZ/1IbyRH+f59iIv9xNoUEwsRHyNkXnYCYlA0O4Lu6crnC
aHckTVjt7M3MImTH9yx5ljxZvu7ZnyA4ckmqEqpsaXd7enq6+/u6e9Xv9yOv
far2Re+tSrQU5lpZ8ef3x2PRF69lNutFcjKx6hoCc76MpVczY1f7QmdTE0WJ
iTO5gILEyqnvp3FhU7XqL8xPfVrQ3x5GrpgstHPaZH6VQ/L48OJIiCdCps5A
r84SlSv8l/nepujBDG+slildHI++w4ex+HZ2cdSLsmIxUXY/SmDFfgSrnkfS
KrkvltpHS2OvZtYU+b7A9lEkCz83EBb9SOBvWqRpMPVNcaXEmA3lJ2ohdbov
rvSNSqE4+cOMbgxis4iizNiF9Poa2wlSC7nj/sGgfc5UexUe+vBQKz/lJ97K
zOXGejxeqklsEhW7ffGDmoz5axSRE+sNon6/L+TEYVnso4j8L7QTUuCIad/r
hRKxyabKqizWeJZb401sUjEpdOqFyYQ3uTBTUVk1iEbCGrOgZU477/hhkXqd
p0rk0nod61xmeLCcG5EXk1S7uVhwKpAVVw4q0lQUOXkcplglUti6KVwRz4Uk
42KKs0I6dBUiaF09fLqFTpJURdETMTbZNUKOrICSLBEHaqozzdfRxVyJK7US
iGjikJrvzy8oG+hTnJzy97NDZOnZ4QF9P389evOm/hKVEuevT9+/OWi+NSvH
p2/fHp4chMW4Kzq3ot7b0Y94Qkb1Tt9dHJ+ejN706Hx+jmgg4YsFDGdfeCMm
dHSvbG4VUgcuiRLlYqsnuMCa78bv/vH34a74/Pk3Z0fjneHwd1++lBd7w693
cbGcqyzsZrJ0VV76OXJT5rmSlrRIxCCWufbAzCa53c3NMhNzpAIcu/GBPPNx
X3wzifPh7qvyBh24c7PyWecm++zunTuLgxPX3FqzTe3Nzv1bnu7aO/qxc135
vXXzm29TnSnRH+59+yqKKIUulF3ozKRmtqrBch8UxAcC70f2c+GQygtKYAjA
08KBFoRvtBFufip0fAXkwe2ETLGx8Z01Moml8xsb+2IETKWpiilhSc0FZ7mY
WqBNCgd4EsICoJQdsAKW4cWZcMpqxXj8I1EWoqpkMGg51/gSy4xSK1EEN0uJ
BcPBGeCNRGyYwvfNtA94KLsRlLOaO8qPLI52R/micP4B7TrraGYd4cxOf4JA
LlcpXEH6JiuiBauQ/Y7QjCDUp18YxgkBB9Q1qAgt89YkRUxskiQMeJm2nV96
+wy8tc7RbZLZrDxM+xYoIZb4yCwWEIVFU30TTvCuWRNU1lkxqWKKpX4uvVjI
FfEqGQinrESoOJxJHTYjtWMJPJpZUPmn89OThhxYV0UELrhfXqOqyAl5plFF
TJpTiaAjUDQqri23QNGUSHsbNoHUCqiXdFL4FdmGvWAb6w9aq+DEYSWppRSn
EDgvF/mAoXOgXUy1fsVcO9UWCWEVct4qth9V6f66A15KNRoBigggBxJMSnXC
YC/bLQRMnCXGqBgNQh4kBn5hRi0oX+qQfOXE6OTk9P3J+JAoT0407mryx7pi
Ruf1c+AVfunWMw3dYWdexIRYFTjZxJ0FGzHSFspayJ8SMCXToUtp5C8HVPgu
Eb8pJ1p0BJ+pG7g4pVr+888/R1ukc7jzfEvCX4rlm3sTM2nd2f3ti61PppSh
tTht60DwsysIMlntnb+8e3M4Oj9E2J2TM9UJA2Xuo0JB0Qdb0JqnFt3P6hkO
iGIDsQzhR/NSHbm1c70lZwm2QgMTMwZrtwKaOovTIinzTyM1ltlaJ90+T3D8
S/bKVv20dPPLxpMCTRLw8tLbQt0Rq5yL7q4txo495rSpqFlkRqQGHYwVS3YS
/NhyGnefVPbJtVkGHgIBOjAbCvBmebJAfiAMdh14tchklpkCt5JB9K7aKfQ5
6IYDK+C6TKtAfgA9O7MUyENrZEivvJUK3Q06XrzfT1P0DqUH0H0F6uL4x+F7
i64oSdaylSuJoapvjVWD6Nh/RbhZw4PqxgM5QS39++H5uOmBhctVrKcln+A0
bZNw1CpQSYDlZflo8FdnsstgVRvsDbCdEdpXdTSQahIYVgZTWtbD8s4pQ087
uIVBNCl0/plplx3ZGDulDZnXMkPEAqbxTVfNQGlvkpklZ0Rp+bTwBbdzbQeE
861t32dl32CyAESuAeGcg+iQLliiKgSuCduUCnpA9fuLo/4ex4z5tUFF1UCK
paU6We/KaxkkstRfoOynuAr2d8NZkgARFzUbXvaBE8OksFDkZO0W4um1LtPm
HfEIKgGil+orla6ewaonTwR6Ac9uASf4qmlr5cjtrKs5eorWwSxpOxfPMeaV
lENzaAUB8VJ85imQ/noSjGV6KLX0ec5rxN+4tcB0opLNRvJaJ4okv6fPhyS3
tsRgMODwx+i7UGSmWqWAA+5GX0qubzqh8iHlGvIWLRKydiKdSripJWA21XfQ
yZWSTSaKPYhRAvUeubtJnlczGZozWJGsMAbrmBODMWrKWlFPai2S3iTM9RAq
30OpK9swTB9FmlTBZatosg4FmWSr3oZwgPlew1kFzsaPyuLhyHjEbomGqzpB
e8y09B/BAxpTrUr4xXNjHNc6Ul1zKaNG3+ISuNuiZSFP8GQVIgPtFFtWzTFs
jo1M42gCCK0nDYD4nCom++1K1KM7Dxtl9wxrw1IM8UouqNmqE66dKZ2kg5Eh
/A759Fbm3/CgcAKPboZFB6zbohmc6tmrVhLmVhvgc4V1xV7rPqpVjmKO2802
9cOlTvwcj0Jru3lXAEVtNvdrJL7cgwVrPPuhXnKP3DTVOWQmxqQKvNwRKpFA
CX3ZOOQy4KFNYgvJg12ITVaxUfB6CILldlXPCstWIbTnKmTph3vKzsenc+9z
t7+1tVwuB8vnA7D81sXZVv3SZusJb9AvN+iHDZ4x8VaaQn23aqZpnFBkNC0N
zel7zD17I2uR7SXCKb/n6iYwYlXekDaA6do+6b6EWRPhr3e287VPagk2DSI9
eR0PBy92t7eH097dVOjIJz+UiTPc2dv+JdnXVQ7BlgdkJxpx9ApyL7b57wFZ
Lj2l9PPtwfYdyS9rcnl371e4Qj3aFXu7e4/2xO6DXms8sfMf8EQD2fVssfOv
ksX6mDdUgTCv3bNFDdt3mYB70hr7RMBceIGYkqV/DQNXa2sKrhm4XdUfzcC8
6LEM/G+yWDD8v8hivMH/CYvx/uaR4DV54R5CrWMjzgJmgMQH8RWK2Ol0jA41
U6nrAuaOeANdQsn244hpYbL/lbMNH0fQu2uP9ktMM6xBwe/8w9usaLS2B6M3
s0iflDhlycxSQYa6UyOQZDJ3Bf1Iw0DovPFCuvHUU7/bC+MJDzLohG05Fkj6
ZYEJdEBvAtjJzdBWvowLw0o17DxVN4MAzWeb4c1INftwSxqGs85sVm0B2JxS
a41ZkDvplkmtZfVgVi0r5xbq/Ffik7KGf00xVnXsqg4clvARXXXG+nUf7cq/
511Lq2mc76cqm0GGfrSglx5PX+z0EWQQ0s0zUaEYIykmBItWG2YmLswZln4n
45es5QRWvWpE4x3cWHHI7zEplKP+eqbqMs7tiWM+2HmxG06SGXEZ3kvw+5CK
SJc8f9B8hBy+GUwqwzfpfR0c2dIgH1Yw+n48rlaHV6PnCnMDcpey1SE5S/qN
Lk4PTuuHLHk8OhndlgpzSD2JziXlVZCUccnj4aewCTKetIziq8wsU5XMaIWL
Pu8HiKrkZY/rY+9LFDaXtSRy95+YLDuOvB0AAA==

-->

</rfc>
