const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const webrtc = require('wrtc'); // Instead of one global stream, keep one per room const roomStreams = {}; // { [roomId]: MediaStream } app.use(express.static('public')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // Consumer endpoint: front-end must POST { sdp, roomId } app.post("/consumer", async ({ body }, res) => { const { sdp, roomId } = body; const stream = roomStreams[roomId]; if (!stream) { return res.status(404).json({ error: "No broadcast for room " + roomId }); } const peer = new webrtc.RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org" }] }); // add the broadcaster’s tracks for this room stream.getTracks().forEach(track => peer.addTrack(track, stream)); await peer.setRemoteDescription(new webrtc.RTCSessionDescription(sdp)); const answer = await peer.createAnswer(); await peer.setLocalDescription(answer); res.json({ sdp: peer.localDescription }); }); // Broadcast endpoint: front-end must POST { sdp, roomId } app.post("/broadcast", async ({ body }, res) => { const { sdp, roomId } = body; const peer = new webrtc.RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org" }] }); peer.ontrack = ({ streams }) => { // store the incoming stream under its roomId roomStreams[roomId] = streams[0]; }; await peer.setRemoteDescription(new webrtc.RTCSessionDescription(sdp)); const answer = await peer.createAnswer(); await peer.setLocalDescription(answer); res.json({ sdp: peer.localDescription }); }); app.listen(7860, () => console.log('SFU server running on port 5000'));