This document describes the message sequence for publishing a track and automatic internal subscription in the red5-moq-relay server.
%%{init: {'theme':'base', 'themeVariables': {'fontSize':'16px', 'fontFamily':'arial'}}}%%
sequenceDiagram
participant Publisher as Publisher Client
participant Control as MoQ Control Handler
participant Relay as MoqRelayManager
participant Internal as RecordingInternalSubscriber
participant Data as MoQ Data Handler
Note over Publisher,Internal: Phase 1: Session Setup (not shown)
Note over Publisher,Internal: CLIENT_SETUP ↔ SERVER_SETUP exchange
rect rgb(120, 160, 220)
Note over Publisher,Internal: Phase 2: Namespace/Track Publication
Publisher->>Control: PUBLISH_NAMESPACE(namespace="red5")
Control->>Relay: registerPublishedNamespace()
Relay-->>Internal: onNamespacePublished() notification
Control->>Publisher: PUBLISH_NAMESPACE_OK
Publisher->>Control: PUBLISH(trackNamespace="red5", trackName="catalog", alias=555704345)
Control->>Relay: onTrackPublished(track)
Relay-->>Internal: onTrackAvailable() notification
Note right of Internal: Creates recording file<br/>red5_catalog_*.moq
Control->>Publisher: PUBLISH_OK(alias=555704345, forward=1)
end
rect rgb(230, 160, 100)
Note over Publisher,Internal: Phase 3: Internal Subscriber Triggers Data Flow
Internal->>Relay: subscribeToTrack(track)
Relay->>Control: sendSubscribeToPublisher()
Control->>Publisher: SUBSCRIBE(id=2000006, namespace="red5", track="catalog", filter=LATEST_GROUP)
Note right of Publisher: Publisher prepares to send data
Publisher->>Control: SUBSCRIBE_OK(id=2000006, alias=555704345)
end
rect rgb(100, 190, 170)
Note over Publisher,Internal: Phase 4: Data Delivery
Publisher->>Data: Open unidirectional stream (stream_id=2)
Publisher->>Data: SUBGROUP_HEADER(type=SUBGROUP_ZERO_ID, alias=1, group=4, subgroup=0)
Note right of Data: Auto-creates track if needed<br/>based on namespace subscription
Publisher->>Data: OBJECT(objectIdDelta=0, payload=128426 bytes)
Data->>Relay: relayObject(object)
Relay->>Internal: handleObject(object)
Note right of Internal: Writes object to recording:<br/>group=4, object=1, 128426 bytes
Publisher->>Data: OBJECT(objectIdDelta=0, payload=5120 bytes)
Data->>Relay: relayObject(object)
Relay->>Internal: handleObject(object)
Note right of Internal: Writes to recording:<br/>group=4, object=2, 5120 bytes
end
rect rgb(200, 150, 220)
Note over Publisher,Internal: Phase 5: Additional Tracks
Publisher->>Control: PUBLISH(trackName="track-1", alias=1)
Control->>Relay: tryAutoCreateTrackFromNamespaceSubscription()
Note right of Relay: Auto-creates track from<br/>announced namespace
Relay-->>Internal: onTrackAvailable() notification
Control->>Publisher: PUBLISH_OK(alias=1, forward=1)
Internal->>Relay: subscribeToTrack("track-1")
Relay->>Control: sendSubscribeToPublisher()
Control->>Publisher: SUBSCRIBE(id=2000007, track="track-1", filter=LATEST_GROUP)
Publisher->>Control: SUBSCRIBE_OK(id=2000007, alias=1)
Note over Publisher,Data: Data delivery continues as in Phase 4
end
- CLIENT_SETUP: Publisher initiates session with supported versions and role
- SERVER_SETUP: Server responds with negotiated version (e.g., draft-14)
Message Type: 0x06
Track Namespace Prefix: tuple["red5"]
Parameters: 0
Message Type: 0x07
Track Namespace Prefix: tuple["red5"]
Message Type: 0x1D
Request ID: 8 (varint)
Track Namespace: tuple["red5"]
Track Name: "catalog" (length-prefixed string)
Track Alias: 555704345 (varint)
Subscriber Priority: 128 (u8)
Group Order: ASCENDING (0x01)
Forward: 1 (u8) - how many hops to forward subscription requests
Filter Type: LATEST_GROUP (0x01)
Parameters: 0
Message Type: 0x1E
Request ID: 8 (varint)
Track Alias: 555704345 (varint) - NOT included in response (already known)
Forward: 1 (u8)
Publisher Priority: 128 (u8)
Group Order: ASCENDING (0x01)
Filter Type: LATEST_GROUP (0x01)
Parameters: 0
Message Type: 0x03
Subscribe ID: 2000006 (varint) - unique ID for this subscription
Track Namespace: tuple["red5"]
Track Name: "catalog" (length-prefixed string)
Subscriber Priority: 128 (u8)
Group Order: PUBLISHER_PREFERENCE (0x00)
Filter Type: LATEST_GROUP (0x01)
Parameters: 0
Note: Draft-14 removed the Forward field from SUBSCRIBE. It only exists in PUBLISH/PUBLISH_OK.
Message Type: 0x04
Subscribe ID: 2000006 (varint)
Expires: 0 (varint) - no expiration
Group Order: ASCENDING (0x01)
Content Exists: true (0x01)
Largest Group ID: 4 (varint, optional)
Largest Object ID: 1 (varint, optional)
Stream Type: SUBGROUP_ZERO_ID (0x10)
Track Alias: 1 (varint)
Group ID: 4 (varint)
Subgroup ID: 0 (implicitly 0 for type 0x10)
Publisher Priority: 0 (u8)
Subgroup Header Types (draft-14 Section 10.4.2):
0x10: SUBGROUP_ZERO_ID - subgroup ID = 0, no extensions0x11: SUBGROUP_ZERO_ID_EXT - subgroup ID = 0, with extensions0x12: SUBGROUP_FIRST_OBJECT_ID - subgroup ID = first object's ID0x14: SUBGROUP_ID - explicit subgroup ID field0x18-0x1D: Same as above but with end-of-group marker
Object ID Delta: 0 (varint) - first object, so delta = absolute ID
Payload Length: 128426 (varint)
Payload: [128426 bytes]
Delta Encoding Rules (draft-14 Section 10.4.2):
- First object:
objectId = objectIdDelta - Subsequent objects:
objectId = previousObjectId + objectIdDelta + 1
Example:
Object 1: delta=0 → objectId = 0
Object 2: delta=0 → objectId = 0 + 0 + 1 = 1
Object 3: delta=1 → objectId = 1 + 1 + 1 = 3 (skipped object 2)
When a publisher sends data for a track not explicitly registered:
- Data arrives with unknown track alias
- Relay looks up announced namespaces for the publisher session
- Auto-creates track:
namespace="red5",trackName="track-{alias}" - Registers track in TrackRegistry
- Notifies internal subscribers (RecordingInternalSubscriber, etc.)
- Internal subscriber subscribes → Relay sends SUBSCRIBE to publisher
- Publisher responds with SUBSCRIBE_OK
- Data flows as normal
Central coordinator for:
- Registering published namespaces and tracks
- Managing subscriptions (both external and internal)
- Forwarding objects from publishers to subscribers
- Sending SUBSCRIBE messages to publishers for internal subscribers
Built-in subscribers that automatically subscribe to tracks:
-
RecordingInternalSubscriber
- Records all objects to
.moqfiles - Format:
recordings/{namespace}_{track}_{timestamp}.moq - Can be disabled via
recording.internal.subscriber.enabled=false
- Records all objects to
-
Other Internal Subscribers (future)
- Metrics collection
- Transcoding
- CDN replication
Control Stream (Bidirectional Stream 0 or 4):
- PUBLISH_NAMESPACE, PUBLISH, SUBSCRIBE, etc.
- Always bidirectional
- One per session
- For WebTransport: Stream 0 = HTTP/3 CONNECT handshake, Stream 4 = MoQ control
Data Streams (Unidirectional):
- SUBGROUP_HEADER + OBJECT messages
- One stream per subgroup (draft-14)
- Publisher-initiated
- Carries media payload
- Publisher announces track availability via PUBLISH instead of waiting for SUBSCRIBE
- Relay/subscriber can send SUBSCRIBE to request data delivery
- Enables "push" model where publisher controls when to start sending
- Replaces legacy STREAM_HEADER_TRACK and STREAM_HEADER_GROUP
- 12 variants (0x10-0x1D) encoding subgroup ID, extensions, and end-of-group
- Delta-encoded object IDs for efficiency
- SUBSCRIBE_NAMESPACE: Subscribe to all tracks under a namespace prefix
- Server automatically creates subscriptions when new tracks are published
- Simplifies subscription management for large track sets (e.g., conference rooms)
Internal subscribers can be configured in server.properties:
# Enable/disable recording internal subscriber
recording.internal.subscriber.enabled=true
# Recording output directory
recording.output.dir=recordings/
# Recording file format: moq, mp4, etc.
recording.format=moqIf track alias is unknown when data arrives:
- Relay attempts auto-creation from announced namespaces
- If no namespace announced → objects dropped + error logged
- If namespace exists → track auto-created as
namespace/track-{alias}
This auto-creation enables:
- Simplified publisher implementation (just send data with alias)
- Namespace-based authorization (announce namespace first, then send any track)
- Dynamic track discovery without pre-registration
- draft-ietf-moq-transport-14: Main MoQ Transport specification
- Section 9.13-9.15: PUBLISH/PUBLISH_OK/PUBLISH_ERROR messages
- Section 10.4.2: Subgroup stream format and delta encoding
- Section 9.7: SUBSCRIBE message format