Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/fishjam-server
190 changes: 190 additions & 0 deletions docs/explanation/data-channels.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
---
type: explanation
sidebar_position: 7
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Data Channels

Data channels allow you to send and receive arbitrary binary data between peers in a room. This is useful for implementing features like text chat, file sharing, game state synchronization, or real-time cursor positions.

## Prerequisites

Before using data channels, you must be [connected to a room](./connecting). Data channels only work after you have successfully joined a room.

## Channel Types

The SDK provides two types of data channels, each optimized for different use cases:

### Reliable Channel

- **Ordered delivery**: Messages arrive in the order they were sent
- **Guaranteed delivery**: All messages will be delivered, with automatic retransmission if needed
- **Use cases**: Chat messages, file transfers, commands, or any data that must not be lost

### Lossy Channel

- **Unordered delivery**: Messages may arrive out of order
- **No retransmission**: Messages may be dropped if the network is congested
- **Lower latency**: Faster delivery since there's no waiting for retransmissions
- **Use cases**: Real-time cursor positions, game state updates, live sensor data, or any data where the latest value matters more than every value

## Broadcast Communication

Data channels work in a **broadcast fashion** - when you publish data, it is sent to all other peers in the room. Additionally:

- Messages sent on the **reliable channel** are only received by peers subscribed to the **reliable channel**
- Messages sent on the **lossy channel** are only received by peers subscribed to the **lossy channel**

This separation allows you to use both channels simultaneously for different purposes without interference.

## Using Data Channels

Use the [`useDataChannel`](../../api/web/functions/useDataChannel) 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
3. Publish messages to other peers

### Example: Simple Chat Messages
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: How about moving this section to "how-to/features" as a "text chat" article? Both articles should link to each other like: "see how to build a text-chat using data channel" and "we will use data channels to send messages, check out the explanation to learn more"


<Tabs groupId="platform">
<TabItem value="web" label="React (Web)">

```tsx
import { useConnection, useDataChannel } from "@fishjam-cloud/react-client";
import { useCallback, useEffect, useState } from "react";

export function useChat() {
const { peerStatus } = useConnection();
const {
initializeDataChannel,
publishData,
subscribeData,
dataChannelReady,
} = useDataChannel();

const [messages, setMessages] = useState<string[]>([]);

// Step 1: Initialize data channel when connected
useEffect(() => {
if (peerStatus === "connected") {
initializeDataChannel();
}
}, [peerStatus, initializeDataChannel]);

// Step 2: Subscribe to incoming messages
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]);

// Step 3: Publish messages
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 };
}
```

</TabItem>
<TabItem value="mobile" label="React Native (Mobile)" disabled>

Mobile SDK support for data channels will be available in a future release.

</TabItem>
</Tabs>

### Example: Using the Lossy Channel

For real-time data where low latency is more important than guaranteed delivery:

<Tabs groupId="platform">
<TabItem value="web" label="React (Web)">

```tsx
import { useConnection, useDataChannel } from "@fishjam-cloud/react-client";
import { useCallback, useEffect, useState } from "react";

interface CursorPosition {
peerId: string;
x: number;
y: number;
}

export function useCursorSharing(peerId: string) {
const { peerStatus } = useConnection();
const {
initializeDataChannel,
publishData,
subscribeData,
dataChannelReady,
} = useDataChannel();

const [cursors, setCursors] = useState<Map<string, CursorPosition>>(
new Map(),
);

useEffect(() => {
if (peerStatus === "connected") {
initializeDataChannel();
}
}, [peerStatus, initializeDataChannel]);

useEffect(() => {
if (!dataChannelReady) return;

const unsubscribe = subscribeData(
(data: Uint8Array) => {
const position: CursorPosition = JSON.parse(
new TextDecoder().decode(data),
);
setCursors((prev) => new Map(prev).set(position.peerId, position));
},
{ reliable: false }, // Lossy channel for low latency
);

return unsubscribe;
}, [subscribeData, dataChannelReady]);

const updateCursor = useCallback(
(x: number, y: number) => {
if (!dataChannelReady) return;

const encoded = new TextEncoder().encode(
JSON.stringify({ peerId, x, y }),
);
publishData(encoded, { reliable: false });
},
[publishData, dataChannelReady, peerId],
);

return { cursors, updateCursor, ready: dataChannelReady };
}
```

</TabItem>
<TabItem value="mobile" label="React Native (Mobile)" disabled>

Mobile SDK support for data channels will be available in a future release.

</TabItem>
</Tabs>
1 change: 1 addition & 0 deletions docs/how-to/client/connecting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,6 @@ Now that you're connected to a room, you can explore additional features:

