0.25.x Migration Guide Mobile
Upgrading @fishjam-cloud/react-native-client from 0.24 to 0.25
This guide will help you upgrade your React Native application from @fishjam-cloud/react-native-client@0.24.x to @fishjam-cloud/react-native-client@0.25.x.
Overview
Version 0.25 of @fishjam-cloud/react-native-client introduces API changes that may require code updates.
Required Android Permissions
Add the following WebRTC permissions to your Android configuration in app.json:
{ "expo": { "android": { "permissions": [ "android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.MODIFY_AUDIO_SETTINGS" ] } } }
FishjamProvider Setup
In 0.25, wrapping your app with FishjamProvider is required to provide the Fishjam ID context.
Before
import {useConnection } from "@fishjam-cloud/react-native-client"; const {joinRoom } =useConnection (); // fishjamId was passed directly to joinRoom awaitjoinRoom ({fishjamId : "your-fishjam-id",peerToken : "..." });
After
import {FishjamProvider } from "@fishjam-cloud/react-native-client"; // Wrap your app with FishjamProvider export default functionApp () { return ( <FishjamProvider fishjamId ="YOUR_FISHJAM_ID"> <YourApp /> </FishjamProvider > ); } constYourApp = () => { return ( <> <Text >Your app content</Text > </> ); };
The fishjamId is now provided through the context, so you no longer need to pass it to joinRoom or useSandbox.
Device Initialization
Before
import {useCamera } from "@fishjam-cloud/react-native-client"; const {prepareCamera } =useCamera (); awaitprepareCamera ({cameraEnabled : true });
After
import {useInitializeDevices } from "@fishjam-cloud/react-native-client"; const {initializeDevices } =useInitializeDevices (); // Initialize devices when you first want to stream awaitinitializeDevices ({enableAudio : false }); // or initializeDevices() for both audio and video
On mobile, you should use initializeDevices() when you first want to stream. This gives your app access to all available devices and automatically requests camera and microphone permissions. After initialization, you can use startCamera/stopCamera or startMicrophone/stopMicrophone to manage device state.
Video Rendering and Accessing Peer Tracks
Before
import {usePeers ,VideoRendererView , } from "@fishjam-cloud/react-native-client"; const {remotePeers ,localPeer } =usePeers (); constvideoTracks =remotePeers .flatMap ((peer ) =>peer .tracks .filter ((track ) =>track .type === "Video" &&track .isActive ), ); constlocalTrack =localPeer ?.tracks .find ((t ) =>t .type === "Video"); <View > {localTrack && ( <VideoRendererView key ={localTrack .id }trackId ={localTrack .id }videoLayout ="FIT" /> )} {videoTracks .map ((track ) => ( <VideoRendererView key ={track .id }trackId ={track .id }videoLayout ="FIT" /> ))} </View >;
After
import {usePeers ,RTCView } from "@fishjam-cloud/react-native-client"; functionVideoPlayer ({stream }: {stream :MediaStream | null | undefined }) { return ( <> {stream && ( <RTCView mediaStream ={stream }style ={{width : 300,height : 200 }}objectFit ="cover" /> )} </> ); } const {localPeer ,remotePeers } =usePeers (); {localPeer ?.cameraTrack ?.stream && ( <VideoPlayer stream ={localPeer .cameraTrack .stream } /> ); } {remotePeers .map ((peer ) => ( <> {peer .cameraTrack ?.stream && ( <VideoPlayer stream ={peer .cameraTrack .stream } /> )} </> )); }
Key changes:
VideoRendererView→RTCViewtrackIdprop →mediaStreamproppeer.tracksarray →peer.cameraTrackandpeer.microphoneTrackpropertiestrack.isActiveremoved (check if stream exists instead)track.typeremoved (use specific track properties)
Connection API
Before
import {useConnection ,useSandbox } from "@fishjam-cloud/react-native-client"; const {joinRoom } =useConnection (); const {getSandboxPeerToken } =useSandbox ({fishjamId : "your-id" }); constpeerToken = awaitgetSandboxPeerToken ("roomName", "peerName"); awaitjoinRoom ({fishjamId : "your-id",peerToken });
After
import {useConnection ,useSandbox } from "@fishjam-cloud/react-native-client"; const {joinRoom } =useConnection (); // fishjamId is now provided through FishjamProvider const {getSandboxPeerToken } =useSandbox (); constpeerToken = awaitgetSandboxPeerToken ("roomName", "peerName"); awaitjoinRoom ({peerToken }); // fishjamId passed through FishjamProvider
Device Management
Camera Device Selection
Before
import {useCamera } from "@fishjam-cloud/react-native-client"; const {cameras ,switchCamera ,currentCamera } =useCamera (); // find first camera facing opposite direction than current camera constotherCamera =cameras .find ( (camera ) =>camera .facingDirection !==currentCamera ?.facingDirection , ); if (otherCamera ) {switchCamera (otherCamera .id ); }
After
import {useCamera } from "@fishjam-cloud/react-native-client"; const {cameraDevices ,selectCamera } =useCamera (); // Select camera by deviceId constnextCamera =cameraDevices [0]; if (nextCamera ) {selectCamera (nextCamera .deviceId ); }
Key changes:
cameras→cameraDevicesswitchCamera→selectCamera(takesdeviceIdinstead of direction)facingDirectionproperty removed
Camera Control
Before
import {useCamera } from "@fishjam-cloud/react-native-client"; const {isCameraOn ,toggleCamera } =useCamera (); <Button onPress ={toggleCamera }title ={isCameraOn ? "Disable camera" : "Enable camera"} />;
After
import {useCamera } from "@fishjam-cloud/react-native-client"; const {startCamera ,stopCamera ,toggleCamera } =useCamera (); awaitstartCamera (); awaitstopCamera ();toggleCamera ();
Screen Sharing
Before
import {useScreenShare } from "@fishjam-cloud/react-native-client"; const {toggleScreenShare ,isScreenShareOn } =useScreenShare (); constonPressToggle =useCallback ( () =>toggleScreenShare (), [toggleScreenShare ], ); <Button onPress ={onPressToggle }title ={isScreenShareOn ? "Disable" : "Enable"} />;
After
import {useScreenShare } from "@fishjam-cloud/react-native-client"; const {startStreaming ,stopStreaming ,stream } =useScreenShare (); constonPressToggle = () => { if (stream ) {stopStreaming (); } else {startStreaming (); } }; <Button onPress ={onPressToggle }title ={stream ? "Disable" : "Enable"} />;
Key changes:
toggleScreenShare()→startStreaming()/stopStreaming()isScreenShareOn→ check ifstreamexists
Picture in Picture
Before
import {PipContainerView } from "@fishjam-cloud/react-native-client"; export functionVideoCallScreen () { return ( <PipContainerView > <View >{/* Your video call UI */}</View > </PipContainerView > ); }
After
importReact , {useRef } from "react"; import {View ,Button } from "react-native"; import {RTCPIPView ,startPIP ,stopPIP ,useCamera , } from "@fishjam-cloud/react-native-client"; export functionVideoCallScreen () { constpipViewRef =useRef <React .ElementRef <typeofRTCPIPView >>(null); const {cameraStream } =useCamera (); return ( <View > <Button title ="Start PiP"onPress ={() =>startPIP (pipViewRef as any)} /> <Button title ="Stop PiP"onPress ={() =>stopPIP (pipViewRef as any)} /> {cameraStream && ( <RTCPIPView ref ={pipViewRef }mediaStream ={cameraStream }style ={{width : 300,height : 200 }}pip ={{startAutomatically : true,stopAutomatically : true,enabled : true, }} /> )} </View > ); }
Key changes:
PipContainerView→RTCPIPView- Requires a ref for manual
startPIP/stopPIPcontrol - Added
pipprop for configuration
Livestreaming Imports
Before
import {useLivestreamStreamer ,useLivestreamViewer , } from "@fishjam-cloud/react-native-client/livestream";
After
import {useLivestreamStreamer ,useLivestreamViewer , } from "@fishjam-cloud/react-native-client";
The livestreaming hooks are now exported from the main package instead of a separate /livestream subpath.
Removed Hooks and APIs
The following hooks and APIs have been removed and are no longer available:
Permission Hooks
Before
import {useCameraPermissions ,useMicrophonePermissions , } from "@fishjam-cloud/react-native-client"; const [cameraPermission ,requestCameraPermission ] =useCameraPermissions (); const [micPermission ,requestMicPermission ] =useMicrophonePermissions ();
After
Permissions are now handled automatically by the SDK. When you call initializeDevices(), the SDK will automatically request camera and microphone permissions if they haven't been granted yet.