Skip to main content

React Native Secure Room Operations

This guide shows a small, reproducible room lifecycle for mediasfu-reactnative 2.4.0: create or join through your backend, observe participants, distinguish device permission from active media, recover from request failures, and clean up app-owned resources.

The included example type-checks against the package's generated 2.4.0 declarations. Its local tests exercise request shaping and state predicates without contacting MediaSFU or opening a device. Run the final integration on physical Android and iOS devices before shipping.

Keep credentials on your backend

Your mobile bundle is inspectable. Do not place a reusable MediaSFU API key in application code, build configuration, over-the-air updates, or device storage.

Inject backend-backed room functions into the supplied room component:

const adapters = createBackendRoomAdapters(
appFetch,
runtimeConfig.applicationBackendBaseUrl,
);

<ModernMediasfuGeneric
connectMediaSFU
createMediaSFURoom={adapters.createMediaSFURoom}
joinMediaSFURoom={adapters.joinMediaSFURoom}
returnUI
/>

React Native has no same-origin application server. Pass an absolute HTTPS URL for your application backend and an injected HTTP client that applies the current user's app authentication. Keep reusable MediaSFU credentials on the backend; do not embed them in the mobile client or this URL.

The adapter deliberately ignores the credential-shaped arguments passed by the component. It sends only the requested room payload to your authenticated application routes:

import type {
CreateRoomOnMediaSFUType,
JoinRoomOnMediaSFUType,
} from 'mediasfu-reactnative';

const backendBaseUrl = runtimeConfig.applicationBackendBaseUrl;
const createUrl = new URL('rooms/create', backendBaseUrl).toString();
const joinUrl = new URL('rooms/join', backendBaseUrl).toString();

// appFetch is your configured client. It adds the signed-in user's short-lived
// application session without exposing a reusable MediaSFU credential.
export const createMediaSFURoom: CreateRoomOnMediaSFUType = async ({ payload }) => {
const response = await appFetch(createUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) throw new Error(`Create failed: ${response.status}`);
return response.json();
};

export const joinMediaSFURoom: JoinRoomOnMediaSFUType = async ({ payload }) => {
const response = await appFetch(joinUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) throw new Error(`Join failed: ${response.status}`);
return response.json();
};

Configure applicationBackendBaseUrl as an absolute HTTPS base such as https://api.example.test/. The complete local example rejects relative and non-HTTPS values, adds typed error classification, and keeps networking injectable for deterministic tests.

Your backend remains responsible for user authentication, allowed room type, capacity and duration limits, host authority, rate limiting, and the protected MediaSFU request.

Observe the room without inventing success

Use updateSourceParameters to receive the latest room state. Treat each state separately:

  • A participant name in participants confirms a state update, not remote media playback.
  • Microphone permission confirms access to the device, not an active audio producer.
  • audioAlreadyOn === true or videoAlreadyOn === true is a useful UI observation, but verify on another device that the intended media is actually received.

The example's mediaReadiness predicate requires both granted permission and an explicit active-media observation. This prevents the UI from reporting "ready" immediately after a permission prompt.

Handle failures deliberately

ResultUser experienceRetry policy
401 or 403Explain that the session or role is not authorizedRe-authenticate or request access; do not loop
404Explain that the room is unavailableAsk for a corrected room or invitation
429Explain that requests are temporarily limitedRetry after backoff
5xx or network interruptionPreserve safe user input and show a reconnect actionRetry with bounded backoff
Device permission deniedKeep the user in control and link to platform settingsRetry only after the user changes permission

Never fall back to a client-held API key after a backend error.

Validate on real devices

For both Android and iOS, verify:

  1. First-run microphone and camera permission.
  2. Denial, later approval in system settings, and app resume.
  3. Local microphone and camera start/stop.
  4. Remote audio and video on a second device.
  5. Background/foreground transitions and route changes such as speaker, earpiece, and Bluetooth.
  6. Screen-share availability and stop behavior on each supported OS version.
  7. Network loss, reconnect, participant leave, and host-ended room behavior.

A simulator can help with layout and state tests, but it cannot validate capture, audio routing, screen sharing, or teardown. Test those behaviors on physical devices.

Leave and clean up

Use the supplied role-aware exit UI for the visible leave action. After a participant leaves, your application should also:

  • stop app-owned local tracks;
  • remove app-owned subscriptions and timers;
  • close the room screen only after the leave action is accepted or a safe fallback is shown;
  • clear participant and media snapshots so a later room cannot display stale state.

A headless host can end the room or leave it running through the current hook:

import { Button } from 'react-native';
import { useMediasfuHeadless } from 'mediasfu-reactnative';

export function HostExitButtons() {
const room = useMediasfuHeadless();
return <>
<Button title="End room" onPress={() => void room.controls.leave(false, true)} />
<Button title="Leave and keep room open" onPress={() => void room.controls.leave(false, false)} />
</>;
}

The second argument defaults to true. Await the chosen action before closing the screen; a host who preserved the room returns through the normal authorized join flow.

Build and test your application, then verify actual track shutdown and room cleanup on physical devices. A JavaScript test cannot prove native capture, audio routing, remote playback, or operating-system cleanup.

Next, use the React Native SDK guide for native project setup and Secure backend proxy for the server-side boundary.