Skip to content

Commit 3e36aa8

Browse files
kixelatedclaude
andauthored
Remove Frame/Object Duration from moq-lite and moq-timestamp (#32)
Duration was an application-level presentation hint that the transport never used for delivery decisions. Keeping it encourages a frame of added latency: a publisher either has to know a frame's length before its successor exists (impossible for live) or wait for the next frame to infer it. A bare timestamp lets a receiver present each frame as soon as it arrives. moq-lite: drop the Duration field from the Frame concept, the FRAME message (Duration Delta), the datagram body, the Publisher Timescale omission rule, and the moq-lite-05 changelog. moq-timestamp: remove the DURATION object property entirely, including its 0x915C4 IANA registration (never published, so the codepoint is freed), and the relay age-refinement rationale. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 80308a3 commit 3e36aa8

2 files changed

Lines changed: 17 additions & 55 deletions

File tree

draft-lcurley-moq-lite.md

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,9 @@ A Frame is a payload of bytes within a Group.
155155
A frame is used to represent a chunk of data with an upfront size.
156156
The contents are opaque to the moq-lite layer.
157157

158-
Each frame carries a presentation timestamp expressed in the parent Track's `Timescale` (units per second, part of the [TRACK_INFO](#track-info)), and a duration in the same scale.
158+
Each frame carries a presentation timestamp expressed in the parent Track's `Timescale` (units per second, part of the [TRACK_INFO](#track-info)).
159159
The timestamp is the source-of-truth for media time and is used by the moq-lite layer for [expiration](#expiration) decisions instead of wall-clock arrival time.
160-
The duration is a hint for the application layer (e.g. presentation scheduling) and is not used by moq-lite itself; a duration of `0` means unknown and the frame is presented until the next frame begins.
161-
A Track with a `Timescale` of 0 (unspecified) carries no meaningful timestamps or durations and falls back to wall-clock arrival time for expiration.
160+
A Track with a `Timescale` of 0 (unspecified) carries no meaningful timestamps and falls back to wall-clock arrival time for expiration.
162161

163162
# Flow
164163
This section outlines the flow of messages within a moq-lite session.
@@ -495,13 +494,12 @@ DATAGRAM Body {
495494
Subscribe ID (i)
496495
Group Sequence (i)
497496
[Timestamp (i)]
498-
[Duration (i)]
499497
Payload (b)
500498
}
501499
~~~
502500

503-
`Timestamp` and `Duration` are present only when the Track's `Publisher Timescale` (see [TRACK_INFO](#track-info)) is non-zero.
504-
When `Publisher Timescale` is 0, both fields are omitted from the wire and the datagram body consists of just `Subscribe ID`, `Group Sequence`, and `Payload`.
501+
`Timestamp` is present only when the Track's `Publisher Timescale` (see [TRACK_INFO](#track-info)) is non-zero.
502+
When `Publisher Timescale` is 0, the field is omitted from the wire and the datagram body consists of just `Subscribe ID`, `Group Sequence`, and `Payload`.
505503

506504
**Subscribe ID**:
507505
The Subscribe ID of an active subscription on the same session.
@@ -515,10 +513,6 @@ Each datagram represents a complete group containing exactly one frame.
515513
The absolute timestamp of the single frame in the group, expressed in the Track's negotiated `Timescale`.
516514
Any varint value (including 0) is a valid absolute timestamp.
517515

518-
**Duration**:
519-
The absolute duration of the frame, expressed in the Track's negotiated `Timescale`.
520-
A value of `0` means the duration is unknown; the frame is presented until the next frame begins (or indefinitely, since a datagram-delivered group contains exactly one frame, until the application supersedes it).
521-
522516
**Payload**:
523517
The frame payload, extending to the end of the datagram.
524518
If the Track's `Publisher Compression` is non-zero, the payload is compressed using the negotiated algorithm (see [TRACK_INFO](#track-info)).
@@ -847,7 +841,7 @@ The unit is milliseconds (independent of `Publisher Timescale`) so cache retenti
847841
**Publisher Timescale**:
848842
The number of timestamp units per second for frame timestamps on this Track.
849843
A value of 0 means unspecified; the subscriber MUST treat per-frame timestamps as opaque and fall back to wall-clock arrival time for [expiration](#expiration).
850-
When `Publisher Timescale` is 0, the per-frame `Timestamp Delta` and `Duration Delta` fields are omitted from FRAME messages and the `Timestamp` and `Duration` fields are omitted from datagram bodies (see [FRAME](#frame) and [Datagrams](#datagrams)).
844+
When `Publisher Timescale` is 0, the per-frame `Timestamp Delta` field is omitted from FRAME messages and the `Timestamp` field is omitted from datagram bodies (see [FRAME](#frame) and [Datagrams](#datagrams)).
851845
Common values include `1000` (milliseconds), `1000000` (microseconds), `48000` (audio sample rate), and `90000` (RTP video clock).
852846

853847
**Publisher Compression**:
@@ -1044,14 +1038,13 @@ The FRAME message is a payload within a group.
10441038
~~~
10451039
FRAME Message {
10461040
[Timestamp Delta (i)]
1047-
[Duration Delta (i)]
10481041
Message Length (i)
10491042
Payload (b)
10501043
}
10511044
~~~
10521045

1053-
`Timestamp Delta` and `Duration Delta` are present only when the Track's `Publisher Timescale` (see [TRACK_INFO](#track-info)) is non-zero.
1054-
When `Publisher Timescale` is 0, both fields are omitted from the wire and the FRAME consists of just `Message Length` and `Payload`.
1046+
`Timestamp Delta` is present only when the Track's `Publisher Timescale` (see [TRACK_INFO](#track-info)) is non-zero.
1047+
When `Publisher Timescale` is 0, the field is omitted from the wire and the FRAME consists of just `Message Length` and `Payload`.
10551048

10561049
**Timestamp Delta**:
10571050
A signed delta from the previous frame's timestamp, in the Track's negotiated `Timescale`.
@@ -1063,18 +1056,6 @@ Encoded as a zigzag-mapped variable-length integer:
10631056
Zigzag interleaves non-negative and negative values (`0 → 0, -1 → 1, 1 → 2, -2 → 3, 2 → 4, ...`) so small magnitudes of either sign fit in a 1-byte varint and there is exactly one wire encoding for zero.
10641057
The first frame of a group is delta-encoded from `0`, so its `Timestamp Delta` is the zigzag encoding of the absolute timestamp.
10651058

1066-
**Duration Delta**:
1067-
A signed delta from the previous frame's duration, in the Track's negotiated `Timescale`, encoded using the same zigzag mapping as `Timestamp Delta`.
1068-
A wire value of `0` means the duration is unchanged from the previous frame; this is the common case for constant-rate media and fits in one byte.
1069-
The first frame of a group is delta-encoded from a prior duration of `0`.
1070-
1071-
The resolved duration value carries the following semantics for the application:
1072-
1073-
- A resolved duration of `0` means the duration is unknown; the frame is presented until the next frame in the group begins (or until the group ends, if it is the last frame).
1074-
- A non-zero resolved duration is the explicit presentation duration in the Track's `Timescale`.
1075-
1076-
The duration is an application-level hint and is not used by the moq-lite layer for delivery decisions.
1077-
10781059
**Payload**:
10791060
An application-specific payload.
10801061
If the Track's `Publisher Compression` is non-zero, the payload is compressed using the negotiated algorithm (see [TRACK_INFO](#track-info)) and the `Message Length` describes the compressed size.
@@ -1093,9 +1074,9 @@ A generic library or relay MUST NOT inspect or modify the decompressed contents
10931074
- Renamed `Start Group`/`End Group` to `Group Start`/`Group End` in SUBSCRIBE, SUBSCRIBE_UPDATE, and SUBSCRIBE_DROP for consistency with the entity-first naming used elsewhere (e.g. `Group Sequence`). Wire format unchanged.
10941075
- Allowed a duplicate `active` ANNOUNCE to atomically replace the prior advertisement (equivalent to UNANNOUNCE+ANNOUNCE). Used when only the origin or hop path changes (e.g. relay failover) without interrupting the broadcast. No new wire enum value — the existing `active` status carries the new metadata.
10951076
- Added ANNOUNCE_OK message, sent once at the head of the Announce Stream response. Carries the publisher's `Hop ID` (hoisted out of every ANNOUNCE's Hop ID list) and an `Active Count` so subscribers can batch the initial set instead of reporting each ANNOUNCE as it trickles in.
1096-
- Added `Publisher Timescale` to TRACK_INFO for per-track timestamp negotiation. When `Publisher Timescale` is 0, the per-frame timestamp/duration fields are omitted entirely from FRAME and datagram bodies.
1097-
- Added `Timestamp Delta` and `Duration Delta` to FRAME, both zigzag-encoded signed varints (present only when timescale is non-zero). `Duration Delta = 0` is the common "unchanged" case and fits in one byte; a resolved duration of `0` means "until the next frame".
1098-
- Added `Timestamp` and `Duration` to the QUIC datagram body (absolute, present only when timescale is non-zero).
1077+
- Added `Publisher Timescale` to TRACK_INFO for per-track timestamp negotiation. When `Publisher Timescale` is 0, the per-frame timestamp field is omitted entirely from FRAME and datagram bodies.
1078+
- Added `Timestamp Delta` to FRAME, a zigzag-encoded signed varint (present only when timescale is non-zero).
1079+
- Added `Timestamp` to the QUIC datagram body (absolute, present only when timescale is non-zero).
10991080
- Renamed `Publisher Max Latency` to `Publisher Cache` (now in TRACK_INFO), defined as a minimum retention guarantee (similar to HTTP `Cache-Control: max-age`). Groups may live longer than `Publisher Cache` and remain FETCH-able.
11001081
- Renamed `Subscriber Max Latency` to `Subscriber Stale` in SUBSCRIBE/SUBSCRIBE_UPDATE. It is the subscriber's delivery-time preference for dropping non-latest stale groups, separate from the publisher's retention guarantee.
11011082
- Timestamp-based expiration replaces wall-clock arrival time when a Track timescale is negotiated.

draft-lcurley-moq-timestamp.md

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ informative:
2323

2424
--- abstract
2525

26-
This document defines an extension for MoQ Transport {{moqt}} that attaches a media presentation timestamp and duration to each object.
27-
A track-level Timescale property establishes the units, an object-level Timestamp property carries the presentation time of each object, and an optional Duration property carries its presentation duration.
26+
This document defines an extension for MoQ Transport {{moqt}} that attaches a media presentation timestamp to each object.
27+
A track-level Timescale property establishes the units, and an object-level Timestamp property carries the presentation time of each object.
2828
Exposing media time to the transport lets relays make consistent age-based decisions (e.g. dropping stale objects) without parsing the media container, and it remains consistent across hops regardless of buffering or jitter.
2929

3030
--- middle
@@ -46,7 +46,7 @@ A relay frequently needs a notion of *when* an object is meant to be presented:
4646
MoQ also demultiplexes media into many independent tracks — audio, video, captions, metadata, and more — so a timestamp is needed on nearly every track.
4747
Re-implementing per-object timestamping inside each application's container format, for every track, is repetitive and error-prone; standardizing it at the transport lets one implementation serve every track and lets relays use it directly.
4848

49-
This extension exposes media time to the transport with three Key-Value-Pairs ({{moqt}} Section 2.5): a track-level **Timescale**, an object-level **Timestamp**, and an optional object-level **Duration**.
49+
This extension exposes media time to the transport with two Key-Value-Pairs ({{moqt}} Section 2.5): a track-level **Timescale** and an object-level **Timestamp**.
5050
The transport does not interpret the *meaning* of the timeline (it is still the application's clock); it only uses the timestamp for relative age comparisons.
5151

5252

@@ -67,7 +67,7 @@ A relay MAY perform timestamp-based dropping for a track only if the upstream pu
6767

6868

6969
# TIMESCALE Track Property
70-
The TIMESCALE property establishes the units for every Timestamp and Duration on a track.
70+
The TIMESCALE property establishes the units for every Timestamp on a track.
7171
It is a track-level Key-Value-Pair, carried with the track's properties (see {{moqt}} Section 2.5 and Section 12).
7272
Because the value is a single integer, TIMESCALE uses an even Type so the value is a bare varint with no length prefix:
7373

@@ -81,11 +81,11 @@ TIMESCALE Track Property {
8181
**Value**:
8282
The number of timestamp units per second.
8383
Common values include `1000` (milliseconds), `1000000` (microseconds), `48000` (a typical audio sample rate), and `90000` (the RTP video clock).
84-
A value of `0`, or the absence of the property, means the track has no media timeline: Timestamp and Duration properties, if present, MUST be ignored, and a relay MUST fall back to wall-clock arrival time for any age-based decision.
84+
A value of `0`, or the absence of the property, means the track has no media timeline: Timestamp properties, if present, MUST be ignored, and a relay MUST fall back to wall-clock arrival time for any age-based decision.
8585

8686
The Timescale is fixed for the lifetime of the track and MUST NOT change.
8787

88-
The Timescale is required to interpret the units of every Timestamp and Duration, so a receiver cannot resolve an object's timing until it has the track's properties.
88+
The Timescale is required to interpret the units of every Timestamp, so a receiver cannot resolve an object's timing until it has the track's properties.
8989
Those properties are delivered in SUBSCRIBE_OK or TRACK_STATUS ({{moqt}} Section 12), so a receiver that begins receiving objects before it has them MUST buffer the timing (or treat it as unknown) until the Timescale arrives.
9090
A relay that has not yet learned the Timescale MUST fall back to wall-clock arrival time for any age-based decision.
9191

@@ -117,24 +117,6 @@ This decision is identical at every hop because it depends only on values embedd
117117
A relay MUST NOT use timestamps to reorder delivery beyond what {{moqt}} already permits; this property informs *dropping*, not transmission order.
118118

119119

120-
# DURATION Object Property
121-
The DURATION property carries the presentation duration of an object, in the track's Timescale.
122-
It is optional and is an object-level Key-Value-Pair with an even Type:
123-
124-
~~~
125-
DURATION Object Property {
126-
Type (vi64) = 0x915C4
127-
Value (vi64) ; presentation duration, in Timescale units
128-
}
129-
~~~
130-
131-
**Value**:
132-
The presentation duration of the object, expressed in the track's Timescale.
133-
A value of `0`, or the absence of the property, means the duration is unknown; the object is presented until the next object begins.
134-
135-
Duration is primarily an application-level presentation hint, but a relay MAY also use it to refine age-based dropping: an object's Timestamp plus its Duration marks the end of its presentation interval, which is a more precise "this object is now in the past" signal than the Timestamp alone (for example, the last object of a group has no following object to bound it). A relay MUST NOT rely on Duration being present; when it is absent, the relay falls back to comparing Timestamps as in [Age-Based Dropping](#age-based-dropping).
136-
137-
138120
# Security Considerations
139121
Timestamps expose the media timeline to relays, which is the point of the extension, but a relay still treats payloads as opaque and gains no access to media content.
140122

@@ -147,7 +129,7 @@ Because age-based dropping only affects which objects a live subscription receiv
147129

148130
This document requests the following registrations.
149131
High, distinctive values are requested to avoid the low ranges reserved by {{moqt}} and to minimize collisions with provisional registrations by other extensions; they also avoid the greasing pattern (`0x7f * N + 0x9D`).
150-
The three property Types are even so that each value is a bare varint with no length prefix (see {{moqt}} Section 2.5).
132+
The property Types are even so that each value is a bare varint with no length prefix (see {{moqt}} Section 2.5).
151133

152134
## MOQT Setup Options
153135

@@ -165,7 +147,6 @@ This document requests registrations in the "MOQT Properties" registry ({{moqt}}
165147
|:--------|:----------|:-------|:--------------|
166148
| 0x915C0 | TIMESCALE | Track | This Document |
167149
| 0x915C2 | TIMESTAMP | Object | This Document |
168-
| 0x915C4 | DURATION | Object | This Document |
169150

170151

171152
--- back

0 commit comments

Comments
 (0)