⚠️ Internal package. This is a building block of
rtcforge. Unless you need advanced/custom wiring, installrtcforgeand import fromrtcforge/client,rtcforge/server,rtcforge/media, orrtcforge/filetransferinstead.
The media plane for RTCForge — P2P mesh calls and a mediasoup-backed SFU.
Carries the actual audio/video. Two modes:
Call — peer-to-peer mesh with perfect-negotiation, for small groups. Drives RTCPeerConnections over an existing signaling Room.MediaService / MediaRouter — a mediasoup Selective Forwarding Unit (WorkerPool, Producer, Consumer) for larger rooms where mesh doesn't scale.Signaling only lets peers find each other; this is where media flows. Mesh is simplest for 2–4 peers; past that, an SFU forwards each sender's stream once per node instead of N times per sender. This package gives you both behind one API.
rtcforge-sdk (Room) → rtcforge-media
├─ Call → P2P mesh (small)
└─ MediaService → SFU (large) → rtcforge-sfu for multi-node
npm i rtcforge-media # browser P2P mesh (Call) — no native build
npm i rtcforge-media mediasoup # add mediasoup for the server-side SFU
mediasoup is an optional peer dependency (a native addon): browser-only
consumers never download or compile it, and it is lazily imported so importing
this package without it only fails when you actually spawn an SFU worker. Import
the browser plane from rtcforge-media/browser (or the browser export
condition) to keep bundlers clear of any Node/mediasoup types.
Browser P2P mesh:
import { Call, MediaEvent } from "rtcforge-media"; // or "rtcforge-media/browser"
// `room` comes from rtcforge-sdk: await client.joinRoom("my-room")
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
const call = new Call(room, { stream });
call.start();
call.on(MediaEvent.RemoteStream, (peerId, remoteStream) => attachToVideoEl(peerId, remoteStream));
Server-side SFU — MediaService (+ WorkerPool) with SfuSignalHandler driving
the caps→transport→produce→consume handshake over your signaling:
import { MediaService, SfuSignalHandler } from "rtcforge-media";
const media = new MediaService();
await media.init();
const router = await media.attachRoom(room);
const sfu = new SfuSignalHandler(router);
// on an inbound SFU message from `peerId`: reply with await sfu.handle(peerId, msg)
Part of RTCForge. See docs/PUBLISHING.md.