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
- React Native development environment set up
- Access to Fishjam Dashboard
Step 1: Install and configure
Install the package
- npm
- Yarn
- pnpm
- Bun
npm install @fishjam-cloud/react-native-client
yarn add @fishjam-cloud/react-native-client
pnpm add @fishjam-cloud/react-native-client
bun add @fishjam-cloud/react-native-client
Configure app permissions
Your app needs to have permissions configured in order to use the microphone and camera.
Android
- Expo
- Bare workflow
Add required permissions to the app.json file:
{ "expo": { "android": { "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.MODIFY_AUDIO_SETTINGS" ] } } }
Add required permissions to the AndroidManifest.xml file:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTING"/>
iOS
- Expo
- Bare workflow
Add camera and microphone usage descriptions to app.json:
{ "expo": { "ios": { "infoPlist": { "NSCameraUsageDescription": "Allow $(PRODUCT_NAME) to access your camera.", "NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) to access your microphone." } } } }
Ensure Info.plist contains camera and microphone usage description entries:
<key>NSCameraUsageDescription</key> <string>Allow $(PRODUCT_NAME) to access your camera.</string> <key>NSMicrophoneUsageDescription</key> <string>Allow $(PRODUCT_NAME) to access your microphone.</string>
Build native dependencies
npx expo prebuild
Get your Fishjam ID
- Log in to Fishjam Dashboard
- Navigate to your Sandbox environment
- Copy your Fishjam ID
Set up Fishjam context
Wrap your app in the FishjamProvider component:
// Check https://fishjam.io/app/ for your Fishjam ID constFISHJAM_ID = "YOUR_FISHJAM_ID"; export default functionRoot () { return ( <FishjamProvider fishjamId ={FISHJAM_ID }> <App /> </FishjamProvider > ); }
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:
importReact from "react"; import {Button } from "react-native"; import {useConnection ,useSandbox ,useInitializeDevices , } from "@fishjam-cloud/react-native-client"; export functionJoinRoomButton () { const {joinRoom } =useConnection (); const {initializeDevices } =useInitializeDevices (); const {getSandboxPeerToken } =useSandbox (); consthandleJoinRoom = async () => { constroomName = "testRoom"; constpeerName = "testUser"; // In sandbox environment, you can get the peer token from our sandbox API // In production environment, you need to get it from your backend constpeerToken = awaitgetSandboxPeerToken (roomName ,peerName ); // Start camera by selecting the first available camera awaitinitializeDevices ({enableAudio : false }); // or just initializeDevices(); if you want both camera and mic // Join the room awaitjoinRoom ({peerToken }); }; return <Button title ="Join Room"onPress ={handleJoinRoom } />; }
Step 3: Check connection status
Monitor your connection status:
export functionConnectionStatus () { const {peerStatus } =useConnection (); return <Text >Status: {peerStatus }</Text >; }
Step 4: Display your video
Show your own video stream:
importReact from "react"; import {Text ,View } from "react-native"; import {RTCView ,useCamera } from "@fishjam-cloud/react-native-client"; export functionStreamPreview () { const {cameraStream } =useCamera (); return ( <View > {cameraStream ? ( <RTCView mediaStream ={cameraStream }style ={{height : 300,width : 300 }}objectFit ="cover"mirror ={true} /> ) : ( <Text >No camera stream</Text > )} </View > ); }
Step 5: Display other participants
Show video from other peers in the room:
importReact from "react"; import {View ,Text } from "react-native"; import {usePeers ,RTCView } from "@fishjam-cloud/react-native-client"; functionVideoPlayer ({stream }: {stream :MediaStream | null | undefined }) { return ( <View > {stream ? ( <RTCView mediaStream ={stream }objectFit ="cover"style ={{height : 300,width : 300 }} /> ) : ( <Text >No video</Text > )} </View > ); } export functionParticipantsView () { const {remotePeers } =usePeers (); return ( <View > {remotePeers .map ((peer ) => ( <View key ={peer .id }> {peer .cameraTrack ?.stream && ( <VideoPlayer stream ={peer .cameraTrack .stream } /> )} </View > ))} </View > ); }
Complete example
Here's a complete working app:
functionVideoPlayer ({stream }: {stream :MediaStream | null | undefined }) { if (!stream ) { return ( <View style ={styles .videoPlaceholder }> <Text >No video</Text > </View > ); } return ( <RTCView mediaStream ={stream }style ={styles .video }objectFit ="cover" /> ); } functionVideoCall () { const {joinRoom ,peerStatus } =useConnection (); const {cameraStream } =useCamera (); const {remotePeers } =usePeers (); const {initializeDevices } =useInitializeDevices (); const {getSandboxPeerToken } =useSandbox (); const [isJoined ,setIsJoined ] =useState (false); consthandleJoin = async () => { constroomName = "testRoom"; constpeerName = `user_${Date .now ()}`; // Initialize devices first awaitinitializeDevices (); // In sandbox environment, you can get the peer token from our sandbox API // In production environment, you need to get it from your backend constpeerToken = awaitgetSandboxPeerToken (roomName ,peerName ); awaitjoinRoom ({peerToken });setIsJoined (true); }; return ( <ScrollView style ={styles .container }> <Text style ={styles .title }>Fishjam Video Call</Text > <Text style ={styles .status }>Status: {peerStatus }</Text > {!isJoined && <Button title ="Join Room"onPress ={handleJoin } />} {cameraStream && ( <View style ={styles .section }> <Text style ={styles .sectionTitle }>Your Video</Text > <VideoPlayer stream ={cameraStream } /> </View > )} <View style ={styles .section }> <Text style ={styles .sectionTitle }>Other Participants</Text > {remotePeers .length === 0 ? ( <Text >No other participants</Text > ) : (remotePeers .map ((peer ) => ( <View key ={peer .id }style ={styles .participant }> {peer .cameraTrack ?.stream && ( <VideoPlayer stream ={peer .cameraTrack .stream } /> )} </View > )) )} </View > </ScrollView > ); } conststyles =StyleSheet .create ({container : {flex : 1,padding : 20, },title : {fontSize : 24,fontWeight : "bold",marginBottom : 10, },status : {fontSize : 16,marginBottom : 20, },section : {marginTop : 20, },sectionTitle : {fontSize : 18,fontWeight : "600",marginBottom : 10, },participant : {marginBottom : 10, },video : {height : 200,width : "100%",borderRadius : 8, },videoPlaceholder : {height : 200,width : "100%",backgroundColor : "#000",borderRadius : 8,justifyContent : "center",alignItems : "center", }, }); export default functionApp () { return ( <FishjamProvider fishjamId ={FISHJAM_ID }> <VideoCall /> </FishjamProvider > ); }
Next steps
Now that you have a basic app working, explore these how-to guides:
- How to handle screen sharing
- How to implement background streaming
- How to handle reconnections
- How to work with metadata
Or learn more about Fishjam concepts: