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-shared1.1.0 plus compatiblemediasoup-clientandsocket.io-clientpeer 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
allMemberscallbacks. - 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.