- [Start Streaming](./start-streaming) - Enable your camera and microphone
- [List Other Peers](./list-other-peers) - Display video from other participants
- [Data Channels](./data-channels) - Send and receive arbitrary data between peers (e.g., text chat)
- [Picture in Picture](./picture-in-picture) - Allow users to watch video in a floating window (Mobile)
- [Background Streaming](./background-streaming) - Keep calls active when the app is backgrounded (Mobile)
2 changes: 1 addition & 1 deletion packages/web-client-sdk
Submodule web-client-sdk updated 61 files
+1 −1 .eslintrc.js
+20 −0 .github/workflows/release.yaml
+1 −1 .github/workflows/tests.yaml
+1 −1 .gitmodules
+1 −1 examples/mobile-client/fishjam-chat/app.json
+1 −1 examples/mobile-client/fishjam-chat/app/_layout.tsx
+1 −1 examples/mobile-client/fishjam-chat/app/livestream/screen-sharing.tsx
+1 −1 examples/mobile-client/fishjam-chat/app/livestream/streamer.tsx
+1 −1 examples/mobile-client/fishjam-chat/app/livestream/viewer.tsx
+1 −1 examples/mobile-client/fishjam-chat/app/room/[roomName].tsx
+1 −1 examples/mobile-client/fishjam-chat/app/room/preview.tsx
+1 −1 examples/mobile-client/fishjam-chat/components/VideosGrid.tsx
+1 −1 examples/mobile-client/fishjam-chat/package.json
+1 −1 examples/mobile-client/minimal-react-native/App.tsx
+1 −1 examples/mobile-client/minimal-react-native/app.json
+1 −1 examples/mobile-client/minimal-react-native/components/VideosGridItem.tsx
+1 −1 examples/mobile-client/minimal-react-native/hooks/useConnectFishjam.ts
+1 −1 examples/mobile-client/minimal-react-native/package.json
+1 −1 examples/mobile-client/minimal-react-native/screens/room/index.tsx
+1 −1 examples/mobile-client/minimal-react-native/types/index.ts
+1 −1 examples/mobile-client/minimal-react-native/utils/index.ts
+1 −1 examples/mobile-client/video-player/App.tsx
+1 −1 examples/mobile-client/video-player/app.json
+1 −1 examples/mobile-client/video-player/components/FishjamPlayerStreamer.tsx
+1 −1 examples/mobile-client/video-player/components/FishjamPlayerViewer.tsx
+1 −1 examples/mobile-client/video-player/package.json
+1 −0 examples/react-client/text-chat/.env.example
+2 −0 examples/react-client/text-chat/.eslintignore
+4 −0 examples/react-client/text-chat/.eslintrc
+3 −0 examples/react-client/text-chat/.prettierrc
+12 −0 examples/react-client/text-chat/index.html
+40 −0 examples/react-client/text-chat/package.json
+338 −0 examples/react-client/text-chat/src/App.tsx
+13 −0 examples/react-client/text-chat/src/main.tsx
+1 −0 examples/react-client/text-chat/src/vite-env.d.ts
+8 −0 examples/react-client/text-chat/tsconfig.json
+21 −0 examples/react-client/text-chat/vite.config.ts
+3 −3 packages/mobile-client/README.md
+10 −7 packages/mobile-client/package.json
+1 −1 packages/mobile-client/plugin/src/withFishjam.ts
+1 −1 packages/mobile-client/plugin/src/withFishjamIos.ts
+189 −0 packages/protobufs/fishjam/media_events/shared.ts
+274 −0 packages/protobufs/fishjam/server_notifications.ts
+5 −6 packages/protobufs/protobuf.sh
+1 −1 packages/protobufs/protos
+1 −1 packages/react-client/.tool-versions
+100 −0 packages/react-client/src/hooks/useDataChannel.ts
+4 −0 packages/react-client/src/index.ts
+43 −1 packages/react-client/src/types/public.ts
+125 −1 packages/ts-client/src/FishjamClient.ts
+2 −0 packages/ts-client/src/index.ts
+9 −0 packages/ts-client/src/types.ts
+4 −0 packages/webrtc-client/src/ConnectionManager.ts
+155 −0 packages/webrtc-client/src/dataChannels/DataChannel.ts
+223 −0 packages/webrtc-client/src/dataChannels/DataChannelManager.ts
+4 −0 packages/webrtc-client/src/index.ts
+3 −0 packages/webrtc-client/src/logger.ts
+85 −0 packages/webrtc-client/src/types.ts
+87 −0 packages/webrtc-client/src/webRTCEndpoint.ts
+3 −0 release-automation/bump-version.sh
+90 −22 yarn.lock