File size: 4,267 Bytes
42e18e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314b7d8
42e18e6
 
 
64a031b
42e18e6
 
 
 
 
 
 
 
 
 
 
64a031b
42e18e6
 
 
 
 
 
 
64a031b
42e18e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 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;
        }
      }
    });
  });
})();