Skip to main content
Version: Next

React Native Quick Start

This tutorial will guide you through integrating Fishjam into your React Native application step by step.
By the end, you'll have a working video streaming app and understand the core concepts.

What you'll build

A simple React Native app that can join conference calls and stream audio/video between participants.

What you'll learn

  • How to install and configure Fishjam SDK
  • How to join a room and start streaming
  • How to display video and play audio from other participants
  • How to check connection status

Prerequisites

Step 1: Install and configure

Install the package

npm install @fishjam-cloud/react-native-client

Configure app permissions

Your app needs to have permissions configured in order to use the microphone and camera.

Android

Permissions below are required to stream audio and video with Fishjam on Android.

  • android.permission.CAMERA
  • android.permission.RECORD_AUDIO
  • android.permission.MODIFY_AUDIO_SETTINGS

Add required permissions to the app.json file.

{ "expo": { ... "android": { ... "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.MODIFY_AUDIO_SETTINGS" ] } } }

iOS

You don't have to make any changes to run app on iOS. To update default content of permission alert, you can add these settings to app.json:

{ "expo": { ... "ios": { ... "infoPlist": { "NSCameraUsageDescription": "Allow $(PRODUCT_NAME) to access your camera.", "NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) to access your microphone." } }, } }

Build native dependencies

npx expo prebuild

Get your Fishjam ID

  1. Log in to Fishjam Dashboard
  2. Navigate to your Sandbox environment
  3. Copy your Fishjam ID

Quick example

To quickly test our streaming infrastructure use FishjamRoom component. It encapsulates all the steps needed to start streaming.

Example usage:

import { FishjamRoom, useSandbox } from "@fishjam-cloud/react-native-client"; import React, { useEffect, useState } from "react"; export default function HomeScreen() { const fishjamId = "YOUR_FISHJAM_ID"; const [peerToken, setPeerToken] = useState<string | null>(null); const { getSandboxPeerToken } = useSandbox({ fishjamId: fishjamId }); useEffect(() => { const fetchPeerToken = async () => { try { const peerToken = await getSandboxPeerToken( "example-room-name", "example-peer-name", ); setPeerToken(peerToken); } catch (e) { console.error("Error connecting to Fishjam", e); } }; fetchPeerToken(); }, []); if (!peerToken) { return null; } return <FishjamRoom fishjamId={fishjamId} peerToken={peerToken} />; }
important

This won't work on the iOS Simulator, as the Simulator can't access the camera. Test on a real device.

For more detailed implementation follow the steps below.

Step 2: Join a room and start streaming

Create a component that joins a room and starts streaming video:

import React, { useCallback } from "react"; import { Button } from "react-native"; import { useCamera, useConnection, useSandbox, } from "@fishjam-cloud/react-native-client"; // Check https://fishjam.io/app for your Fishjam ID const FISHJAM_ID = "YOUR_FISHJAM_ID"; export function StartStreamingButton({ roomName, peerName, }: { roomName: string; peerName: string; }) { const { prepareCamera } = useCamera(); const { joinRoom } = useConnection(); const { getSandboxPeerToken } = useSandbox({ fishjamId: FISHJAM_ID }); const startStreaming = useCallback(async () => { // In sandbox environment, you can get the peer token from our sandbox API // In production environment, you need to get it from your backend const peerToken = await getSandboxPeerToken(roomName, peerName); // Prepare camera await prepareCamera({ cameraEnabled: true }); // Join the room await joinRoom({ peerToken, fishjamId: FISHJAM_ID }); }, [joinRoom, prepareCamera, roomName, peerName]); return <Button title="Start Streaming" onPress={startStreaming} />; }

Step 3: Check connection status

Monitor your connection status:

export function ConnectionStatus() { const { peerStatus } = useConnection(); return <Text>Status: {peerStatus}</Text>; }

Step 4: Display your video

Show your own video stream:

import React from "react"; import { VideoPreviewView } from "@fishjam-cloud/react-native-client"; export function StreamPreview() { return <VideoPreviewView style={{ height: 300, width: 300 }} />; }

Step 5: Display other participants

Show video from other peers in the room:

export function ParticipantsView() { const { remotePeers } = usePeers(); const videoTracks = remotePeers.flatMap((peer) => peer.tracks.filter((track) => track.type === "Video" && track.isActive), ); return ( <View> {videoTracks.map((track) => ( <VideoRendererView key={track.id} trackId={track.id} videoLayout="FIT" style={{ height: 300, width: 300 }} /> ))} </View> ); }

Complete example

Here's a complete working example:

import { Text, View, Button } from "react-native"; import { usePeers, useCamera, useConnection, useSandbox, VideoRendererView, VideoPreviewView, } from "@fishjam-cloud/react-native-client"; import React, { useCallback } from "react"; // Check https://fishjam.io/app for your Fishjam ID const FISHJAM_ID = `${process.env.EXPO_PUBLIC_FISHJAM_ID}`; function StartStreamingButton({ roomName, peerName, }: { roomName: string; peerName: string; }) { const { prepareCamera } = useCamera(); const { joinRoom } = useConnection(); const { getSandboxPeerToken } = useSandbox({ fishjamId: FISHJAM_ID }); const startStreaming = useCallback(async () => { const peerToken = await getSandboxPeerToken(roomName, peerName); await prepareCamera({ cameraEnabled: true }); await joinRoom({ peerToken, fishjamId: FISHJAM_ID }); }, [joinRoom, prepareCamera, roomName, peerName]); return <Button title="Start Streaming" onPress={startStreaming} />; } function ConnectionStatus() { const { peerStatus } = useConnection(); return <Text>Status: {peerStatus}</Text>; } function StreamPreview() { return <VideoPreviewView style={{ height: 300, width: 300 }} />; } function ParticipantsView() { const { remotePeers } = usePeers(); const videoTracks = remotePeers.flatMap((peer) => peer.tracks.filter((track) => track.type === "Video" && track.isActive), ); return ( <View> {videoTracks.map((track) => ( <VideoRendererView key={track.id} trackId={track.id} videoLayout="FIT" style={{ height: 300, width: 300 }} /> ))} </View> ); } export default function Index() { return ( <View style={{ flex: 1, alignItems: "center", }} > <StartStreamingButton roomName="test-room" peerName="test-peer" /> <ConnectionStatus /> <Text>Your Stream:</Text> <StreamPreview /> <Text>Other Participants:</Text> <ParticipantsView /> </View> ); }

Next steps

Now that you have a basic app working, explore these how-to guides:

Or learn more about Fishjam concepts: