Spaces:
Sleeping
Sleeping
| // server.js | |
| const http = require('http'); | |
| const WebSocket = require('ws'); | |
| const mediasoup = require('mediasoup'); | |
| const PORT = 7860; | |
| let worker, router; | |
| const producerTransports = new Map(); // ws → { transport, producer } | |
| const consumerTransports = new Map(); // ws → [ { transport, consumer } ] | |
| (async () => { | |
| // 1) Start HTTP + WebSocket server | |
| const server = http.createServer(); | |
| const wss = new WebSocket.Server({ server }); | |
| server.listen(PORT, () => console.log(`Server running on ${PORT}`)); | |
| // 2) Create a single Mediasoup Worker + Router | |
| worker = await mediasoup.createWorker(); | |
| router = await worker.createRouter({ mediaCodecs: [ | |
| { kind: 'audio', mimeType: 'audio/opus', clockRate: 48000, channels: 2 }, | |
| { kind: 'video', mimeType: 'video/VP8', clockRate: 90000 }, | |
| ]}); | |
| wss.on('connection', ws => { | |
| ws.on('message', async msg => { | |
| const { action, data } = JSON.parse(msg); | |
| switch (action) { | |
| case 'createProducerTransport': { | |
| // Create transport for broadcaster | |
| const transport = await router.createWebRtcTransport({ listenIps: ['127.0.0.1'], enableUdp: true, enableTcp: true }); | |
| producerTransports.set(ws, { transport, producer: null }); | |
| ws.send(JSON.stringify({ | |
| action: 'producerTransportCreated', | |
| data: { id: transport.id, iceParameters: transport.iceParameters, iceCandidates: transport.iceCandidates, dtlsParameters: transport.dtlsParameters } | |
| })); | |
| break; | |
| } | |
| case 'connectProducerTransport': { | |
| const { dtlsParameters } = data; | |
| const { transport } = producerTransports.get(ws); | |
| await transport.connect({ dtlsParameters }); | |
| ws.send(JSON.stringify({ action: 'producerTransportConnected' })); | |
| break; | |
| } | |
| case 'produce': { | |
| const { kind, rtpParameters } = data; | |
| const { transport } = producerTransports.get(ws); | |
| const producer = await transport.produce({ kind, rtpParameters }); | |
| producerTransports.get(ws).producer = producer; | |
| ws.send(JSON.stringify({ action: 'produced', data: { producerId: producer.id } })); | |
| break; | |
| } | |
| case 'createConsumerTransport': { | |
| // Create transport for a viewer | |
| const transport = await router.createWebRtcTransport({ listenIps: ['127.0.0.1'], enableUdp: true, enableTcp: true }); | |
| const arr = consumerTransports.get(ws) || []; | |
| arr.push({ transport, consumer: null }); | |
| consumerTransports.set(ws, arr); | |
| ws.send(JSON.stringify({ | |
| action: 'consumerTransportCreated', | |
| data: { id: transport.id, iceParameters: transport.iceParameters, iceCandidates: transport.iceCandidates, dtlsParameters: transport.dtlsParameters } | |
| })); | |
| break; | |
| } | |
| case 'connectConsumerTransport': { | |
| const { dtlsParameters } = data; | |
| // assume latest transport | |
| const arr = consumerTransports.get(ws); | |
| await arr[arr.length - 1].transport.connect({ dtlsParameters }); | |
| ws.send(JSON.stringify({ action: 'consumerTransportConnected' })); | |
| break; | |
| } | |
| case 'consume': { | |
| // find the broadcaster’s producer | |
| const producerEntry = [...producerTransports.values()].find(e => e.producer); | |
| if (!producerEntry) { | |
| ws.send(JSON.stringify({ action: 'consumeError', data: 'No producer available yet' })); | |
| return; | |
| } | |
| const producer = producerEntry.producer; | |
| const arr = consumerTransports.get(ws); | |
| const { transport } = arr[arr.length - 1]; | |
| const consumer = await transport.consume({ | |
| producerId: producer.id, | |
| rtpCapabilities: router.rtpCapabilities, | |
| paused: false | |
| }); | |
| arr[arr.length - 1].consumer = consumer; | |
| ws.send(JSON.stringify({ | |
| action: 'consumed', | |
| data: { | |
| producerId: producer.id, | |
| id: consumer.id, | |
| kind: consumer.kind, | |
| rtpParameters: consumer.rtpParameters | |
| } | |
| })); | |
| break; | |
| } | |
| } | |
| }); | |
| }); | |
| })(); |