diff --git a/docs/explanation/data-channels.mdx b/docs/explanation/data-channels.mdx index bd559ec..31d5124 100644 --- a/docs/explanation/data-channels.mdx +++ b/docs/explanation/data-channels.mdx @@ -42,7 +42,22 @@ This separation allows you to use both channels simultaneously for different pur ## Using Data Channels -Use the [`useDataChannel`](../api/web/functions/useDataChannel) hook to work with data channels. The typical flow is: +Use the `useDataChannel` hook to work with data channels. The hook is available in both the web and mobile SDKs with the same API: + + + + +Use [`useDataChannel`](../api/web/functions/useDataChannel) from `@fishjam-cloud/react-client`. + + + + +Use [`useDataChannel`](../api/mobile/functions/useDataChannel) from `@fishjam-cloud/react-native-client`. + + + + +The typical flow is: 1. Initialize the data channel after connecting to a room 2. Subscribe to incoming messages diff --git a/docs/how-to/client/installation.mdx b/docs/how-to/client/installation.mdx index 14cf23d..9bfb5e9 100644 --- a/docs/how-to/client/installation.mdx +++ b/docs/how-to/client/installation.mdx @@ -77,23 +77,45 @@ You can also follow more detailed [Expo instructions](https://docs.expo.dev/get- ## Step 1: Install the Package -Install `@fishjam-cloud/react-native-client` with your preferred package manager. + + + + +Install `@fishjam-cloud/react-native-client` and `react-native-get-random-values` with your preferred package manager. + +```bash npm2yarn +npm install @fishjam-cloud/react-native-client react-native-get-random-values@1.11.0 +``` + +Expo SDK 54+ resolves native dependencies recursively, so `@fishjam-cloud/react-native-webrtc` (a transitive dependency) is autolinked automatically. + + + + +Install `@fishjam-cloud/react-native-client`, `@fishjam-cloud/react-native-webrtc`, and `react-native-get-random-values`: ```bash npm2yarn -npm install @fishjam-cloud/react-native-client +npm install @fishjam-cloud/react-native-client @fishjam-cloud/react-native-webrtc react-native-get-random-values@1.11.0 ``` +Bare React Native and Expo SDK versions below 54 only autolink direct dependencies. +`@fishjam-cloud/react-native-webrtc` must be in your app's `package.json` for its native code to be linked. + + + + ## Step 2: Configure App Permissions Your app needs to have permissions configured in order to use the microphone and camera. ### Android -These permissions are required to stream audio and video with Fishjam on Android: +The following Android permissions are required by Fishjam: - `android.permission.CAMERA` - `android.permission.RECORD_AUDIO` - `android.permission.MODIFY_AUDIO_SETTINGS` +- `android.permission.ACCESS_NETWORK_STATE` @@ -110,7 +132,8 @@ Add required permissions to the `app.json` file. "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } } @@ -128,6 +151,7 @@ Add required permissions to the `AndroidManifest.xml` file. + ... ``` diff --git a/docs/how-to/client/migration-guide.mdx b/docs/how-to/client/migration-guide.mdx index 270813b..891a6ec 100644 --- a/docs/how-to/client/migration-guide.mdx +++ b/docs/how-to/client/migration-guide.mdx @@ -24,7 +24,8 @@ Add the following WebRTC permissions to your Android configuration in `app.json` "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } } diff --git a/docs/how-to/features/text-chat.mdx b/docs/how-to/features/text-chat.mdx index 635f114..b979571 100644 --- a/docs/how-to/features/text-chat.mdx +++ b/docs/how-to/features/text-chat.mdx @@ -22,7 +22,7 @@ For a deeper understanding of how data channels work, including channel types an ## Step 1 — Set up the chat hook -Use the [`useDataChannel`](/api/web/functions/useDataChannel) hook to work with data channels. The typical flow is: +Use the [`useDataChannel`](/api/web/functions/useDataChannel) (web) or [`useDataChannel`](/api/mobile/functions/useDataChannel) (mobile) hook to work with data channels. The typical flow is: 1. Initialize the data channel after connecting to a room 2. Subscribe to incoming messages @@ -84,9 +84,67 @@ export function useChat() { ``` - + -Mobile SDK support for data channels will be available in a future release. +```tsx +import { + useConnection, + useDataChannel, +} from "@fishjam-cloud/react-native-client"; +import { useCallback, useEffect, useState } from "react"; + +export function useChat() { + const { peerStatus } = useConnection(); + const { + initializeDataChannel, + publishData, + subscribeData, + dataChannelReady, + dataChannelLoading, + dataChannelError, + } = useDataChannel(); + + const [messages, setMessages] = useState([]); + + useEffect(() => { + if (peerStatus === "connected") { + initializeDataChannel(); + } + }, [peerStatus, initializeDataChannel]); + + useEffect(() => { + if (dataChannelLoading || !dataChannelReady) return; + + const unsubscribe = subscribeData( + (data: Uint8Array) => { + const message = new TextDecoder().decode(data); + setMessages((prev) => [...prev, message]); + }, + { reliable: true }, + ); + + return unsubscribe; + }, [dataChannelReady, dataChannelLoading, subscribeData]); + + const sendMessage = useCallback( + (text: string) => { + if (!dataChannelReady) return; + + const encoded = new TextEncoder().encode(text); + publishData(encoded, { reliable: true }); + }, + [publishData, dataChannelReady], + ); + + return { + messages, + sendMessage, + ready: dataChannelReady, + loading: dataChannelLoading, + error: dataChannelError, + }; +} +``` @@ -185,9 +243,97 @@ function ChatPanel() { ``` - + + +```tsx +import React, { useState, useEffect, useCallback } from "react"; +import { View, Text, TextInput, FlatList, Pressable } from "react-native"; +import { + useConnection, + useDataChannel, +} from "@fishjam-cloud/react-native-client"; + +function useChat() { + const { peerStatus } = useConnection(); + const { + initializeDataChannel, + publishData, + subscribeData, + dataChannelReady, + } = useDataChannel(); + + const [messages, setMessages] = useState([]); + + useEffect(() => { + if (peerStatus === "connected") { + initializeDataChannel(); + } + }, [peerStatus, initializeDataChannel]); -Mobile SDK support for data channels will be available in a future release. + useEffect(() => { + if (!dataChannelReady) return; + + const unsubscribe = subscribeData( + (data: Uint8Array) => { + const message = new TextDecoder().decode(data); + setMessages((prev) => [...prev, message]); + }, + { reliable: true }, + ); + + return unsubscribe; + }, [subscribeData, dataChannelReady]); + + const sendMessage = useCallback( + (text: string) => { + if (!dataChannelReady) return; + + const encoded = new TextEncoder().encode(text); + publishData(encoded, { reliable: true }); + }, + [publishData, dataChannelReady], + ); + + return { messages, sendMessage, ready: dataChannelReady }; +} + +// ---cut--- + +function ChatPanel() { + const { messages, sendMessage, ready } = useChat(); + const [input, setInput] = useState(""); + + const handleSend = () => { + if (input.trim()) { + sendMessage(input); + setInput(""); + } + }; + + if (!ready) { + return Connecting to chat...; + } + + return ( + + String(i)} + renderItem={({ item }) => {item}} + /> + + + Send + + + ); +} +``` @@ -209,4 +355,5 @@ This ensures no chat messages are lost or arrive out of order. - [Data Channels](../../explanation/data-channels) — detailed explanation of channel types and broadcast behavior - [Connecting to a room](../../how-to/client/connecting) — prerequisite for using data channels -- [`useDataChannel` API reference](../../api/web/functions/useDataChannel) +- [`useDataChannel` API reference (Web)](../../api/web/functions/useDataChannel) +- [`useDataChannel` API reference (Mobile)](../../api/mobile/functions/useDataChannel) diff --git a/docs/tutorials/react-native-quick-start.mdx b/docs/tutorials/react-native-quick-start.mdx index 722b430..c3e845b 100644 --- a/docs/tutorials/react-native-quick-start.mdx +++ b/docs/tutorials/react-native-quick-start.mdx @@ -53,7 +53,8 @@ Add required permissions to the `app.json` file: "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } } diff --git a/packages/web-client-sdk b/packages/web-client-sdk index b73a7b1..2b23a8f 160000 --- a/packages/web-client-sdk +++ b/packages/web-client-sdk @@ -1 +1 @@ -Subproject commit b73a7b1d96c4a63909b2bb641aa3285b51a01999 +Subproject commit 2b23a8fa8f8da3ccee29eb2093031fa6a2943286 diff --git a/versioned_docs/version-0.25.0/explanation/data-channels.mdx b/versioned_docs/version-0.25.0/explanation/data-channels.mdx index bd559ec..31d5124 100644 --- a/versioned_docs/version-0.25.0/explanation/data-channels.mdx +++ b/versioned_docs/version-0.25.0/explanation/data-channels.mdx @@ -42,7 +42,22 @@ This separation allows you to use both channels simultaneously for different pur ## Using Data Channels -Use the [`useDataChannel`](../api/web/functions/useDataChannel) hook to work with data channels. The typical flow is: +Use the `useDataChannel` hook to work with data channels. The hook is available in both the web and mobile SDKs with the same API: + + + + +Use [`useDataChannel`](../api/web/functions/useDataChannel) from `@fishjam-cloud/react-client`. + + + + +Use [`useDataChannel`](../api/mobile/functions/useDataChannel) from `@fishjam-cloud/react-native-client`. + + + + +The typical flow is: 1. Initialize the data channel after connecting to a room 2. Subscribe to incoming messages diff --git a/versioned_docs/version-0.25.0/how-to/client/installation.mdx b/versioned_docs/version-0.25.0/how-to/client/installation.mdx index 14cf23d..9bfb5e9 100644 --- a/versioned_docs/version-0.25.0/how-to/client/installation.mdx +++ b/versioned_docs/version-0.25.0/how-to/client/installation.mdx @@ -77,23 +77,45 @@ You can also follow more detailed [Expo instructions](https://docs.expo.dev/get- ## Step 1: Install the Package -Install `@fishjam-cloud/react-native-client` with your preferred package manager. + + + + +Install `@fishjam-cloud/react-native-client` and `react-native-get-random-values` with your preferred package manager. + +```bash npm2yarn +npm install @fishjam-cloud/react-native-client react-native-get-random-values@1.11.0 +``` + +Expo SDK 54+ resolves native dependencies recursively, so `@fishjam-cloud/react-native-webrtc` (a transitive dependency) is autolinked automatically. + + + + +Install `@fishjam-cloud/react-native-client`, `@fishjam-cloud/react-native-webrtc`, and `react-native-get-random-values`: ```bash npm2yarn -npm install @fishjam-cloud/react-native-client +npm install @fishjam-cloud/react-native-client @fishjam-cloud/react-native-webrtc react-native-get-random-values@1.11.0 ``` +Bare React Native and Expo SDK versions below 54 only autolink direct dependencies. +`@fishjam-cloud/react-native-webrtc` must be in your app's `package.json` for its native code to be linked. + + + + ## Step 2: Configure App Permissions Your app needs to have permissions configured in order to use the microphone and camera. ### Android -These permissions are required to stream audio and video with Fishjam on Android: +The following Android permissions are required by Fishjam: - `android.permission.CAMERA` - `android.permission.RECORD_AUDIO` - `android.permission.MODIFY_AUDIO_SETTINGS` +- `android.permission.ACCESS_NETWORK_STATE` @@ -110,7 +132,8 @@ Add required permissions to the `app.json` file. "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } } @@ -128,6 +151,7 @@ Add required permissions to the `AndroidManifest.xml` file. + ... ``` diff --git a/versioned_docs/version-0.25.0/how-to/client/migration-guide.mdx b/versioned_docs/version-0.25.0/how-to/client/migration-guide.mdx index 270813b..891a6ec 100644 --- a/versioned_docs/version-0.25.0/how-to/client/migration-guide.mdx +++ b/versioned_docs/version-0.25.0/how-to/client/migration-guide.mdx @@ -24,7 +24,8 @@ Add the following WebRTC permissions to your Android configuration in `app.json` "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } } diff --git a/versioned_docs/version-0.25.0/how-to/features/text-chat.mdx b/versioned_docs/version-0.25.0/how-to/features/text-chat.mdx index 635f114..b979571 100644 --- a/versioned_docs/version-0.25.0/how-to/features/text-chat.mdx +++ b/versioned_docs/version-0.25.0/how-to/features/text-chat.mdx @@ -22,7 +22,7 @@ For a deeper understanding of how data channels work, including channel types an ## Step 1 — Set up the chat hook -Use the [`useDataChannel`](/api/web/functions/useDataChannel) hook to work with data channels. The typical flow is: +Use the [`useDataChannel`](/api/web/functions/useDataChannel) (web) or [`useDataChannel`](/api/mobile/functions/useDataChannel) (mobile) hook to work with data channels. The typical flow is: 1. Initialize the data channel after connecting to a room 2. Subscribe to incoming messages @@ -84,9 +84,67 @@ export function useChat() { ``` - + -Mobile SDK support for data channels will be available in a future release. +```tsx +import { + useConnection, + useDataChannel, +} from "@fishjam-cloud/react-native-client"; +import { useCallback, useEffect, useState } from "react"; + +export function useChat() { + const { peerStatus } = useConnection(); + const { + initializeDataChannel, + publishData, + subscribeData, + dataChannelReady, + dataChannelLoading, + dataChannelError, + } = useDataChannel(); + + const [messages, setMessages] = useState([]); + + useEffect(() => { + if (peerStatus === "connected") { + initializeDataChannel(); + } + }, [peerStatus, initializeDataChannel]); + + useEffect(() => { + if (dataChannelLoading || !dataChannelReady) return; + + const unsubscribe = subscribeData( + (data: Uint8Array) => { + const message = new TextDecoder().decode(data); + setMessages((prev) => [...prev, message]); + }, + { reliable: true }, + ); + + return unsubscribe; + }, [dataChannelReady, dataChannelLoading, subscribeData]); + + const sendMessage = useCallback( + (text: string) => { + if (!dataChannelReady) return; + + const encoded = new TextEncoder().encode(text); + publishData(encoded, { reliable: true }); + }, + [publishData, dataChannelReady], + ); + + return { + messages, + sendMessage, + ready: dataChannelReady, + loading: dataChannelLoading, + error: dataChannelError, + }; +} +``` @@ -185,9 +243,97 @@ function ChatPanel() { ``` - + + +```tsx +import React, { useState, useEffect, useCallback } from "react"; +import { View, Text, TextInput, FlatList, Pressable } from "react-native"; +import { + useConnection, + useDataChannel, +} from "@fishjam-cloud/react-native-client"; + +function useChat() { + const { peerStatus } = useConnection(); + const { + initializeDataChannel, + publishData, + subscribeData, + dataChannelReady, + } = useDataChannel(); + + const [messages, setMessages] = useState([]); + + useEffect(() => { + if (peerStatus === "connected") { + initializeDataChannel(); + } + }, [peerStatus, initializeDataChannel]); -Mobile SDK support for data channels will be available in a future release. + useEffect(() => { + if (!dataChannelReady) return; + + const unsubscribe = subscribeData( + (data: Uint8Array) => { + const message = new TextDecoder().decode(data); + setMessages((prev) => [...prev, message]); + }, + { reliable: true }, + ); + + return unsubscribe; + }, [subscribeData, dataChannelReady]); + + const sendMessage = useCallback( + (text: string) => { + if (!dataChannelReady) return; + + const encoded = new TextEncoder().encode(text); + publishData(encoded, { reliable: true }); + }, + [publishData, dataChannelReady], + ); + + return { messages, sendMessage, ready: dataChannelReady }; +} + +// ---cut--- + +function ChatPanel() { + const { messages, sendMessage, ready } = useChat(); + const [input, setInput] = useState(""); + + const handleSend = () => { + if (input.trim()) { + sendMessage(input); + setInput(""); + } + }; + + if (!ready) { + return Connecting to chat...; + } + + return ( + + String(i)} + renderItem={({ item }) => {item}} + /> + + + Send + + + ); +} +``` @@ -209,4 +355,5 @@ This ensures no chat messages are lost or arrive out of order. - [Data Channels](../../explanation/data-channels) — detailed explanation of channel types and broadcast behavior - [Connecting to a room](../../how-to/client/connecting) — prerequisite for using data channels -- [`useDataChannel` API reference](../../api/web/functions/useDataChannel) +- [`useDataChannel` API reference (Web)](../../api/web/functions/useDataChannel) +- [`useDataChannel` API reference (Mobile)](../../api/mobile/functions/useDataChannel) diff --git a/versioned_docs/version-0.25.0/tutorials/react-native-quick-start.mdx b/versioned_docs/version-0.25.0/tutorials/react-native-quick-start.mdx index 722b430..c3e845b 100644 --- a/versioned_docs/version-0.25.0/tutorials/react-native-quick-start.mdx +++ b/versioned_docs/version-0.25.0/tutorials/react-native-quick-start.mdx @@ -53,7 +53,8 @@ Add required permissions to the `app.json` file: "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", - "android.permission.MODIFY_AUDIO_SETTINGS" + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE" ] } }