The frontend is a Next.js 16 project built with App Router, TypeScript, and Tailwind CSS.
- App Router: Uses server-side rendering (SSR) by default for layout but manages stateful WebRTC logic in Client components.
- Dynamic Routing: The
room/[roomId]segment allows direct access to isolated meeting rooms.
Handling Mediasoup in the browser is complex and involves several asynchronous steps. We use a custom MediasoupClient wrapper class located in src/lib/mediasoup.ts.
export class MediasoupClient {
private ws: WebSocket | null = null;
private device: Device | null = null;
private sendTransport: types.Transport | null = null;
private recvTransport: types.Transport | null = null;
private producers: Map<string, types.Producer> = new Map();
private consumers: Map<string, types.Consumer> = new Map();
// ... callbacks for UI integration
}- WebSocket
request: Each message sent usingrequest()includes arequestId. A Promise is created and stored in apendingRequestsMap, which is resolved when the server sends a matchingresponse. - Media Transports: The
initTransports()method invokescreate-transporton the server and then callsdevice.createSendTransport()ordevice.createRecvTransport()with the server-provided parameters. - Producing: The
produce(track)method uses thesendTransportand updates the internalproducersmap. - Consuming: The
consume(producerId)method asks the server to create a consumer and then initializes it locally on therecvTransport.
- Lobby Preview: The camera is turned on immediately for the user to adjust their appearance.
- HandleJoin():
MediasoupClientis instantiated with room-specific callbacks.client.connect(token)establishes the WebSocket connection.client.joinRoom()gets the initial state and room capabilities.client.initTransports()prepares the sending and receiving pipelines.client.produce(track)publishes the local streams.
- State Map:
remoteStreamsis aMap<string, { stream: MediaStream, userName: string }>that reactive components iterate over to render the video grid. - Component Lifecycle: We use
useEffectextensively for cleaning up streams and the WebSocket connection when the component unmounts.
- React Refs (
useRef): Crucial for persistent objects like theMediasoupClientandlocalVideoelements that must survive re-renders. - React State (
useState): Manages UI flags (showLobby,isJoined), local media tracks, and theremoteStreamsmap. - Cleanup: The
useEffectcleanup function ensures that WebSockets are closed and camera tracks are stopped when the user leaves.