Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
.aider*
node_modules
dist
build
.env
.vscode
22 changes: 22 additions & 0 deletions mobile-react-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Examples for Fishjam client

- [Minimal React Native](./minimal-react-native/) - minimal example
- joining a video room with a custom room name and user name
- real-time video grid with local and remote participants
- almost no UI

- [Fishjam Chat](./fishjam-chat/) - example video chat app
- connecting to VideoRoom by entering a room name and username
- streaming camera, microphone and screen sharing
- joining and creating livestreams

- [Background Blur](./blur-example/) - example of applying background blur
- toggling camera background blur on/off during a video call
- using a camera track middleware

- [Text Chat](./text-chat/) - example text messaging app
- real-time text messaging between participants
- using WebRTC data channels

- [Video Player](./video-player/) - minimal livestreaming viewer
- joining an existing livestream as a viewer
2 changes: 2 additions & 0 deletions mobile-react-native/blur-example/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
EXPO_PUBLIC_FISHJAM_ID=
EXPO_PUBLIC_FISHJAM_URL=
39 changes: 39 additions & 0 deletions mobile-react-native/blur-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/

# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo
android/*
ios/*
.env
.cursor/
20 changes: 20 additions & 0 deletions mobile-react-native/blur-example/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FishjamProvider } from '@fishjam-cloud/react-native-client';
import { NavigationContainer } from '@react-navigation/native';
import * as React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';

import RootNavigation from './navigation/RootNavigation';

const App = () => {
return (
<FishjamProvider fishjamId={process.env.EXPO_PUBLIC_FISHJAM_ID}>
<SafeAreaProvider>
<NavigationContainer>
<RootNavigation />
</NavigationContainer>
</SafeAreaProvider>
</FishjamProvider>
);
};

export default App;
91 changes: 91 additions & 0 deletions mobile-react-native/blur-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Background Blur Example

A mobile video chat demo showcasing **real-time camera background blur** using the [`@fishjam-cloud/react-native-webrtc-background-blur`](https://www.npmjs.com/package/@fishjam-cloud/react-native-webrtc-background-blur) package. Built with [Fishjam Cloud](https://fishjam.io/), [Expo](https://expo.dev/), and [React Native](https://reactnative.dev/).

## Features

- **Background blur toggle** — blur your camera background on/off during a video call using a camera track middleware
- Join a video room with a custom room name and user name
- Real-time video grid with local and remote participants
- Automatic camera and microphone permission handling

## Getting Started

### Prerequisites

- [Node.js](https://nodejs.org/) (v18 or newer recommended)
- [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/)
- [Expo](https://docs.expo.dev/get-started/installation/): You do **not** need to install Expo CLI globally. Use `npx expo` to run Expo commands.

### Installation

1. **Clone the repository:**
```sh
git clone https://github.com/fishjam-cloud/web-client-sdk.git
cd web-client-sdk
```
2. **Install dependencies and build project:**
```sh
yarn
yarn build
```
3. **Set up environment variables:**
- Create a `.env` file in the `examples/mobile-client/blur-example` directory:
```sh
cp .env.example .env
```
- Fill in your Fishjam ID. _You can find the value for this variable by creating an account on [fishjam.io](https://fishjam.io) and copying it from the sandbox dashboard._

There also exists this additional environment variable, which is used for internal testing purposes:
- `EXPO_PUBLIC_FISHJAM_URL` - Sandbox URL for custom Fishjam environment

4. **Prebuild native files:**
```sh
cd examples/mobile-client/blur-example
npx expo prebuild --clean
```
> [!NOTE]
> Be sure to run `npx expo prebuild` and not `yarn prebuild` as there's an issue with path generation for the `ios/.xcode.env.local` file

### Running the App

- **Run on Android:**
```sh
yarn android
```
- **Run on iOS:**
```sh
yarn ios
```

## Usage

1. Enter a room name and your user name on the Home screen.
2. Tap **Connect** to join the video room.
3. See yourself and other participants in a responsive video grid.
4. Tap **Enable Blur** to apply background blur to your camera feed, or **Disable Blur** to turn it off.
5. Leaving the room or closing the app will disconnect you from the session.

## Architecture Overview

- **React Native + Expo**: Cross-platform mobile app framework.
- **Fishjam Cloud SDK**: Handles all real-time video, audio, and peer management.
- **`@fishjam-cloud/react-native-webrtc-background-blur`**: Provides a `useBackgroundBlur` hook that returns a camera track middleware. The middleware is applied via `setCameraTrackMiddleware` from the Fishjam `useCamera()` hook.
- **TypeScript**: Provides type safety and better developer experience.

## Troubleshooting & FAQ

- **App fails to connect to a room:**
- Ensure your `.env` file is present and `EXPO_PUBLIC_FISHJAM_ID` is set correctly.
- Check your network connection.
- Review logs in the Metro/Expo console for errors.
- **Camera or microphone not working:**
- Make sure you have granted the necessary permissions on your device.

## License

This example is provided under the Apache License 2.0. See [LICENSE](../../../LICENSE) for details.

---

_This project is maintained by the Fishjam team. For questions or support, visit [fishjam.io](https://fishjam.io/) or open an issue on GitHub._
44 changes: 44 additions & 0 deletions mobile-react-native/blur-example/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"expo": {
"name": "blur-example",
"slug": "blur-example",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "io.fishjam.mobile.example.blurexample",
"infoPlist": {
"NSCameraUsageDescription": "Allow $(PRODUCT_NAME) to access your camera.",
"NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) to access your microphone."
},
"appleTeamId": "J5FM626PE2"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true,
"package": "io.fishjam.mobile.example.blurexample",
"permissions": [
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO",
"android.permission.MODIFY_AUDIO_SETTINGS",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.ACCESS_WIFI_STATE"
]
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [["@fishjam-cloud/react-native-client"]]
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mobile-react-native/blur-example/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions mobile-react-native/blur-example/components/VideosGridItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { RTCView } from '@fishjam-cloud/react-native-client';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

import type { GridTrack } from '../types';

export const VideosGridItem = ({ peer }: { peer: GridTrack }) => {
const mediaStream = peer.track?.stream ? peer.track.stream : null;

return (
<View style={styles.container}>
<View
style={[
styles.video,
{ backgroundColor: peer.isLocal ? '#606619' : '#7089DB' },
]}>
{mediaStream ? (
<RTCView
mediaStream={mediaStream}
objectFit="cover"
style={styles.videoContent}
mirror={true}
/>
) : (
<View style={styles.videoContent}>
<Text>No video</Text>
</View>
)}
</View>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 0.5,
},
video: {
flex: 1,
aspectRatio: 1,
borderRadius: 8,
overflow: 'hidden',
borderColor: '#001A72',
borderWidth: 1,
},
videoContent: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
58 changes: 58 additions & 0 deletions mobile-react-native/blur-example/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import js from '@eslint/js';
import prettier from 'eslint-config-prettier';
import importPlugin from 'eslint-plugin-import';
import prettierPlugin from 'eslint-plugin-prettier';
import reactHooks from 'eslint-plugin-react-hooks';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{
ignores: [
'dist/',
'node_modules/',
'coverage/',
'build/',
'ios/',
'android/',
'.expo/',
'prettier.config.js',
],
},
js.configs.recommended,
...tseslint.configs.recommended,
prettier,
{
plugins: {
'react-hooks': reactHooks,
'simple-import-sort': simpleImportSort,
'import': importPlugin,
'prettier': prettierPlugin,
},
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'no-case-declarations': 'off',
'no-console': ['error', { allow: ['debug', 'warn', 'error'] }],
'no-shadow': 'error',
'react-hooks/exhaustive-deps': 'error',
'react-hooks/rules-of-hooks': 'error',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'import/no-unresolved': 'off',
'prettier/prettier': 'error',
},
},
);
Loading