moq L. Curley Internet-Draft 3 August 2026 Intended status: Informational Expires: 4 February 2027 Media over QUIC - Hang draft-lcurley-moq-hang-02 Abstract 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. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 4 February 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Curley Expires 4 February 2027 [Page 1] Internet-Draft hang August 2026 Table of Contents 1. Conventions and Definitions . . . . . . . . . . . . . . . . . 2 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 2 3. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4. Catalog . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4.1. Root . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4.2. Video . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4.3. Audio . . . . . . . . . . . . . . . . . . . . . . . . . . 6 4.3.1. PCM . . . . . . . . . . . . . . . . . . . . . . . . . 7 4.4. Binary Fields . . . . . . . . . . . . . . . . . . . . . . 7 4.5. Common Rendition Fields . . . . . . . . . . . . . . . . . 8 4.5.1. broadcast . . . . . . . . . . . . . . . . . . . . . . 8 4.5.2. container . . . . . . . . . . . . . . . . . . . . . . 8 4.5.3. jitter . . . . . . . . . . . . . . . . . . . . . . . 8 5. Container . . . . . . . . . . . . . . . . . . . . . . . . . . 9 5.1. legacy . . . . . . . . . . . . . . . . . . . . . . . . . 9 5.2. cmaf . . . . . . . . . . . . . . . . . . . . . . . . . . 10 5.3. loc . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6. Security Considerations . . . . . . . . . . . . . . . . . . . 10 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 10 8. Normative References . . . . . . . . . . . . . . . . . . . . 10 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 11 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 11 1. Conventions and Definitions The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. 2. Terminology Hang is built on top of moq-lite [moql] and uses much of the same terminology. A quick recap: * *Broadcast*: A collection of Tracks from a single publisher. * *Track*: A series of Groups, each of which can be delivered and decoded _out-of-order_. * *Group*: A series of Frames, each of which must be delivered and decoded _in-order_. * *Frame*: A sized payload of bytes representing a single moment in time. Curley Expires 4 February 2027 [Page 2] Internet-Draft hang August 2026 Hang introduces additional terminology: * *Room*: A collection of participants, publishing under a common prefix. * *Participant*: A moq-lite broadcaster that may produce any number of media tracks. * *Catalog*: A JSON document that describes each available media track, supporting live updates. * *Container*: A tiny header in front of each media payload containing the timestamp. 3. Discovery 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. A room consists of a path. Any participants within the room MUST publish a broadcast with the room path as a prefix which SHOULD end with the .hang suffix. For example: /room123/alice.hang /room123/bob.hang /room456/zoe.hang 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. For example: ANNOUNCE_PLEASE prefix=/room/ ANNOUNCE suffix=alice.hang active=true ANNOUNCE suffix=bob.hang active=true If a participant leaves or is disconnected, their broadcast is unannounced. Publishers and subscribers SHOULD terminate any subscriptions once a participant is unannounced. ANNOUNCE suffix=alice.hang active=false Curley Expires 4 February 2027 [Page 3] Internet-Draft hang August 2026 4. Catalog The catalog describes the available media tracks for a single participant. It's a JSON document that extends the W3C WebCodecs specification [webcodecs]. The catalog is published as a catalog.json track within the broadcast so it can be updated live as the participant's media tracks change. A participant MAY forgo publishing a catalog if it does not wish to publish any media tracks now and in the future. The catalog track consists of multiple groups, one for each update. Each group contains a single frame with UTF-8 JSON. A publisher MUST NOT write multiple frames to a group until a future specification includes a delta-encoding mechanism (via JSON Patch most likely). 4.1. Root The root of the catalog is a JSON document with the following schema: type Catalog = { "audio": AudioSchema | undefined, "video": VideoSchema | undefined, // ... any custom fields ... } Additional fields MAY be added based on the application. The catalog SHOULD be mostly static, delegating any dynamic content to other tracks. For example, a "chat" section should include the name of a chat track, not individual chat messages. This way catalog updates are rare and a client MAY choose to not subscribe. This specification currently only defines audio and video tracks. 4.2. Video A video track contains the necessary information to decode a video stream. Curley Expires 4 February 2027 [Page 4] Internet-Draft hang August 2026 type VideoSchema = { "renditions": Map, "display": { "width": number, "height": number, } | undefined, "rotation": number | undefined, "flip": boolean | undefined, } The renditions field contains a map of track names to video decoder configurations. See the WebCodecs specification (https://www.w3.org/TR/webcodecs/#video-decoder-config) for specifics and registered codecs. Any field carrying raw bytes, notably description, is a hex string (Section 4.4). The display field is the size to render the video at, in pixels. It is separate from a rendition's displayAspectWidth/displayAspectHeight because changing it does not require reinitializing the decoder. In addition to the WebCodecs fields, each rendition MAY carry the fields common to audio and video (Section 4.5) plus: type VideoDecoderConfigExtensions = { "displayAspectWidth": number | undefined, "displayAspectHeight": number | undefined, } displayAspectWidth and displayAspectHeight give the display aspect ratio of the media, stretching or shrinking the coded pixels. A consumer that understands neither field MUST assume square pixels, a 1:1 ratio. Both MUST be present together; a consumer that sees only one MUST ignore it. For example: Curley Expires 4 February 2027 [Page 5] Internet-Draft hang August 2026 { "renditions": { "720p": { "codec": "avc1.64001f", "container": { "kind": "legacy" }, "codedWidth": 1280, "codedHeight": 720, "bitrate": 6000000, "framerate": 30.0, "jitter": 33 }, "480p": { "codec": "avc1.64001e", "container": { "kind": "legacy" }, "codedWidth": 848, "codedHeight": 480, "bitrate": 2000000, "framerate": 30.0, "jitter": 33 } }, "display": { "width": 1280, "height": 720 }, "rotation": 0, "flip": false, } 4.3. Audio An audio track contains the necessary information to decode an audio stream. type AudioSchema = { "renditions": Map, } The renditions field contains a map of track names to audio decoder configurations. See the WebCodecs specification (https://www.w3.org/TR/webcodecs/#audio-decoder-config) for specifics and registered codecs. Any field carrying raw bytes, notably description, is a hex string (Section 4.4). In addition to the WebCodecs fields, each rendition MAY carry the fields common to audio and video (Section 4.5). Curley Expires 4 February 2027 [Page 6] Internet-Draft hang August 2026 4.3.1. PCM Hang defines the "pcm" audio codec for uncompressed samples. The sampleRate and numberOfChannels fields MUST be present and greater than zero. The description field MUST NOT be present. If bitrate is present, it MUST equal sampleRate * numberOfChannels * 32. Each codec payload consists of interleaved IEEE 754 binary32 samples in little-endian byte order. Samples are ordered by sample frame, then by ascending channel index within each frame. The payload length MUST be a non-zero multiple of 4 * numberOfChannels. The frame timestamp identifies the presentation time of its first sample. The frame duration in seconds is the payload length divided by 4 * numberOfChannels * sampleRate. For example: { "renditions": { "stereo": { "codec": "opus", "container": { "kind": "legacy" }, "sampleRate": 48000, "numberOfChannels": 2, "bitrate": 128000, "jitter": 20 }, "mono": { "codec": "opus", "container": { "kind": "legacy" }, "sampleRate": 48000, "numberOfChannels": 1, "bitrate": 64000, "jitter": 20 } }, } 4.4. Binary Fields A decoder config field carrying raw bytes, notably description (an AllowSharedBufferSource in WebCodecs), is carried in the catalog as a hex string ([RFC4648], Section 8). A publisher SHOULD emit lowercase hexadecimal characters and MUST NOT emit a 0x prefix or any separators. A consumer MUST accept either case. Curley Expires 4 February 2027 [Page 7] Internet-Draft hang August 2026 Note that this differs from the cmaf container's init field (Section 5), which is base64 ([RFC4648], Section 4); the two alphabets overlap, so the encoding cannot be detected and must be specified. 4.5. Common Rendition Fields Audio and video renditions share the following fields, extending the WebCodecs decoder config: type CommonExtensions = { "broadcast": string | undefined, "container": Container, "jitter": number | undefined, } 4.5.1. broadcast By default a rendition's track lives in the same broadcast that served the catalog. The broadcast field overrides that, naming a different broadcast that publishes the track. The value is a relative path, resolved against the path of the broadcast that served the catalog. It uses the . and .. semantics of a relative URL reference ([RFC3986], Section 5.2.4), for example ../source. A publisher MUST NOT use an absolute path, and a consumer MUST ignore a rendition whose broadcast escapes above the root. This lets a publisher author a catalog that points at tracks it does not republish. For example, a transcoder produces a catalog listing its own downstream renditions alongside the untouched source rendition, referencing the latter in the source broadcast rather than copying the bytes through. A consumer subscribes to such a rendition in the referenced broadcast, using the rendition's track name unchanged. 4.5.2. container The container used to frame this rendition's media, as described in Section 5. If absent, it defaults to { "kind": "legacy" }. 4.5.3. jitter The maximum delay, in milliseconds, between a frame being ready and the publisher flushing it. A consumer's jitter buffer SHOULD be at least this large to avoid stalling. If absent, a consumer SHOULD assume each frame is flushed immediately. Curley Expires 4 February 2027 [Page 8] Internet-Draft hang August 2026 For example: * If each frame is flushed immediately, a video track's jitter is 1000/framerate. * If up to 3 B-frames may be emitted in a row, it is 3 * 1000/ framerate. * If frames are buffered into 2 second segments, it is 2000. An audio frame's duration is codec dependent. AAC often uses 1024 samples per frame, so at 44100Hz an immediately-flushed track's jitter is 23. 5. Container Audio and video tracks use a container to encapsulate the media payload. A rendition declares its container via the container field of its catalog entry (Section 4.5): type Container = { "kind": "legacy" } | { "kind": "cmaf", "init": string } | { "kind": "loc" } The kind field selects the framing; a consumer MUST ignore a rendition whose kind it does not recognize. Every container shares the same group rules: Each moq-lite group MUST start with a keyframe. If the codec does not support delta frames (e.g. audio), a group MAY consist of multiple keyframes. Otherwise, a group MUST consist of a single keyframe followed by zero or more delta frames. 5.1. legacy The default, used when the container field is absent. 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. For example, h.264 with no description field would be annex.b encoded, while h.264 with a description field would be AVCC encoded. Curley Expires 4 February 2027 [Page 9] Internet-Draft hang August 2026 5.2. cmaf Each frame is a complete fragmented MP4 fragment (moof+mdat), carrying its own timestamps. The init field is the initialization segment (ftyp+moov) for the track, base64-encoded ([RFC4648], Section 4). A consumer MUST feed init to the decoder before the first frame. 5.3. loc Each frame is a Low Overhead Container frame [I-D.ietf-moq-loc]: a property block, carrying the timestamp among other properties, followed by the codec payload. 6. Security Considerations TODO Security 7. IANA Considerations This document has no IANA actions. 8. Normative References [I-D.ietf-moq-loc] Zanaty, M., Nandakumar, S., and P. Thatcher, "Low Overhead Media Container", Work in Progress, Internet-Draft, draft- ietf-moq-loc-04, 20 July 2026, . [moql] Curley, L., "Media over QUIC - Lite", Work in Progress, Internet-Draft, draft-lcurley-moq-lite-05, 30 June 2026, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, . Curley Expires 4 February 2027 [Page 10] Internet-Draft hang August 2026 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, . [webcodecs] W3C, "WebCodecs", . Acknowledgments TODO acknowledge. Author's Address Luke Curley Email: kixelated@gmail.com Curley Expires 4 February 2027 [Page 11]