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
4 changes: 1 addition & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
[submodule "packages/web-client-sdk"]
path = packages/web-client-sdk
url = https://github.com/fishjam-cloud/web-client-sdk.git
[submodule "packages/mobile-client-sdk"]
path = packages/mobile-client-sdk
url = https://github.com/fishjam-cloud/mobile-client-sdk.git
branch = mobile-sdk-2-0
[submodule "packages/js-server-sdk"]
path = packages/js-server-sdk
url = https://github.com/fishjam-cloud/js-server-sdk.git
Expand Down
36 changes: 20 additions & 16 deletions docs/explanation/public-livestreams.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,23 @@ Once you've created a viewer token, you can connect to a room using the Fishjam
const viewerToken = '';

// ---cut---
import {
LivestreamViewer,
useLivestreamViewer,
} from '@fishjam-cloud/react-native-client/livestream';
import { useLivestreamViewer, RTCView } from '@fishjam-cloud/mobile-client';

// ...
//TODO: FCE-2487 remove it when MediaStream will be updated
interface MediaStreamWithURL extends MediaStream {
toURL(): string;
}

const { connect, whepClientRef } = useLivestreamViewer();
// Inside your component:
const { connect, stream } = useLivestreamViewer();

// ...

await connect({ token: viewerToken });

// Use `LivestreamViewer` to render the stream
<LivestreamViewer ref={whepClientRef} />
// Render the stream
const streamURL = stream ? (stream as MediaStreamWithURL).toURL() : null;
{streamURL && <RTCView streamURL={streamURL} style={{ flex: 1 }} />}
```

</TabItem>
Expand Down Expand Up @@ -203,21 +205,23 @@ Once you've created a room of type `livestream` with the `public` flag enabled,
const roomId = '';

// ---cut---
import {
LivestreamViewer,
useLivestreamViewer,
} from '@fishjam-cloud/react-native-client/livestream';
import { useLivestreamViewer, RTCView } from '@fishjam-cloud/mobile-client';

// ...
//TODO: FCE-2487 remove it when MediaStream will be updated
interface MediaStreamWithURL extends MediaStream {
toURL(): string;
}

const { connect, whepClientRef } = useLivestreamViewer();
// Inside your component:
const { connect, stream } = useLivestreamViewer();

// ...

await connect({ streamId: roomId });

// Use `LivestreamViewer` to render the stream
<LivestreamViewer ref={whepClientRef} />
// Render the stream
const streamURL = stream ? (stream as MediaStreamWithURL).toURL() : null;
{streamURL && <RTCView streamURL={streamURL} style={{ flex: 1 }} />}
```

</TabItem>
Expand Down
3 changes: 1 addition & 2 deletions docs/how-to/backend/server-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ At any time you can terminate user's access by deleting the peer.

#### Metadata

When creating a peer, you can also assign metadata to that peer, which can be read later with the [mobile SDK](../../how-to/react-native/metadata)
or [web SDK](../../how-to/react/metadata). This metadata can be only set when creating the peer and can't be updated later.
When creating a peer, you can also assign metadata to that peer, which can be read later with the [client SDK](../../how-to/client/metadata). This metadata can be only set when creating the peer and can't be updated later.

<Tabs groupId="language">
<TabItem value="ts" label="Typescript">
Expand Down
9 changes: 9 additions & 0 deletions docs/how-to/client/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"label": "Web & Mobile",
"position": 1,
"link": {
"type": "generated-index",
"description": "Learn how to integrate Fishjam into your web and mobile applications."
}
}

128 changes: 128 additions & 0 deletions docs/how-to/client/background-streaming.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
sidebar_position: 13
sidebar_label: "Background calls 📱"
---

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

# Background calls <span className="badge badge--mobile">Mobile</span>

:::note
This guide is exclusively for **Mobile** (React Native) applications.
:::

Both Android and iOS support calls running in the background, but they use different approaches:

- **Android**: Uses foreground services to keep the app active in the background
- **iOS**: Uses CallKit integration to maintain VoIP calls in the background

Below is configuration required to make it work:

<Tabs groupId="app-type">

<TabItem value="expo" label="Expo">

You need to modify `app.json` file and add our plugin:

```json
{
"expo": {
...
"plugins": {
...
[
"@fishjam-cloud/mobile-client",
{
"android": {
"enableForegroundService": true
},
"ios": {
"enableVoIPBackgroundMode": true
}
}
],
...
}
}
}
```

</TabItem>
<TabItem value="rn" label="Bare workflow">

**Android Configuration**

You need to add the following service to `AndroidManifest.xml`:

```xml title='AndroidManifest.xml'
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<application ...>
...
<service android:name="io.fishjam.reactnative.FishjamForegroundService" android:foregroundServiceType="camera|microphone|mediaProjection"/>
</application>
</manifest>
```

**iOS Configuration**

You need to add VoIP background mode in `Info.plist`:

```xml title='Info.plist'
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
```

</TabItem>
</Tabs>

## Usage

<Tabs groupId="platform">

<TabItem value="android" label="Android">

You can use [`useForegroundService`](../../api/mobile/variables/useForegroundService) hook to handle how foreground service behaves on Android.

:::important[Permissions]

