-
Notifications
You must be signed in to change notification settings - Fork 3
Add MoQ streaming tutorial to docs #252
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
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
6300a24
Add MoQ streaming tutorial to docs
Karolk99 537bd60
Format code snippets
Karolk99 46e5600
Fix MoQ tutorial reference
Karolk99 b0775dd
Add MoQ explanation section
Karolk99 78d33e6
Requested changes
Karolk99 d9f4e5d
Requested changes
Karolk99 3af1bb8
Fix build
Karolk99 d74531e
Requested changes
Karolk99 77cb5f8
Fix code snippets to work with the new sandboxAPI
Karolk99 36df4b5
Merge branch 'main' into fce-3167/add-moq-to-doc
Karolk99 a7957fd
Add remuxing to spelling.txt
Karolk99 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| --- | ||
| type: explanation | ||
| sidebar_position: 6 | ||
| title: MoQ Streaming | ||
| description: Understand how Media over QUIC (MoQ) works in Fishjam — the relay model, publish/subscribe architecture, paths, and token-based access control. | ||
| --- | ||
|
|
||
| # MoQ Streaming with Fishjam | ||
|
|
||
| _How Media over QUIC (MoQ) works in Fishjam_ | ||
|
|
||
| ## What is MoQ? | ||
|
|
||
| [Media over QUIC (MoQ)](https://datatracker.ietf.org/wg/moq/about/) is a new internet standard for live media delivery, designed from the ground up for **scalable, low-latency streaming to large audiences**. | ||
|
|
||
| Unlike WebRTC — which was primarily built for interactive, peer-to-peer conferencing — MoQ is optimized for the one-to-many broadcast model: one publisher, potentially thousands of simultaneous subscribers, all receiving the stream with minimal delay. | ||
|
|
||
| A few properties make MoQ stand out: | ||
|
|
||
| - **Built on QUIC.** QUIC is a modern transport protocol that eliminates head-of-line blocking, recovers from packet loss more gracefully than TCP, and establishes connections faster. For live video, this means more resilient delivery at low latency. | ||
| - **Standardized negotiation.** Because MoQ defines a common signaling and subscription protocol, any MoQ-compliant client can connect to any MoQ-compliant relay — you are not locked into a proprietary stack. | ||
| - **Relay-based architecture.** The relay is a first-class part of the MoQ protocol, not an add-on. Because relaying is built into the protocol's design, scaling delivery to large audiences is a native capability. | ||
|
|
||
| :::info | ||
| Fishjam also supports WebRTC-based livestreaming (WHIP/WHEP). See [Livestreams](./livestreams) for that approach. | ||
| ::: | ||
|
|
||
| ## How MoQ Works in Fishjam | ||
|
|
||
| Fishjam provides a **MoQ relay** that publishers push media to and subscribers pull media from. | ||
|
|
||
| ``` | ||
| Publisher → Fishjam MoQ Relay → Subscriber(s) | ||
| ``` | ||
|
|
||
| The relay is responsible for distributing the stream: it receives media from the publisher once and fans it out to every subscriber. | ||
|
|
||
| ### The publish/subscribe model | ||
|
|
||
| MoQ uses a **publish/subscribe** model: | ||
|
|
||
| - A **publisher** connects to the relay, announces a stream under a specific path, and starts sending media. | ||
| - **Subscribers** connect to the relay, discover announced paths, and receive the media. | ||
|
|
||
| The relay manages the flow between them. Neither side needs a direct connection to the other. | ||
|
|
||
| ### Paths | ||
|
|
||
| Every stream is identified by a **path** — a slash-separated string like `my-room/alice-camera`. Paths are used in two distinct ways: | ||
|
|
||
| 1. **Addressing** — a subscriber consumes an exact path to receive that specific stream (e.g. `my-room/alice-camera`). | ||
| 2. **Discovery** — a subscriber watches a prefix (e.g. `my-room`) to learn which streams are currently live under it. This returns a live feed of announced paths — each of which must then be consumed individually. This is how you can display all participants in a room without knowing their paths in advance. | ||
|
|
||
| Note that consuming an exact path and discovering a prefix are separate operations. Consuming `my-room` directly would fail unless a publisher is broadcasting at that exact path. | ||
|
|
||
| ### Path Scoping | ||
|
|
||
| Every connection goes to `relay.fishjam.io/<fishjam-id>`. Your Fishjam ID is automatically used as the token's root namespace by the Fishjam Server — you never include it in `publishPath` or `subscribePath`; it is set for you. All paths you specify are **relative to that root**. | ||
|
|
||
| Path matching is **prefix-based**: a path of `"stream-name"` permits any broadcast whose full path starts with `stream-name/`, not just the exact string `"stream-name"`. | ||
|
|
||
| #### Publisher paths | ||
|
|
||
| The `publishPath` you set determines how much freedom the broadcaster has when naming their broadcast: | ||
|
|
||
| - **Broad path** (`publishPath: "stream-name"`) — the client can publish as any sub-path under `stream-name`, such as `stream-name/alice` or `stream-name/bob-camera`. The client chooses its own identity; the relay only enforces the prefix. | ||
| - **Specific path** (`publishPath: "stream-name/alice"`) — the client can **only** publish as `stream-name/alice`. If the broadcaster tries to use `stream-name/bob`, the relay rejects the announcement. This is how you enforce a broadcaster's identity from the server side. | ||
|
|
||
| Use the broad form when clients self-identify (e.g., users pick their own stream name). Use the specific form when your backend assigns identities (e.g., you issue a per-user token for a managed conference). | ||
|
|
||
| #### Subscriber paths | ||
|
|
||
| The `subscribePath` works the same way: it is a prefix that limits which broadcasts the subscriber can consume and discover. | ||
|
|
||
| - **Broad path** (`subscribePath: "stream-name"`) — the subscriber can consume any broadcast under `stream-name/` and will surface all publishers in that namespace as they come and go. | ||
| - **Specific path** (`subscribePath: "stream-name/alice"`) — the subscriber can only receive from `stream-name/alice`. Broadcasts at `stream-name/bob` are invisible to this client. | ||
|
|
||
| #### Example: a multi-publisher room | ||
|
|
||
| A typical room setup uses a combination of both patterns: | ||
|
|
||
| 1. The backend issues each broadcaster a **specific** publisher token — `publishPath: "my-room/<user-id>"` — so each user can only occupy their own slot. | ||
| 2. The backend issues viewers a **broad** subscriber token — `subscribePath: "my-room"` — so they discover and consume every broadcast in the room. | ||
| 3. When a new publisher joins or leaves, the viewer is informed by the relay | ||
|
|
||
| ## Access Control: MoQ Tokens | ||
|
|
||
| Access to the relay is controlled by **MoQ tokens** — short-lived JWTs that are path-scoped: | ||
|
|
||
| | Token type | Grants | Typical recipient | | ||
| | ---------------- | ---------------------------------- | ----------------- | | ||
| | Publisher token | Write access to a specific path | Streamer | | ||
| | Subscriber token | Read access to a path or namespace | Viewer | | ||
|
|
||
| A token is attached to the relay URL as a query parameter (`?jwt=<token>`). The relay validates the token and enforces its scope before allowing any media to flow. | ||
|
Karolk99 marked this conversation as resolved.
|
||
|
|
||
| Keeping publisher and subscriber tokens separate ensures that a viewer can never accidentally publish to the stream, and a publisher cannot subscribe to paths it does not own. | ||
|
|
||
| ## Getting Tokens | ||
|
|
||
| There are two ways to obtain MoQ tokens, depending on where you are in the development lifecycle. | ||
|
|
||
| ### Sandbox API (prototyping) | ||
|
|
||
| The **Sandbox API** is a ready-made backend provided by Fishjam for development and prototyping. It issues tokens without requiring you to build your own server, so you can start streaming immediately. | ||
|
|
||
| To get a publisher token, call: | ||
|
|
||
| ``` | ||
| GET https://fishjam.io/api/v1/connect/{FISHJAM_ID}/room-manager/moq/{PUBLISHER-PATH}/publisher | ||
| ``` | ||
|
|
||
| To get a subscriber token, call: | ||
|
|
||
| ``` | ||
| GET https://fishjam.io/api/v1/connect/{FISHJAM_ID}/room-manager/moq/{SUBSCRIBER-PATH}/subscriber | ||
| ``` | ||
|
|
||
| The Sandbox API is **not intended for production** — it has no authentication and is only available in the Sandbox environment. See [What is the Sandbox API?](./sandbox-api-concept) for more context. | ||
|
|
||
| ### Fishjam Server SDK (production) | ||
|
|
||
| In production, your backend generates tokens using the **Fishjam Server SDK**. This gives you full control over who can publish and who can subscribe. | ||
|
|
||
| The SDK's `createMoqToken` method accepts either a `publishPath` or a `subscribePath`: | ||
|
|
||
| - `publishPath` — issues a publisher token scoped to that path. | ||
| - `subscribePath` — issues a subscriber token scoped to that path or namespace prefix. | ||
|
|
||
| Your backend then delivers each token to the appropriate client (publisher or viewer), which uses it to connect to the relay. | ||
|
|
||
| See the [MoQ Streaming tutorial](../tutorials/moq) for working code examples of both approaches. | ||
|
|
||
| ## See also | ||
|
|
||
| - [MoQ Streaming tutorial](../tutorials/moq) — step-by-step guide to publishing and subscribing | ||
| - [What is the Sandbox API?](./sandbox-api-concept) — when and why to use the Sandbox API | ||
| - [Security & Token Model](./security-tokens) — broader overview of Fishjam's token system | ||
| - [Livestreams](./livestreams) — WebRTC-based livestreaming with WHIP/WHEP | ||
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.