Shared Core Compact Call Tutorial
Build the headless compact-call core with mediasfu-shared@1.1.0. Your app owns
the renderer and its socket/transport lifecycle; this controller owns the
published participant, media, screen-share, and personal-leave operations.
Prerequisites
- Node.js 18 to 20 and a TypeScript application that owns its room socket and transports.
- A renderer that can display participants, audio/video tracks, alerts, and navigation.
- An authenticated backend for hosted room authority; no MediaSFU credential goes in the client.
Project files
{"private":true,"type":"module","scripts":{"typecheck":"tsc --noEmit"},"dependencies":{"mediasfu-shared":"1.1.0","mediasoup-client":"3.20.0","socket.io-client":"4.8.3"},"devDependencies":{"typescript":"5.9.3"}}
{"compilerOptions":{"strict":true,"target":"ES2022","module":"ESNext","moduleResolution":"bundler","lib":["DOM","ES2022"],"skipLibCheck":true,"noEmit":true},"include":["src/**/*.ts"]}
import { allMembers, clickAudio, clickScreenShare, clickVideo, confirmExit, processConsumerTransports } from 'mediasfu-shared';
export type RoomRenderer={renderParticipants():void;renderMedia():void;reportFailure(message:string):void;clearRoom():void};
export type SharedRoomRuntime={participants:Parameters<typeof allMembers>[0];microphone:Parameters<typeof clickAudio>[0];camera:Parameters<typeof clickVideo>[0];remoteMedia:Parameters<typeof processConsumerTransports>[0];screenShare:Parameters<typeof clickScreenShare>[0];leave:Parameters<typeof confirmExit>[0]};
export class SharedRoomController {
constructor(private readonly runtime:SharedRoomRuntime,private readonly renderer:RoomRenderer){}
async refreshParticipants(){await allMembers(this.runtime.participants);this.renderer.renderParticipants()}
async toggleMicrophone(){await clickAudio(this.runtime.microphone)}
async toggleCamera(){await clickVideo(this.runtime.camera)}
async receiveMedia(){await processConsumerTransports(this.runtime.remoteMedia);this.renderer.renderMedia()}
async toggleScreenShare(){await clickScreenShare(this.runtime.screenShare)}
leaveRoom(){confirmExit(this.runtime.leave);this.renderer.clearRoom()}
report(error:unknown){this.renderer.reportFailure(error instanceof Error?error.message:'The room action failed.')}
}
import type { RoomRenderer, SharedRoomRuntime } from './room-core';
export type AuthorizedRoom={roomName:string;member:string};
export type RoomAuthority={join(input:{meetingId:string;displayName:string}):Promise<AuthorizedRoom>};
export type RoomApplication={authority:RoomAuthority;runtime:SharedRoomRuntime;renderer:RoomRenderer};
RoomApplication is the explicit boundary: after your authenticated backend
authorizes entry, your existing socket/transport lifecycle fills
SharedRoomRuntime; your renderer mounts the tracks and controls.
Run
npm install
npm run typecheck
Expected result
Your application can construct SharedRoomController from its live room state.
Refreshing participants updates your renderer; microphone, camera, remote
media, screen share, and Leave call the matching shared-core operation.
Recovery
Keep device denial, a missing device, transport failure, paused remote media, autoplay blocking, and screen-selection cancellation distinct in the renderer. Rebuild live runtime state after reconnecting before retrying an operation.
Cleanup
Call leaveRoom, stop application-owned tracks and transports, unmount the
renderer, and clear application state. This is personal leave, not a host-wide
end operation.
Release boundary
The authenticated backend creates or authorizes hosted rooms and returns only
the room information your application needs. mediasfu-shared is a core
library, not a rendered-room or secure client-side room-creation SDK; do not
call its hosted create/join helper with a browser API key.