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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .github/workflows/npm-publish-react-native-executorch-webrtc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: NPM publish react-native-executorch-webrtc

on:
workflow_dispatch:
inputs:
latest-build:
description: 'Whether to publish as a latest build'
required: true
type: boolean

permissions:
id-token: write
contents: read

concurrency:
group: 'npm-react-native-executorch-webrtc-build'
cancel-in-progress: false

jobs:
build:
if: github.repository == 'software-mansion/react-native-executorch'
runs-on: ubuntu-latest
environment: deployment
permissions:
contents: read
id-token: write
env:
PACKAGE_DIR: packages/react-native-executorch-webrtc
PACKAGE_VERSION: PLACEHOLDER
PACKAGE_NAME: PLACEHOLDER
TAG: PLACEHOLDER
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'yarn'
registry-url: https://registry.npmjs.org/

- name: Update NPM
run: npm install -g npm@latest

- name: Determine version
working-directory: ${{ env.PACKAGE_DIR }}
run: |
VERSION=$(jq -r .version package.json)
echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV

- name: Assert PACKAGE_VERSION
if: ${{ env.PACKAGE_VERSION == 'PLACEHOLDER' }}
run: exit 1 # this should never happen

- name: Install monorepo dependencies
run: yarn install --immutable

- name: Set tag
run: |
if [[ "${{ inputs.latest-build }}" != "true" ]]; then
echo "TAG=executorch-nightly" >> $GITHUB_ENV
else
echo "TAG=latest" >> $GITHUB_ENV
fi

- name: Assert tag
if: ${{ env.TAG == 'PLACEHOLDER' }}
run: exit 1 # this should never happen

- name: Set nightly version
if: ${{ !inputs.latest-build }}
working-directory: ${{ env.PACKAGE_DIR }}
run: |
VERSION=${{ env.PACKAGE_VERSION }}
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
GIT_COMMIT=$(git rev-parse HEAD)
DATE=$(date +%Y%m%d)
NIGHTLY_UNIQUE_NAME="${GIT_COMMIT:0:7}-$DATE"
sed -i "3s/.*/ \"version\": \"$MAJOR.$MINOR.$PATCH-nightly-$NIGHTLY_UNIQUE_NAME\",/" package.json

- name: Build core package
working-directory: packages/react-native-executorch
run: yarn prepare

- name: Build package
working-directory: ${{ env.PACKAGE_DIR }}
run: yarn prepare

- name: Pack package
working-directory: ${{ env.PACKAGE_DIR }}
run: npm pack

- name: Restore version
if: ${{ !inputs.latest-build }}
working-directory: ${{ env.PACKAGE_DIR }}
run: |
VERSION=${{ env.PACKAGE_VERSION }}
sed -i "3s/.*/ \"version\": \"$VERSION\",/" package.json

- name: Add package name to env
working-directory: ${{ env.PACKAGE_DIR }}
run: echo "PACKAGE_NAME=$(ls -l | egrep -o "react-native-executorch-webrtc-(.*)(=?\.tgz)")" >> $GITHUB_ENV

- name: Assert package name
if: ${{ env.PACKAGE_NAME == 'PLACEHOLDER' }}
run: exit 1 # this should never happen

- name: Upload package to GitHub
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_NAME }}
path: ${{ env.PACKAGE_DIR }}/${{ env.PACKAGE_NAME }}

- name: Move package to monorepo root
run: mv ${{ env.PACKAGE_DIR }}/${{ env.PACKAGE_NAME }} .

- name: Publish package to npm
run: npm publish $PACKAGE_NAME --tag ${{ env.TAG }} --provenance --access public
118 changes: 118 additions & 0 deletions docs/docs/05-utilities/01-webrtc-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
title: Fishjam Usage
---

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

:::danger
This integration is currently in beta.
:::

## Overview

Starting from v0.9.0, you can use `react-native-executorch` powered background blur integration in your [Fishjam](https://fishjam.io) applications. The package `react-native-executorch-webrtc` exposes a hook, which returns a middleware for your camera streams. We plan to extend this to other models, such as text to speech, speech to text, or other vision models in the future.

## Installation

Install the package with your package manager of choice. Make sure to also have `react-native-executorch` and a resource fetcher adapter installed (see [Getting Started](../01-fundamentals/01-getting-started.md)).

<Tabs>
<TabItem value="npm" label="NPM">

```bash
npm install react-native-executorch-webrtc
```

</TabItem>
<TabItem value="pnpm" label="PNPM">

```bash
pnpm install react-native-executorch-webrtc
```

</TabItem>
<TabItem value="yarn" label="YARN">

```bash
yarn add react-native-executorch-webrtc
```

</TabItem>
</Tabs>

The following peer dependencies must also be installed in your app:

- `@fishjam-cloud/react-native-client`
- `@fishjam-cloud/react-native-webrtc`
- `react-native-executorch`

## Usage

The integration is built around the `selfie_segmentation` model that we expose through the [Model Registry](./model-registry.md). It's the only model we currently support and tune for — the blur pipeline expects its specific input shape and output classes, so other segmentation models will not work correctly.

Use `ResourceFetcher` together with `models.semantic_segmentation.selfie_segmentation().modelSource` to download (and cache) the model, then pass the resulting path to `useBackgroundBlur`. The returned `blurMiddleware` plugs into Fishjam's `cameraTrackMiddleware`.

```tsx
import { useEffect, useState } from 'react';
import { Button, Text } from 'react-native';
import { models, ResourceFetcher } from 'react-native-executorch';
import { useBackgroundBlur } from 'react-native-executorch-webrtc';
import { useCamera } from '@fishjam-cloud/react-native-client';

function VideoCall() {
const [modelUri, setModelUri] = useState<string | null>(null);

useEffect(() => {
ResourceFetcher.fetch(
() => {},
models.semantic_segmentation.selfie_segmentation().modelSource
).then((paths) => paths?.[0] && setModelUri(paths[0]));
}, []);

// Wait for the model to be available before mounting the hook —
// useBackgroundBlur expects a real path, not an empty string.
if (!modelUri) {
return <Text>Downloading model…</Text>;
}

return <VideoCallWithBlur modelUri={modelUri} />;
}

function VideoCallWithBlur({ modelUri }: { modelUri: string }) {
const [blurEnabled, setBlurEnabled] = useState(true);

const { blurMiddleware } = useBackgroundBlur({
modelUri,
blurRadius: 15,
});

useCamera({
cameraTrackMiddleware: blurEnabled ? blurMiddleware : undefined,
});

return (
<Button
title={blurEnabled ? 'Disable Blur' : 'Enable Blur'}
onPress={() => setBlurEnabled(!blurEnabled)}
/>
);
}
```

## API

### `useBackgroundBlur(options)`

| Option | Type | Description |
| ------------ | -------- | -------------------------------------------------------------------------- |
| `modelUri` | `string` | **Required.** Path or `file://` URI to the segmentation `.pte` model. |
| `blurRadius` | `number` | Optional. Gaussian blur sigma applied to the background. Defaults to `12`. |

Returns:

| Field | Type | Description |
| ---------------- | ----------------- | -------------------------------------------------------------- |
| `blurMiddleware` | `TrackMiddleware` | Pass to `useCamera({ cameraTrackMiddleware })` to enable blur. |

The hook initializes the native processor on mount and releases it on unmount, so you don't need to manage its lifecycle manually.
2 changes: 1 addition & 1 deletion packages/react-native-executorch-webrtc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-executorch-webrtc",
"version": "0.1.0",
"version": "0.9.0",
"description": "ExecuTorch WebRTC frame processor integration for react-native-webrtc",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down