If you want to use [`enableCamera`](../../api/mobile/type-aliases/ForegroundServiceConfig#enablecamera) or [`enableMicrophone`](../../api/mobile/type-aliases/ForegroundServiceConfig#enablemicrophone),
user must first grant permission for this resource. [`useForegroundService`](../../api/mobile/variables/useForegroundService) will check if permission is
granted and only then allow to start a service.

:::

```tsx
import {
useCamera,
useMicrophone,
} from "@fishjam-cloud/mobile-client";

const { isCameraOn } = useCamera();
const { isMicrophoneOn } = useMicrophone();


```

</TabItem>
<TabItem value="ios" label="iOS">

On iOS, background calls are achieved through CallKit integration. To enable background streaming on iOS:

1. Enable VoIP background mode by setting `enableVoIPBackgroundMode: true` in the plugin configuration or adding the VoIP background mode to your `Info.plist`
2. The SDK will automatically handle CallKit integration for maintaining background audio/video sessions

:::note
CallKit integration is handled automatically by the SDK when VoIP background mode is enabled. The call will appear in the iOS call history and can be managed through the native phone interface.
:::

</TabItem>
</Tabs>

## See Also

For an enhanced user experience when your app is in the background, consider enabling [Picture in Picture](./picture-in-picture), which allows users to see video content in a floating window while using other apps.

173 changes: 173 additions & 0 deletions docs/how-to/client/connecting.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
sidebar_position: 3
---

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

# Connecting

This article will guide you through the process of connecting to a Fishjam room.

## Getting URL and token

In order to connect, you need to obtain a **Peer Token** (the token that will authenticate the peer in
your Room).

<Tabs groupId="app-type">

<TabItem value="sandbox" label="Sandbox App">

Once you create your account on [Fishjam](https://fishjam.io), you will have access to the Sandbox environment as part of the Mini Jar plan.
While using the Sandbox environment, [you can use the Sandbox API](../features/sandbox-api-testing) to generate peer tokens for testing or development purposes.
This is basically a service that will create a Room, add your app as
the Room's Peer, and return the token required to use that Room.

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

```ts
import { useSandbox } from "@fishjam-cloud/react-client";
const roomName = "room";
const peerName = "user";
// ---cut---

// The `useSandbox` hook gets the fishjamId from FishjamProvider
// It will work ONLY with the FISHJAM_ID of the Sandbox environment
const { getSandboxPeerToken } = useSandbox();
const peerToken = await getSandboxPeerToken(roomName, peerName);
```

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

```ts
import { useSandbox } from "@fishjam-cloud/mobile-client";
const roomName = "room";
const peerName = "user";
// ---cut---

// The `useSandbox` hook gets the fishjamId from FishjamProvider
// It will work ONLY with the FISHJAM_ID of the Sandbox environment
const { getSandboxPeerToken } = useSandbox();
const peerToken = await getSandboxPeerToken(roomName, peerName);
```

</TabItem>
</Tabs>

</TabItem>
<TabItem value="production" label="Production App">

For the production app, you need to implement your own backend service that will provide the user with a **Peer Token**. To do that,
follow our [server setup instructions](../backend/server-setup).

</TabItem>
</Tabs>

## Connecting

Use the [`useConnection`](../../api/web/functions/useConnection) hook to get
the [`joinRoom`](../../api/web/functions/useConnection#joinroom) function.

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

```tsx
const PEER_TOKEN = "some-peer-token";
// ---cut-before---
import { useConnection, useSandbox } from "@fishjam-cloud/react-client";
import React, { useCallback } from "react";

export function JoinRoomButton() {
const { joinRoom } = useConnection(); // [!code highlight]
// get the peer token from sandbox or your backend
const { getSandboxPeerToken } = useSandbox();

const onJoinRoomPress = useCallback(async () => {
// [!code highlight:5]
const peerToken = await getSandboxPeerToken("Room", "User");
await joinRoom({ peerToken });
}, [joinRoom]);

return <button onClick={onJoinRoomPress}>Join room</button>;
}
```

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

```tsx
import React, { useCallback } from "react";
import { Button } from "react-native";
import { useConnection, useSandbox } from "@fishjam-cloud/mobile-client";

export function JoinRoomButton() {
const { joinRoom } = useConnection(); // [!code highlight]
// fishjamId is provided through FishjamProvider
const { getSandboxPeerToken } = useSandbox();

const onPressJoin = useCallback(async () => {
// in production environment, get the peerToken from your backend
const peerToken = await getSandboxPeerToken("Room", "User");

await joinRoom({ peerToken }); // [!code highlight]
}, [joinRoom, getSandboxPeerToken]);

return <Button onPress={onPressJoin} title="Join Room" />;
}
```

</TabItem>
</Tabs>

## Disconnecting

In order to close connection, use the [`leaveRoom`](../../api/web/functions/useConnection#leaveroom) method
from [`useConnection`](../../api/web/functions/useConnection) hook.

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

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

export function LeaveRoomButton() {
const { leaveRoom } = useConnection(); // [!code highlight]

return <button onClick={leaveRoom}>Leave room</button>;
}
```

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

```tsx
import React, { useCallback } from "react";
import { Button } from "react-native";
import { useConnection } from "@fishjam-cloud/mobile-client";

export function LeaveRoomButton() {
const { leaveRoom } = useConnection(); // [!code highlight]

const onPressLeave = useCallback(async () => {
await leaveRoom(); // [!code highlight]
}, [leaveRoom]);

return <Button onPress={onPressLeave} title="Leave Room" />;
}
```

</TabItem>
</Tabs>

## Next Steps

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
- [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)

Loading
Loading