Skip to main content

Build an app-owned MediaSFU room with the shared core

Use mediasfu-shared 1.1.0 when you are building every visible part of the room yourself. It is a TypeScript runtime, not a rendered room SDK: your app owns screens, controls, participant tiles, error messages, and navigation.

This guide wires the shared-core operations for joining, participant updates, media permission and controls, remote media, screen sharing, and participant exit. It does not put reusable MediaSFU credentials in a client application.

What you need

  • mediasfu-shared 1.1.0 plus compatible mediasoup-client and socket.io-client peer dependencies, resolved through your approved package source.
  • An authenticated application backend that decides who may create or join a room and gives the client only the room authority it needs.
  • A socket, media-device implementation, and the complete parameter objects required by each shared-core action. Your app creates and maintains these objects.
  • Camera, microphone, and display-capture permissions for every target browser or desktop shell.

Keep room authority on your backend

The exported joinRoomOnMediaSFU helper accepts apiUserName and apiKey. Do not call it from a browser or bundled client. Instead, make your app call an authenticated backend endpoint; that endpoint may use the helper or an equivalent server-side integration and returns only the room result your app needs.

import type { JoinRoomOnMediaSFUType } from 'mediasfu-shared';

type JoinResult = Awaited<ReturnType<JoinRoomOnMediaSFUType>>;

export interface RoomGateway {
join(input: { meetingId: string; displayName: string }): Promise<JoinResult>;
}

export async function joinFromApp(
gateway: RoomGateway,
meetingId: string,
displayName: string,
) {
const result = await gateway.join({ meetingId, displayName });
if (!result.success) {
throw new Error('The room could not be joined. Check access and try again.');
}
return result;
}

A successful result lets your app begin its socket and media setup. For a rejected invitation, expired application session, or unavailable room, keep the person out of the room, explain the failure, and obtain a fresh backend result before retrying.

There is no safe client-side room.create.secure recipe in this package: its direct create helper also accepts reusable credentials. Keep room creation in your backend.

Bind the room operations

The following binding uses exact public shared-core operations. It does not render anything or open a network connection by itself; your app invokes each operation when its socket and runtime parameter object are ready.

import {
allMembers,
checkPermission,
clickAudio,
clickVideo,
processConsumerTransports,
clickScreenShare,
confirmExit,
} from 'mediasfu-shared';

export const roomCore = {
receiveMembers: allMembers,
checkPermission,
toggleMicrophone: clickAudio,
toggleCamera: clickVideo,
receiveRemoteMedia: processConsumerTransports,
toggleScreenShare: clickScreenShare,
leaveParticipant: confirmExit,
};

allMembers is the participant-update operation. Give it the complete member payload and your app's update callbacks; when it resolves, render the participant collection your callbacks received. It is not a visual participant list and it does not create one for you.

Call checkPermission before a custom microphone, camera, or screen-share control. Its result is 0 for allow, 1 for approval, and 2 for denied or unavailable. Show a request or denial state for 1 and 2; only continue to the appropriate media action for 0.

const decision = await roomCore.checkPermission({
permissionType: 'screenshareSetting',
audioSetting: 'allow',
videoSetting: 'allow',
screenshareSetting: 'approval',
chatSetting: 'allow',
});

if (decision === 0) {
// Call roomCore.toggleScreenShare with your complete runtime parameters.
}

clickAudio and clickVideo use your parameter object's device, socket, transport, role, permission, and state-update functions to produce or stop local media. processConsumerTransports uses its transport and stream inputs to connect remote media. Render the local or remote tracks in your own UI only after your state updates show that they are available. If a device permission, transport, or socket step fails, keep the room usable, show a retry control, and do not display a track as active until your own state confirms it.

clickScreenShare checks restrictions and either starts or stops screen share through the functions in its parameter object. A successful start should update your app's screen-sharing state and make the selected display visible in the UI; on picker cancellation or denial, keep the person in the room and leave their camera and microphone controls available.

Let a participant leave

After your own confirmation screen, call the headless leaveRoom action with the latest parameters:

import { leaveRoom } from 'mediasfu-shared';

const participantLeaveOrHostEnd = () => leaveRoom({
parameters: latestParameters,
endRoomOnHostExit: true,
});

const hostLeaveAndKeepOpen = () => leaveRoom({
parameters: latestParameters,
endRoomOnHostExit: false,
});

The option defaults to true. Use false only for a separately labelled host action. Then clear local tracks, room state, timers, and navigation state. A framework wrapper must publicly bind this shared action before its users can rely on it.

Release checklist

  • The app uses an authenticated backend for create and join authority; no reusable MediaSFU credential is shipped to a client.
  • The app renders participant updates received through its allMembers callbacks.
  • Permission outcomes have visible allow, request, and denial states.
  • Local microphone/camera and remote media are shown only after app state confirms the tracks.
  • Screen share has both a visible start state and a reliable stop path.
  • Participant leave, host preserve-room leave, and host end are labelled separately and clear local media only after the selected result.

The isolated shared-core example for this guide type-checks the exported bindings and runs deterministic, no-network policy tests. It does not open a room, request a device, or contact a service.