diff --git a/.gitmodules b/.gitmodules index 5056c22..6f03827 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,9 @@ path = packages/web-client-sdk url = https://github.com/fishjam-cloud/web-client-sdk.git branch = mobile-sdk-2-0 +[submodule "packages/mobile-client-sdk"] + path = packages/mobile-client-sdk + url = https://github.com/fishjam-cloud/mobile-client-sdk.git [submodule "packages/js-server-sdk"] path = packages/js-server-sdk url = https://github.com/fishjam-cloud/js-server-sdk.git diff --git a/docs/how-to/client/migration-guide.mdx b/docs/how-to/client/migration-guide.mdx new file mode 100644 index 0000000..fd25557 --- /dev/null +++ b/docs/how-to/client/migration-guide.mdx @@ -0,0 +1,538 @@ +--- +sidebar_position: 0 +sidebar_label: "Migration Guide" +--- + +# Migration Guide: From @fishjam-cloud/react-native-client to @fishjam-cloud/mobile-client + +This guide will help you migrate your React Native application from `@fishjam-cloud/react-native-client` to `@fishjam-cloud/mobile-client`. + +## Overview + +The new `@fishjam-cloud/mobile-client` package provides a more consistent API across web and mobile platforms, improved TypeScript support, and better integration with React's context system. + +## Package Installation + +### Before + +```bash +npm install @fishjam-cloud/react-native-client +``` + +### After + +```bash +npm install @fishjam-cloud/mobile-client +``` + +Remember to update all your imports: + +**From:** +```tsx +import { useCamera } from "@fishjam-cloud/react-native-client"; + +``` + +**To:** +```tsx +import { useCamera } from "@fishjam-cloud/mobile-client"; +``` + +## Required Android Permissions + +Add the following WebRTC permissions to your Android configuration in `app.json`: + +```json +{ + "expo": { + "android": { + "permissions": [ + "android.permission.CAMERA", + "android.permission.RECORD_AUDIO", + "android.permission.MODIFY_AUDIO_SETTINGS", + "android.permission.ACCESS_NETWORK_STATE", + "android.permission.ACCESS_WIFI_STATE" + ] + } + } +} +``` +## FishjamProvider Setup + +The new package requires wrapping your app with `FishjamProvider` to provide the Fishjam ID context. + +### Before + +```tsx +import React from "react"; +// ---cut--- +import { useConnection } from "@fishjam-cloud/react-native-client"; + +const { joinRoom } = useConnection(); +// fishjamId was passed directly to joinRoom +await joinRoom({ fishjamId: "your-fishjam-id", peerToken: "..." }); + +``` + +### After + +```tsx +import React from "react"; +import { Text } from "react-native"; +// ---cut--- +import { FishjamProvider } from "@fishjam-cloud/mobile-client"; // [!code highlight] + +// Wrap your app with FishjamProvider +export default function App() { + return ( + // [!code highlight] + + // [!code highlight] + ); +} + +const YourApp = () => {return (<>Your app content);}; + +``` + +The `fishjamId` is now provided through the context, so you no longer need to pass it to `joinRoom` or `useSandbox`. + +## Device Initialization + +### Before + +```tsx +import { useCamera } from "@fishjam-cloud/react-native-client"; + +const { prepareCamera } = useCamera(); + +await prepareCamera({ cameraEnabled: true }); + +``` + +### After + +```tsx +import { useInitializeDevices } from "@fishjam-cloud/mobile-client"; + +const { initializeDevices } = useInitializeDevices(); + +// Initialize devices when you first want to stream +await initializeDevices({ enableAudio: false }); // or initializeDevices() for both + +``` + +:::important +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 +Key changes: + +- `VideoRendererView` → `RTCView` +- `trackId` prop → `streamURL` prop +- Use `stream.toURL()` to get the URL from a MediaStream +- Access peer video via `peer.cameraTrack.stream` instead of `peer.track` + +### Before + +```tsx +import React from "react"; +import { View } from "react-native"; +// ---cut--- +import { usePeers, VideoRendererView } from "@fishjam-cloud/react-native-client"; + +const { remotePeers, localPeer } = usePeers(); + +const videoTracks = remotePeers.flatMap( + (peer) => + peer.tracks.filter((track) => track.type === "Video" && track.isActive), + ); +const localTrack = localPeer?.tracks.find((t) => t.type === "Video"); + + + {localTrack && ( + + )} + {videoTracks.map((track) => ( + + ))} + +``` + +### After + +```tsx +import React from "react"; +// ---cut--- +import { usePeers, RTCView } from "@fishjam-cloud/mobile-client"; + +//TODO: FCE-2487 remove it when MediaStream will be updated +interface MediaStreamWithURL extends MediaStream { + toURL(): string; +} + +function VideoPlayer({ stream }: { stream: MediaStream | null | undefined }) { + const streamURL = stream ? (stream as MediaStreamWithURL).toURL() : null; + + if (!streamURL) return null; + + return ( + + ); +} + +const { localPeer, remotePeers } = usePeers(); +{localPeer?.cameraTrack?.stream && ( + +)} + +{remotePeers.map((peer) => ( + <> + {peer.cameraTrack?.stream && ( + + )} + +))} +``` + +Key changes: +- `VideoRendererView` → `RTCView` +- `trackId` prop → `streamURL` prop +- Use `stream.toURL()` to get the URL from a MediaStream +- `peer.tracks` array → `peer.cameraTrack` and `peer.microphoneTrack` properties +- `track.isActive` removed (check if stream exists instead) +- `track.type` removed (use specific track properties) + +## Connection API + +### Before + +```tsx +import { useConnection, useSandbox } from "@fishjam-cloud/react-native-client"; + +const { joinRoom } = useConnection(); +const { getSandboxPeerToken } = useSandbox({ fishjamId: "your-id" }); + +const peerToken = await getSandboxPeerToken("roomName", "peerName"); +await joinRoom({ fishjamId: "your-id", peerToken }); + +``` +### After + +```tsx +import { useConnection, useSandbox } from "@fishjam-cloud/mobile-client"; + +const { joinRoom } = useConnection(); +// fishjamId is now provided through FishjamProvider +const { getSandboxPeerToken } = useSandbox(); + +const peerToken = await getSandboxPeerToken("roomName", "peerName"); +await joinRoom({ peerToken }); // fishjamId passed through FishjamProvider + +``` + +## Device Management + +### Camera Device Selection + +### Before + +```tsx +import { useCamera } from "@fishjam-cloud/react-native-client"; + +const { cameras, switchCamera, currentCamera } = useCamera(); + +// find first camera facing opposite direction than current camera +const otherCamera = cameras.find( + (camera) => camera.facingDirection !== currentCamera?.facingDirection, +); +if (otherCamera) { + switchCamera(otherCamera.id); +} + +``` + +### After + +```tsx +import { useCamera } from "@fishjam-cloud/mobile-client"; +const { cameraDevices, selectCamera } = useCamera(); + +// Select camera by deviceId +const nextCamera = cameraDevices[0]; +if (nextCamera) { + selectCamera(nextCamera.deviceId); +} + +``` + +Key changes: + +- `cameras` → `cameraDevices` +- `switchCamera` → `selectCamera` (takes `deviceId` instead of direction) +- `facingDirection` property removed + +### Camera Control + +### Before + +```tsx +import React from "react"; +import { Button } from "react-native"; +// ---cut--- +import { useCamera } from "@fishjam-cloud/react-native-client"; +const { isCameraOn, toggleCamera } = useCamera(); + +