Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions draft-ietf-moq-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,36 @@ Type `Largest Object` followed by a Joining FETCH (see {{joining-fetches}}) 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`.

When a subscriber is already receiving one Track and intends to join another
Track that carries equivalent content, such as a higher or lower bitrate
variant, the subscriber uses a switching procedure. The subscriber identifies
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a relay identify that two tracks are "switchable" because they contain equivalent content?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding the relay knows that from the SWITCH (without the SWITCH the relay does not know as relays don't have access to catalog payload information).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what If I'm a user, and I request switch(track_a, track_b), where track_a and track_b don't use equivalent data, and aren't even synchronized in terms of group ids?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what If I'm a user, and I request switch(track_a, track_b), where track_a and track_b don't use equivalent data, and aren't even synchronized in terms of group ids?

Good point. There should probably be a constraint on the two tracks in a SWITCH, to disallow this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what If I'm a user, and I request switch(track_a, track_b), where track_a and track_b don't use equivalent data, and aren't even synchronized in terms of group ids?

It is the subscriber's responsibility to know that these two tracks are switchable (for example, as part of a CMAF switching set). Being a CMAF switching set, it has sufficient requirements to ensure a seamless switch. If you are not aiming for such a seamless switch, then just use sub/unsub.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what If I'm a user, and I request switch(track_a, track_b), where track_a and track_b don't use equivalent data, and aren't even synchronized in terms of group ids?

Good point. There should probably be a constraint on the two tracks in a SWITCH, to disallow this.

The relay does not need to check whether these two tracks are actually "switchable." The group IDs may not be aligned for different reasons and if the relay cannot complete the switch, it will return an error anyway. So, I don't think there is a need for a "disallow" check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what If I'm a user, and I request switch(track_a, track_b), where track_a and track_b don't use equivalent data, and aren't even synchronized in terms of group ids?

Good point. There should probably be a constraint on the two tracks in a SWITCH, to disallow this.

The relay does not need to check whether these two tracks are actually "switchable." The group IDs may not be aligned for different reasons and if the relay cannot complete the switch, it will return an error anyway. So, I don't think there is a need for a "disallow" check.

Indeed, we can add some wording to say that if the Relay fails to identify a next common boundary group between the two tracks, it can return an Error. Note that this could be leveraged by those who do not want to implement SWITCH to just reply negatively to any SWITCH message, even if these tracks are switchable.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we later say the mechanism achieves a continuous sequence of groups, I think we should spell out that tracks with equivalent content need to have aligned group IDs.

the current Track and the target Track and requests a transition at a suitable
Group boundary. This allows the subscriber to join the new Track without gaps
or duplication in the delivered object sequence.

#### Coordinated Track Switching for Adaptive Bitrate Streaming
Client-side Adaptive bitrate (ABR) streaming requires a subscriber to
transition between two Tracks that represent alternative formats of the same
content. The subscriber knows which Tracks are alternatives, based on
information such as catalog metadata or an out-of-band manifest.

To request a switch, the subscriber sends a SWITCH (see {{message-switch}})
identifying the Track it is currently receiving and the Track it intends to
receive next. The subscriber determines both Tracks locally and
does not rely on the Relay or publisher to infer ABR intent from subscription
patterns.

When a Relay receives a SWITCH message, it SHOULD NOT forward it upstream.
Instead, the Relay SHOULD performs the transition locally, preparing the
subscription for the new Track and determining the point at which to stop
forwarding objects from the old Track and begin forwarding objects from the
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is implicit here that the new track is assumed to have forward state =0, and that it will change to forward=1 at the switch point, without a forward=1 flag sent in the subscribe message. It may be worth pointing out this detail.

For the old track, it is desribed later on that that forward will be set to 0.

new one (see {{relay-switch}}).

Using SWITCH, the subscriber triggers an atomic transition that preserves a
continuous sequence of Groups and Objects across Tracks. This avoids the
coordination difficulties that arise when attempting to combine SUBSCRIBE,
SUBSCRIBE_UPDATE, and UNSUBSCRIBE messages to perform a Track switch.

#### Dynamically Starting New Groups

While some publishers will deterministically create new Groups, other
Expand Down Expand Up @@ -1546,6 +1576,50 @@ A relay MUST treat the object payload as opaque. A relay MUST NOT
combine, split, or otherwise modify object payloads. A relay SHOULD
prioritize sending Objects based on {{priorities}}.

## Relay Processing of SWITCH {#relay-switch}

A Relay that receives SWITCH is responsible for carrying out the transition
locally and SHOULD NOT forward the SWITCH message upstream. The Relay uses
the information supplied by the subscriber to prepare the subscription for
the new Track and to determine the appropriate transition point.

Upon receiving a SWITCH message, the Relay MUST first validate that the Old
Request ID identifies an Established subscription. If no such subscription
exists, the Relay MUST send a REQUEST_ERROR for the New Request ID and MUST
NOT modify any existing subscription state.

If the New Request ID corresponds to an existing Established subscription
for the target Track, the Relay reuses that subscription. Otherwise, the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the new request id corresponds to an existing established subscription, isn't it possible that the relay may need to send a SUBSCRIBE_UPDATE in order to broaden the range of that subscription? This could happen if, for instance, the SWITCH statement has a SUBSCRIPTION_FILTER that is broader than any existing subscriptions being made to the relay.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the answer is yes. It is also possible that the SWITCH has a SUBSCRIPTION_FILTER that is narrower, in which case an SUBSCRIBE_UPDATE is also needed (to narrow the range of that subscription).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the procedure here is the same as for a new received subscription, with aggregation of subscription. It is detailed here (Sec 8.4). We should change the wording to link to this section.

Relay creates a new upstream subscription using the Track Namespace, Track
Name, and authorization information provided in the SWITCH message. When
preparing this upstream subscription, the Relay applies the union of the
parameters associated with the old subscription and those carried in the
SWITCH message; in case of conflict, the values provided in the SWITCH
message take precedence. This rule applies to all subscription parameters,
including Subscriber Priority. The Relay performs this upstream action
independently of the subscriber.

The Relay selects a transition point G_switch, defined as the next available
common Group boundary shared by the old and new Tracks according to the
temporal alignment of those Tracks. A boundary is considered available if the
Relay already possesses the corresponding Group of the new Track, either from
cache or from upstream delivery. Up to G_switch, the Relay forwards Objects
from the old Track according to its natural temporal order; starting at G_switch
, it forwards Objects from the new Track. At G_switch itself, the Relay MUST
forward Objects from at most one Track to avoid gaps or duplicate content.
A Relay MAY use more advanced techniques (such as retrieving earlier Groups of
the new Track) to enable earlier transition points and further reduce switching
latency.

When the Relay has prepared the new subscription and determined the transition
point, it MUST send SUBSCRIBE_OK for the New Request ID. After the transition
at G_switch completes, the Relay handles the old subscription according to the
close-after-switch flag in the SWITCH message (see {{message-switch}}). If
close-after-switch is 1, the Relay MUST terminate the old subscription by
sending a PUBLISH_DONE for the Old Request ID. If close-after-switch is 0, the
Relay MUST keep the old subscription active and set its Forward state to 0, and
it MUST NOT close or implicitly expire that subscription.

# Control Messages {#message}

MOQT uses a single bidirectional stream to exchange control messages, as
Expand Down Expand Up @@ -1605,6 +1679,8 @@ The following Message Types are defined:
| 0x18 | FETCH_OK ({{message-fetch-ok}}) |
|-------|-----------------------------------------------------|
| 0x17 | FETCH_CANCEL ({{message-fetch-cancel}}) |
|-------|-----------------------------------------------------|
| 0x12 | SWITCH ({{message-switch}}) |
|-------|-----------------------------------------------------|
| 0xD | TRACK_STATUS ({{message-track-status}}) |
|-------|-----------------------------------------------------|
Expand Down Expand Up @@ -2879,6 +2955,92 @@ FETCH_CANCEL Message {
* Request ID: The Request ID of the FETCH ({{message-fetch}}) this message is
cancelling.

## SWITCH {#message-switch}

The SWITCH message allows a subscriber to request a coordinated transition
from one Track to another Track. A SWITCH operation is an atomic transition
that avoids gaps or duplicated objects across the two Tracks. The subscriber
identifies the Track it is currently receiving and the Track it intends to
receive next, and the Relay performs the transition as described in
{{relay-switch}}.

SWITCH Message {
Type (i) = 0x12,
Length (16),

Old Request ID (i),
New Request ID (i),

Track Namespace (...),
Track Name Length (i),
Track Name (...),

Auth Info Length (i),
Auth Info (...),

Close-After-Switch (i), ; 0 or 1

Number of Parameters (i),
Parameters (...) ...,
}


The fields of the SWITCH message are as follows:

* Old Request ID:
Identifies the Established subscription that is the source of objects prior
to the transition. If no such subscription exists, the receiver MUST send a
REQUEST_ERROR for the New Request ID and MUST NOT modify any subscription
state.

* New Request ID:
Identifies the subscription that will deliver objects after the transition.
This Request ID MUST either refer to an existing Established subscription
for the target Track, or be unused, in which case the receiver creates a new
subscription for the Track.

* Track Namespace and Track Name:
Identify the target Track, encoded as in SUBSCRIBE. These determine the
Track that will be used after the transition.

* Auth Info Length and Auth Info:
Optional authorization information for the target Track. If Auth Info Length
is zero, the receiver MAY reuse the authorization information associated
with Old Request ID.

* Close-After-Switch:
A boolean indicating how the Relay handles the old subscription after
the transition at G_switch completes. If flag is 1, the old subscription
MUST be terminated, and the receiver MUST send a PUBLISH_DONE for Old
Request ID. If flag is 0, the old subscription MUST remain active, its
Forward state MUST be set to 0, and the receiver MUST NOT close or
implicitly expire it.

* Parameters:
Version-specific subscription parameters encoded as in SUBSCRIBE. The
receiver MUST construct the upstream subscription for the New Request ID
using the union of the parameters from the Old Request ID and the
parameters present in the SWITCH message. If both specify a value for the
same parameter, the value in the SWITCH message MUST take precedence.

Upon receiving SWITCH, the receiver prepares the subscription associated
with New Request ID and selects a transition point as described in
{{relay-switch}}.

When the receiver has prepared the new subscription and selected the
transition point, it MUST send SUBSCRIBE_OK for New Request ID.

After the transition at G_switch completes, the receiver handles Old Request ID
according to the value of Close-After-Switch, as described above.

If the SWITCH request cannot be honored, the receiver MUST send a REQUEST_ERROR
for New Request ID and MUST NOT alter the behavior of the subscription
associated with Old Request ID.

A Relay that receives SWITCH perform the transition locally and SHOULD
NOT forward the SWITCH message upstream.


## TRACK_STATUS {#message-track-status}

A potential subscriber sends a `TRACK_STATUS` message on the control
Expand Down