-
Notifications
You must be signed in to change notification settings - Fork 41
SWITCH for Client-side ABR #1378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
7bdae34
f5802bf
42c05c5
907d55c
2a55d06
9f9c802
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
| 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 | ||
|
||
| 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 | ||
|
|
@@ -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 | ||
|
||
| 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 | ||
|
|
@@ -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}}) | | ||
| |-------|-----------------------------------------------------| | ||
|
|
@@ -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 | ||
|
|
||
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. There should probably be a constraint on the two tracks in a SWITCH, to disallow this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
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.