You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Move the telescoping subscriber count out of the subscription's update
path into a dedicated SUBSCRIBE_STATS telemetry message, named
generically so further cheaply-aggregatable stats can be added later.
moq-lite: SUBSCRIBE_UPDATE re-echoes all five subscription parameters
on every send, so bumping a counter through it is wasteful. Carry the
count in a separate SUBSCRIBE_STATS message instead. This introduces a
Type tag on the subscriber's post-SUBSCRIBE messages (0x0
SUBSCRIBE_UPDATE, 0x1 SUBSCRIBE_STATS) to distinguish them, mirroring
the publisher's already-typed responses; the count field is removed
from SUBSCRIBE and SUBSCRIBE_UPDATE.
moq-transport: rename the SUBSCRIBER_COUNT message to SUBSCRIBE_STATS
and make its body a list of stats encoded as Message Parameters, so
new stats are added without a new message type or a wire break.
Subscriber Count becomes one such parameter (even type, count - 1).
Draft renamed to draft-lcurley-moq-subscribe-stats.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: draft-lcurley-moq-lite.md
+35-13Lines changed: 35 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -300,7 +300,8 @@ There MAY be multiple Announce Streams, potentially containing overlapping prefi
300
300
### Subscribe
301
301
A subscriber opens Subscribe Streams to request a Track.
302
302
303
-
The subscriber MUST start a Subscribe Stream with a SUBSCRIBE message followed by any number of SUBSCRIBE_UPDATE messages.
303
+
The subscriber MUST start a Subscribe Stream with a SUBSCRIBE message followed by any number of SUBSCRIBE_UPDATE and SUBSCRIBE_STATS messages.
304
+
The opening SUBSCRIBE is identified by the stream type (0x2) and carries no message Type; every subsequent message from the subscriber begins with a Type that distinguishes SUBSCRIBE_UPDATE from SUBSCRIBE_STATS, mirroring how the publisher's messages on this stream are typed.
304
305
When a start group can be resolved, the publisher replies with a SUBSCRIBE_OK message (confirming the subscription and resolving its start group), followed by any number of SUBSCRIBE_END and SUBSCRIBE_DROP messages.
305
306
When the accepted track has already ended with no matching groups there is no start group to resolve, so the publisher sends SUBSCRIBE_END with no preceding SUBSCRIBE_OK.
306
307
A rejection is a stream reset: if the publisher cannot serve the subscription — the track does not exist, or it otherwise refuses — it MUST reset the stream rather than leave it pending, and SHOULD do so promptly (within roughly a round trip) so the subscriber is not left waiting.
@@ -732,7 +733,6 @@ SUBSCRIBE Message {
732
733
Subscriber Stale (i)
733
734
Group Start (i)
734
735
Group End (i)
735
-
Subscriber Count (i)
736
736
}
737
737
~~~
738
738
@@ -768,14 +768,6 @@ The last group to deliver (inclusive).
768
768
A value of 0 means unbounded (default).
769
769
A non-zero value is the absolute group sequence + 1.
770
770
771
-
**Subscriber Count**:
772
-
The number of subscribers this subscription represents, encoded as the count minus one: the subscription is the implicit `1`, so a leaf subscriber sends `0`.
773
-
This is a [subscriber property](#track-info) that fans *in* at a relay: a relay merging multiple downstream subscriptions into one upstream subscription sets this to the **sum** of their counts, so the value telescopes up the fan-out tree.
774
-
A publisher therefore learns its total number of downstream subscribers across any number of relay hops by reading the count on its single upstream subscription, without any per-hop coordination.
775
-
The count changes as subscribers join and leave; a relay refreshes it via SUBSCRIBE_UPDATE.
776
-
A relay holding a subscription open with no live downstream subscribers (e.g. briefly retaining it for reuse) MUST still report at least `1`, since the held subscription cannot represent fewer subscribers than itself.
777
-
The count is advisory: a subscriber MAY misreport it, and a relay MUST NOT use it for delivery decisions.
778
-
779
771
780
772
## SUBSCRIBE_UPDATE
781
773
A subscriber can modify a subscription with a SUBSCRIBE_UPDATE message.
@@ -784,21 +776,51 @@ The start and end group can be changed in either direction (growing or shrinking
784
776
785
777
~~~
786
778
SUBSCRIBE_UPDATE Message {
779
+
Type (i) = 0x0
787
780
Message Length (i)
788
781
Subscriber Priority (8)
789
782
Subscriber Ordered (8)
790
783
Subscriber Stale (i)
791
784
Group Start (i)
792
785
Group End (i)
786
+
}
787
+
~~~
788
+
789
+
**Type**:
790
+
Set to 0x0 to indicate a SUBSCRIBE_UPDATE message.
791
+
792
+
See [SUBSCRIBE](#subscribe) for information about each remaining field.
793
+
794
+
795
+
## SUBSCRIBE_STATS
796
+
A subscriber sends a SUBSCRIBE_STATS message to report telemetry about a subscription.
797
+
Unlike SUBSCRIBE_UPDATE, it does not modify the subscription and the publisher only observes it; it is kept separate so that refreshing telemetry does not re-echo the subscription's delivery parameters on every change.
798
+
A subscriber MAY send multiple SUBSCRIBE_STATS messages over the life of the subscription to refresh the values.
799
+
800
+
~~~
801
+
SUBSCRIBE_STATS Message {
802
+
Type (i) = 0x1
803
+
Message Length (i)
793
804
Subscriber Count (i)
794
805
}
795
806
~~~
796
807
797
-
See [SUBSCRIBE](#subscribe) for information about each field.
808
+
**Type**:
809
+
Set to 0x1 to indicate a SUBSCRIBE_STATS message.
798
810
799
-
A relay SHOULD rate-limit SUBSCRIBE_UPDATE messages sent purely to refresh the `Subscriber Count` (for example, coalescing changes within a short window of roughly a second), so that rapid subscriber churn does not flood the upstream with control messages.
811
+
**Subscriber Count**:
812
+
The number of subscribers this subscription represents, encoded as the count minus one: the subscription is the implicit `1`, so a leaf subscriber sends `0`.
813
+
This is a subscriber-side value that fans *in* at a relay: a relay merging multiple downstream subscriptions into one upstream subscription sets this to the **sum** of their counts, so the value telescopes up the fan-out tree.
814
+
A publisher therefore learns its total number of downstream subscribers across any number of relay hops by reading the count on its single upstream subscription, without any per-hop coordination.
815
+
Until a SUBSCRIBE_STATS is received, the count is `1`; a leaf subscriber that represents only itself need not send the message.
816
+
A relay holding a subscription open with no live downstream subscribers (e.g. briefly retaining it for reuse) MUST still report at least `1`, since the held subscription cannot represent fewer subscribers than itself.
817
+
The count is advisory: a subscriber MAY misreport it, and a relay MUST NOT use it for delivery decisions.
818
+
819
+
A relay SHOULD rate-limit SUBSCRIBE_STATS messages (for example, coalescing changes within a short window of roughly a second), so that rapid subscriber churn does not flood the upstream with control messages.
800
820
Because the count is the latest aggregate rather than a delta, a change that reverts within the window requires no message at all.
801
821
822
+
Future revisions MAY append additional stats to this message; the `Message Length` bounds the message so a receiver can stop after the fields it understands.
823
+
802
824
803
825
## TRACK
804
826
TRACK is sent by a subscriber to request a Track's immutable publisher properties.
@@ -1097,7 +1119,7 @@ A generic library or relay MUST NOT inspect or modify the decompressed contents
1097
1119
# Appendix A: Changelog
1098
1120
1099
1121
## moq-lite-05
1100
-
- Added `Subscriber Count` to SUBSCRIBE and SUBSCRIBE_UPDATE, a telescoping count of downstream subscribers. Encoded as the count minus one (a leaf sends `0`); a relay sums the counts of the downstream subscriptions it merges, so a publisher reads its total audience across any number of hops from its single upstream subscription. It is a subscriber property that fans *in* like the others, so it refreshes via SUBSCRIBE_UPDATE; relays SHOULD rate-limit count-only updates to absorb subscriber churn.
1122
+
- Added a SUBSCRIBE_STATS message carrying a telescoping `Subscriber Count` (count of downstream subscribers, encoded as the count minus one so a leaf sends `0`); a relay sums the counts of the downstream subscriptions it merges, so a publisher reads its total audience across any number of hops from its single upstream subscription. It is kept separate from SUBSCRIBE_UPDATE so that refreshing telemetry does not re-echo the subscription's delivery parameters; relays SHOULD rate-limit it to absorb subscriber churn. This also introduced a `Type` tag on the subscriber's post-SUBSCRIBE messages (`0x0` SUBSCRIBE_UPDATE, `0x1` SUBSCRIBE_STATS) to distinguish them, mirroring the publisher's typed responses.
1101
1123
- Added a SETUP message, sent once on a unidirectional Setup Stream (0x1) at the start of the session and FIN'd immediately. It carries a list of Setup Parameters for negotiating optional capabilities and extensions per-hop, replacing the prior stream-probing approach (version is still negotiated via ALPN, not SETUP). Endpoints keep exchanging non-Setup streams without waiting for SETUP, buffering only a stream whose encoding a negotiated extension would change; unknown stream types are still reset as a fallback.
1102
1124
- Added a SETUP `Probe` parameter advertising the publisher's capability level: `None`, `Report` (measure and report the estimated bitrate), or `Increase` (additionally pad to probe for bandwidth above the current sending rate). The levels are nested since probing without measuring is meaningless. A subscriber must not rely on a level the publisher did not advertise.
1103
1125
- Added `Frame Start` to FETCH so a subscriber can begin partway through a group instead of always at frame `0`, allowing resumption of a partially-received group.
0 commit comments