§5.1.

Subscriptions

All subscriptions begin in the Idle state. A subscription can be initiated and moved to the Pending state by either a publisher or a subscriber. A publisher initiates a subscription to a track by sending the PUBLISH message. The subscriber either accepts or rejects the subscription using PUBLISH_OK or REQUEST_ERROR. A subscriber initiates a subscription to a track by sending the SUBSCRIBE message. The publisher either accepts or rejects the subscription using SUBSCRIBE_OK or REQUEST_ERROR. Once either of these sequences is successful, the subscription moves to the Established state and can be updated by the subscriber using SUBSCRIBE_UPDATE. Either endpoint can terminate an Established subscription, moving it to the Terminated state. The subscriber terminates a subscription using UNSUBSCRIBE, the publisher terminates a subscription using PUBLISH_DONE.

This diagram shows the subscription state machine:

+--------+ | Idle | +--------+ | | SUBSCRIBE | | PUBLISH (subscriber)| | (publisher) V V +--------------+ +--------------+ | Pending | | Pending | +----| (Subscriber) | | (Publisher) |----+ | +--------------+ +--------------+ | | | | | REQUEST_ERROR | SUBSCRIBE_OK | | PUBLISH_OK | REQUEST_ERROR | (publisher)| | (subscriber) | | V V | | +-------------+ | | | Established | ------+ | | | | SUBSCRIBE_UPDATE | +-------------+ <-----+ | | | | | UNSUBSCRIBE | | PUBLISH_DONE | | (subscriber)| | (publisher) | | V V | | +-------------+ | +----------->| Terminated | <------------+ +-------------+

A publisher MUST send exactly one SUBSCRIBE_OK or REQUEST_ERROR in response to a SUBSCRIBE. A subscriber MUST send exactly one PUBLISH_OK or REQUEST_ERROR in response to a PUBLISH. The peer SHOULD close the session with a protocol error if it receives more than one.

A publisher MUST save the Largest Location communicated in PUBLISH or SUBSCRIBE_OK when establishing a subscription. This value can be used in a Joining FETCH (see Section 9.16.2) at any time while the subscription is active.

All Established subscriptions have a Forward State which is either 0 or 1. If the Forward State is 0, the publisher does not send objects for the subscription. If the Forward State is 1, the publisher sends objects. The initiator of the subscription sets the initial Forward State in either PUBLISH or SUBSCRIBE. The sender of PUBLISH_OK can update the Forward State based on its preference. Once the subscription is established, the subscriber can update the Forward State by sending SUBSCRIBE_UPDATE. Control messages, such as PUBLISH_DONE (Section 9.15) are still sent on subscriptions in Forward State 0.

Either endpoint can initiate a subscription to a track without exchanging any prior messages other than SETUP. Relays MUST NOT send any PUBLISH messages without knowing the client is interested in and authorized to receive the content. The communication of intent and authorization can be accomplished by the client sending SUBSCRIBE_NAMESPACE, or conveyed in other mechanisms out of band.

An endpoint MAY SUBSCRIBE to a Track it is publishing, though only Relays are required to handle such a SUBSCRIBE. Such self-subscriptions are identical to subscriptions initiated by other endpoints, and all published Objects will be forwarded back to the endpoint, subject to priority and congestion response rules.

A publisher SHOULD begin sending incomplete objects when available to avoid incurring additional latency.

Publishers MAY start sending Objects on PUBLISH-initiated subscriptions before receiving a PUBLISH_OK response to reduce latency. Doing so can consume unnecessary resources in cases where the Subscriber rejects the subscription with REQUEST_ERROR or sets Forward State=0 in PUBLISH_OK. It can also result in the Subscriber dropping Objects if its buffering limits are exceeded (see Section 10.3 and Section 10.4.2).

5.1.1. Subscription State Management

A subscriber keeps subscription state until it sends UNSUBSCRIBE, or after receipt of a PUBLISH_DONE or REQUEST_ERROR. Note that PUBLISH_DONE does not usually indicate that state can immediately be destroyed, see Section 9.15.

The Publisher can destroy subscription state as soon as it has received UNSUBSCRIBE. It MUST reset any open streams associated with the SUBSCRIBE.

The Publisher can also immediately delete subscription state after sending PUBLISH_DONE, but MUST NOT send it until it has closed all related streams.

