Repository navigation
Conversation
…am model Draft 21 keeps draft 18's unified SETUP, uni control pair and per-request bidi streams. DraftVersion gains 21 and isRequestStreamDraft() (18 and later) replaces the raw draft-18 checks in the session, adapter, player, topology and examples, so draft 21 inherits the draft-18 behavior. The draft-18 control and data codecs take their version, moqt-21 maps to 21, and the browser, playa, player and example types accept it. The draft-21 message changes follow.
…ectors The draft-21 codec is the draft-18 one with its own parameter table (LOCATION_FILTER 0x21, FILL_PARAMETERS 0x23, the range filters 0x25-0x29, INCLUDE_PROPERTIES 0x35) and the draft-21 message changes: FETCH carries its range as a LOCATION_FILTER (a StandaloneFetch maps onto it; there is no Joining FETCH), GOAWAY has no Request ID, and PUBLISH_STATE_NOTIFY (0x22) is new. On draft 21 the 0x21 subscription filter is a LOCATION_FILTER, with RelativeStart and an inclusive AbsoluteRange end object added to the model; encodeFillParameters builds FILL_PARAMETERS. RequestError21 and SessionError TOO_MANY_REQUEST_UPDATES are added. vectors/d21 holds the draft-21 wire vectors shared with red5-moq-relay and produced or verified with moqxr; every control vector round-trips.
…STATE_NOTIFY Draft 21 validates message parameters against its own scope table (the same matrix as red5-moq-relay): PUBLISH_OK carries only EXPIRES, LOCATION_FILTER also rides FETCH and PUBLISH_STATE_NOTIFY, FILL_PARAMETERS, the range filters (which may repeat) and INCLUDE_PROPERTIES are known. A control-stream GOAWAY no longer needs a Request ID. SubscribeOptions.fill sends FILL_PARAMETERS and marks the subscription as expecting a fill stream. PUBLISH_STATE_NOTIFY advances the subscription's Largest Location; one crossing our cancellation is ignored.
Route a FETCH_HEADER carrying a fill-requesting SUBSCRIBE's Request ID as that subscription's fill stream (one per request; FIN completes it without finishing the SUBSCRIBE). cancelFill discards a pending or open fill. PUBLISH_STATE_NOTIFY is accepted on an established SUBSCRIBE stream and refused elsewhere. The request-stream topology and adapter now pick the control and data codecs by the negotiated draft instead of always 18, and fetch flag 0x20C (End of Timed-Out Range) is accepted on draft 21. subscribeTrack passes the fill option through.
The FETCH End of Range marker (0x8C / 0x10C, and 0x20C on draft 21) ends after its Group ID and Object ID. moxygen, LibMoQ and red5-moq-relay all encode it that way, as does the shared draft-21 vector fetch_object_end_of_timed_out_range_g2_o4; Playa wrote and required a trailing zero length, so it misread their markers and they misread its. Applies to drafts 16, 18 and 21. The LibMoQ fetch_eor_* vectors now pass and the draft-18 fetch_eor.bin golden vector is regenerated.
Draft 21 has no Joining FETCH. On 21 the catalog SUBSCRIBE (and a staged recovery candidate's) carries FILL_PARAMETERS for the current group, and the fill fetch stream, which carries the SUBSCRIBE's Request ID, is the MSF-01 prefix: there is no FETCH_OK, so the coordinator's FETCH_OK gate is satisfied when the fill is registered and the FIN completes it. Retiring a fill cancels the fill, never the subscription. Warm start asks for a fill on the media SUBSCRIBE instead of a joining FETCH. PUBLISH_DONE 0x3 (SUBSCRIPTION_ENDED) no longer exists on 21 and is treated as unknown. LOC uses the draft-18 property wire profile on 21. MoqtConnection.openFillStream serves a fill on the publisher side, used by the new draft-21 player loopback test.
…an empty catalog A fill range never extends past Largest Object and one that starts after it opens no fill stream (draft-21 section 3.4), so a catalog SUBSCRIBE_OK without LARGEST_OBJECT means no fill will arrive. Resolve the attempt as an empty track, as INVALID_RANGE does for a Joining FETCH, so the first live head completes the bootstrap instead of the attempt timing out into the fallback ladder.
…21 over native QUIC MAX_REQUEST_UPDATES (section 9.1.7): SetupOptions.maxRequestUpdates is advertised on draft 21, requestUpdate() never exceeds the peer's limit of unanswered updates on one request, and a peer that queues more than ours on a pending SUBSCRIBE closes the session with TOO_MANY_REQUEST_UPDATES. Fills on REQUEST_UPDATE (section 3.4): requestUpdate() takes a fill option. The session tracks every expected fill by the Request ID that asked for it, so a fill stream carrying a REQUEST_UPDATE's Request ID reaches its subscription, a refused update opens none, and cancelFill() on a subscription stops all of its fills. The publisher side accepts FILL_PARAMETERS on an inbound update (openFillStream with the update's Request ID) and resets a subscription's update fills when it ends. @moqt/quic takes draft: 18 | 21 and offers moqt-21 for 21; the adapter selects the session draft from the negotiated ALPN.
… Aliases Draft 21 drops the one-subscription-per-track rule (DUPLICATE_SUBSCRIPTION is gone, section 3.1), so the session admits concurrent SUBSCRIBEs and PUBLISHes for a track on 21. A publisher may give such subscriptions one Track Alias; the subscriber re-applies each subscription's filter. The adapter now keeps every subscribeTrack() sharing an alias in a group: an object reaches each member whose window (its filter resolved against SUBSCRIBE_OK's Largest Object) contains it, once per member, and one member's unsubscribe, peer close or PUBLISH_DONE detaches it without tearing down the alias the others still use. subscriptionWindow() and windowContains() resolve and test a filter's Location window.
The broadcast media publisher refused draft 21 before publishing. Its draft-dependent behavior already follows the draft-18 stream model on 21 (FIRST_OBJECT subgroup bit, draft-18 LOC wire profile), so 21 joins the supported list.
Collaborator
|
Thanks! Your commits (and some of my updates) are now in feature/draft-21. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds MOQT draft 21 (
0xff000015, ALPN / WebTransport protocolmoqt-21) next to drafts 14, 16 and 18. Draft 21 keeps the draft-18 stream model (unified SETUP, one bidirectional stream per request, vi64 integers), so it rides on the draft-18 codec and topology with version checks where the wire or the rules differ.new MoqtConnection(21)ordraftVersion: 21opts in; a negotiatedmoqt-21is detected like the other tokens.Playback works end to end at draft 21 against red5-moq-relay with moqxr publishing (see Testing).
@moqt/transportDraftVersionincludes 21.isRequestStreamDraft()replaces the=== 18checks, andisDraft21()gates what is new.SubscriptionFiltergainsRelativeStartand an inclusiveAbsoluteRange.endObject.vectors/d21/. Every control vector decodes and re-encodes byte for byte.SetupOptions.maxRequestUpdates, and the peer's limit is never exceededsubscriptionWindow()/windowContains()resolve a filter against the Largest Object@moqt/webtransportonDataStreamreports it withfill: true.cancelFill()stops one fill, or every fill of a subscription, without touching the subscription.openFillStream()serves a fill for a SUBSCRIBE or a REQUEST_UPDATE, and ending the subscription resets its fills.subscribeTrack()subscriptions that share an alias each get the objects their own filter selects, once each. Ending one of them (unsubscribe, peer close or PUBLISH_DONE) leaves the others running.@moqt/playerLOCATION_FILTER [1]) as a fill on the catalog SUBSCRIBE, instead of sending a Joining FETCH. The fill is the prefix.Examples
@moqt/quicconnectQuic(uri, { draft: 21 })offersmoqt-21. The adapter selects the session draft from the negotiated ALPN.Fix for all drafts: End-of-Range markers
FETCH End-of-Range markers (0x8C / 0x10C, and 0x20C on 21) end after the Object ID; they have no Object Payload Length. moxygen, LibMoQ and red5-moq-relay all encode them that way, and so does the shared draft-21 vector. Playa wrote and required a trailing zero length, so it misread their markers and they misread Playa's. Figure 28 of the draft leaves the length unbracketed, so the draft text on its own is ambiguous; this follows the other implementations. Because of this fix, the LibMoQ
fetch_eor_*vectors now pass. The draft-18fetch_eor.bingolden vector is regenerated.Testing
pnpm -r build,pnpm -r typecheck,npx vitest run: 227 files, 6154 tests passing.e2e/moqxr-playa, moqxr publishing atmoqt-21through the relay to a Playa subscriber atmoqt-21):run.sh: moqxr -> relay -> Playa subscriber. Playa takes the catalog from the SUBSCRIBE fill when the track already has content; when it is still empty at SUBSCRIBE, the catalog comes on the subscription itself.run-cluster.sh: moqxr -> origin relay -> edge relay -> Playa. The relays peer over native QUIC atmoqt-21.run-playa-loc.sh: Playa's broadcast LOC publisher -> relay -> Playa subscriber. Every media object is LOC-verified.run-backpressure.sh: a slow-link Playa viewer is cut with PUBLISH_DONE TOO_FAR_BEHIND (0x5 on draft 21) and recovers by resubscribing.Not in this PR
@moqt/webtransportand has no draft 21 yet.This change is