diff --git a/docs/moq/_category_.json b/docs/moq/_category_.json new file mode 100644 index 00000000..3abe1549 --- /dev/null +++ b/docs/moq/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "MoQ", + "customProps": { + "topNavSection": "moq" + } +} diff --git a/docs/moq/concepts/_category_.json b/docs/moq/concepts/_category_.json new file mode 100644 index 00000000..74b831d1 --- /dev/null +++ b/docs/moq/concepts/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Concepts", + "position": 2, + "collapsed": false +} diff --git a/docs/explanation/moq-streaming.mdx b/docs/moq/concepts/moq-with-fishjam.mdx similarity index 88% rename from docs/explanation/moq-streaming.mdx rename to docs/moq/concepts/moq-with-fishjam.mdx index 18133b80..c70b049b 100644 --- a/docs/explanation/moq-streaming.mdx +++ b/docs/moq/concepts/moq-with-fishjam.mdx @@ -1,11 +1,11 @@ --- type: explanation -sidebar_position: 6 -title: Media over QUIC (MoQ) +sidebar_position: 1 +title: MoQ with Fishjam 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 +# MoQ with Fishjam _How Media over QUIC (MoQ) works in Fishjam_ @@ -22,7 +22,7 @@ A few properties make MoQ stand out: - **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. +Fishjam also supports WebRTC-based livestreaming (WHIP/WHEP). See [Livestreams](../../explanation/livestreams) for that approach. ::: ## How MoQ Works in Fishjam @@ -116,7 +116,7 @@ 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. +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?](../../explanation/sandbox-api-concept) for more context. ### Fishjam Server SDK (production) @@ -129,11 +129,11 @@ The SDK's `createMoqToken` method accepts either a `publishPath` or a `subscribe 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 the [Web Publishing](../tutorials/web-publishing) and [Web Subscribing](../tutorials/web-subscribing) tutorials (or their [React Native](../tutorials/react-native-publishing) [counterparts](../tutorials/react-native-subscribing)) for working code examples. ## 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 +- [Web Publishing](../tutorials/web-publishing) / [Web Subscribing](../tutorials/web-subscribing) — step-by-step guides to publishing and subscribing +- [What is the Sandbox API?](../../explanation/sandbox-api-concept) — when and why to use the Sandbox API +- [Security & Token Model](../../explanation/security-tokens) — broader overview of Fishjam's token system +- [Livestreams](../../explanation/livestreams) — WebRTC-based livestreaming with WHIP/WHEP diff --git a/docs/moq/tutorials/_category_.json b/docs/moq/tutorials/_category_.json new file mode 100644 index 00000000..e0472874 --- /dev/null +++ b/docs/moq/tutorials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Tutorials", + "position": 1, + "collapsed": false +} diff --git a/docs/moq/tutorials/react-native-publishing.mdx b/docs/moq/tutorials/react-native-publishing.mdx new file mode 100644 index 00000000..5c9629bb --- /dev/null +++ b/docs/moq/tutorials/react-native-publishing.mdx @@ -0,0 +1,230 @@ +--- +type: tutorial +sidebar_position: 3 +title: React Native Publishing +description: Publish a live video and audio broadcast over Media over QUIC (MoQ) from a React Native mobile app with Fishjam, from sandbox prototyping to production. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# React Native Publishing + +This tutorial explains how to **publish** a live stream from a **React Native mobile app** using [Media over QUIC (MoQ)](https://datatracker.ietf.org/wg/moq/about/) with Fishjam. To watch a stream instead, see [React Native Subscribing](./react-native-subscribing). + +It uses [`react-native-moq`](https://github.com/software-mansion-labs/react-native-moq) — React Native bindings for MoQKit, with a small, reactive hooks-based API. For the web equivalent, see [Web Publishing](./web-publishing). + +:::info +If you're new to MoQ, then we recommend getting familiar with the [MoQ with Fishjam](../concepts/moq-with-fishjam) explanation. +::: + +## Requirements + +`react-native-moq` targets the React Native **New Architecture** (Fabric / TurboModules): + +- iOS 16+ +- Android API 30+ + +## Installation + +```bash npm2yarn +npm install react-native-moq +``` + +Then install the iOS pods: + +```sh +cd ios && pod install +``` + +Publishing captures the camera and microphone, so the host app is responsible for runtime permissions: request `CAMERA` / `RECORD_AUDIO` on Android, and add `NSCameraUsageDescription` / `NSMicrophoneUsageDescription` to `Info.plist` on iOS. The library does not request these for you. + +:::tip +MoQ is a protocol with a well-defined negotiation, so a publisher and a subscriber don't need to use the same client library. A React Native app published with `react-native-moq` can be watched in the browser with [`@moq/watch`](./web-subscribing#connecting-and-subscribing), and vice versa. +::: + +## Quickstart with the Sandbox API + +If you don't have a backend server set up, you can prototype publishing using the [Sandbox API](../../explanation/sandbox-api-concept). + +### Obtaining a publisher token + +For more on what the Sandbox API is and its limitations, see [What is the Sandbox API?](../../explanation/sandbox-api-concept). + +:::info +To obtain a MoQ token you'll need your Fishjam ID and Sandbox API URL. If you don't have them already, see [Sandbox API URL and Fishjam ID](../../explanation/sandbox-api-concept#sandbox-api-url-and-fishjam-id). +::: + + + + + The `useSandbox` hook from `@fishjam-cloud/react-native-client` wraps the Sandbox API request for you: + + ```tsx + // @noErrors + import { useSandbox } from "@fishjam-cloud/react-native-client"; + + const FISHJAM_ID = "YOUR_FISHJAM_ID"; + const PUBLISHER_PATH = "stream-alice"; + const SANDBOX_API_URL = "YOUR_SANDBOX_API_URL"; + + // Inside a React component: + const { getSandboxMoqPublisherToken } = useSandbox({ + sandboxApiUrl: SANDBOX_API_URL, + }); + + // Request a publisher token scoped to the publisher path + const publishToken = await getSandboxMoqPublisherToken(PUBLISHER_PATH); + ``` + + + + + + If you don't want to pull in the whole client library just for the `useSandbox` hook, you can call the Sandbox API directly with `fetch`: + + ```ts + // @noErrors + const FISHJAM_ID = "YOUR_FISHJAM_ID"; + const PUBLISHER_PATH = "stream-alice"; + const SANDBOX_API_URL = "YOUR_SANDBOX_API_URL"; + + const response = await fetch( + `${SANDBOX_API_URL}/moq/${PUBLISHER_PATH}/publisher`, + ); + const { token: publishToken } = await response.json(); + ``` + + + + +### Connecting and publishing + +`react-native-moq` is hooks-based. You open a session against the relay, capture the camera and microphone, and hand them to a publisher. + +Build the relay URL using the publisher token, open the session, and publish the camera + microphone tracks: + +```tsx +// @noErrors +import { useEffect } from "react"; +import { Button, PermissionsAndroid, Platform } from "react-native"; +import { + PublisherView, + useCamera, + useMicrophone, + usePublisher, + useSession, +} from "react-native-moq"; + +const FISHJAM_ID = "YOUR_FISHJAM_ID"; +const PUBLISHER_PATH = "stream-alice"; +const publishToken = ""; // from the step above + +// Build the relay URL using the publisher token +const relayUrl = `https://relay.fishjam.io/${FISHJAM_ID}?jwt=${publishToken}`; + +function PublishScreen() { + // Open the MoQ session against the Fishjam relay + const session = useSession(relayUrl, (s) => s.connect()); + const camera = useCamera({ position: "front" }); + const microphone = useMicrophone(); + const publisher = usePublisher(session); + + // Request camera + mic permissions on Android (iOS handles it automatically when Info.plist is configured) + useEffect(() => { + if (Platform.OS === "android") { + PermissionsAndroid.requestMultiple([ + PermissionsAndroid.PERMISSIONS.CAMERA, + PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, + ]); + } + }, []); + + const isPublishing = publisher.state === "publishing"; + + return ( + <> + +