A REQUEST_ERROR indicates no objects will be delivered, and both endpoints can immediately destroy relevant state. Objects MUST NOT be sent for requests that end with an error.

5.1.2. Subscription Filters

Subscribers can specify a filter on a subscription indicating to the publisher which Objects to send. Subscriptions without a filter pass all Objects published or received via upstream subscriptions.

All filters have a Start Location and an optional End Group. Only objects published or received via a subscription having Locations greater than or equal to Start Location and strictly less than or equal to the End Group (when present) pass the filter.

Some filters are defined to be relative to the Largest Object. The Largest Object is the Object with the largest Location (Section 1.4.1) in the Track from the perspective of the publisher processing the message. Largest Object updates when the first byte of an Object with a Location larger than the previous value is published or received through a subscription.

A Subscription Filter has the following structure:

Subscription Filter {
  Filter Type (i),
  [Start Location (Location),]
  [End Group (i),]
}

Filter Type can have one of the following values:

Largest Object (0x2): The filter Start Location is {Largest Object.Group, Largest Object.Object + 1} and Largest Object is communicated in SUBSCRIBE_OK. If no content has been delivered yet, the filter Start Location is {0, 0}. There is no End Group - the subscription is open ended. Note that due to network reordering or prioritization, relays can receive Objects with Locations smaller than Largest Object after the SUBSCRIBE is processed, but these Objects do not pass the Largest Object filter.

Next Group Start (0x1): The filter Start Location is {Largest Object.Group + 1, 0} and Largest Object is communicated in SUBSCRIBE_OK. If no content has been delivered yet, the filter Start Location is {0, 0}. There is no End Group - the subscription is open ended. For scenarios where the subscriber intends to start from more than one group in the future, it can use an AbsoluteStart filter instead.

AbsoluteStart (0x3): The filter Start Location is specified explicitly. The specified Start Location MAY be less than the Largest Object observed at the publisher. There is no End Group - the subscription is open ended. An AbsoluteStart filter with Start = {0, 0} is equivalent to an unfiltered subscription.

AbsoluteRange (0x4): The filter Start Location and End Group are specified explicitly. The specified Start Location MAY be less than the Largest Object observed at the publisher. If the specified End Group is the same group specified in Start Location, the remainder of that Group passes the filter. End Group MUST specify the same or a larger Group than specified in Start Location.

An endpoint that receives a filter type other than the above MUST close the session with PROTOCOL_VIOLATION.

5.1.3. Joining an Ongoing Track

The MOQT Object model is designed with the concept that the beginning of a Group is a join point, so in order for a subscriber to join a Track, it needs to request an existing Group or wait for a future Group. Different applications will have different approaches for when to begin a new Group.

To join a Track at a past Group, the subscriber sends a SUBSCRIBE with Filter Type Largest Object followed by a Joining FETCH (see Section 9.16.2) for the intended start Group, which can be relative. To join a Track at the next Group, the subscriber sends a SUBSCRIBE with Filter Type Next Group Start.

5.1.3.1. Dynamically Starting New Groups

While some publishers will deterministically create new Groups, other applications might want to only begin a new Group when needed. A subscriber joining a Track might detect that it is more efficient to request the Original Publisher create a new group than issue a Joining FETCH. Publishers indicate a Track supports dynamic group creation using the DYNAMIC_GROUPS parameter (Section 9.2.1.11).

One possible subscriber pattern is to SUBSCRIBE to a Track using Filter Type Largest Object and observe the Largest Location in the response. If the Object ID is below the application's threshold, the subscriber sends a FETCH for the beginning of the Group. If the Object ID is above the threshold and the Track supports dynamic groups, the subscriber sends a SUBSCRIBE_UPDATE message with the NEW_GROUP_REQUEST parameter equal to the Largest Location's Group, plus one (see Section 9.2.1.12).

Another possible subscriber pattern is to send a SUBSCRIBE with Filter Type Next Group Start and NEW_GROUP_REQUEST equal to 0. The value of DYNAMIC_GROUPS in SUBSCRIBE_OK will indicate if the publisher supports dynamic groups. A publisher that does will begin the next group as soon as practical.

This is one section of the MoQT specification, rendered per-section for quick reference and citation. The authoritative text is draft-ietf-moq-transport-15 at the IETF.