165 lines
5.0 KiB
JavaScript
165 lines
5.0 KiB
JavaScript
import express from "express";
|
|
import http from "http";
|
|
import cors from "cors";
|
|
import { Server } from "socket.io";
|
|
import * as mediasoup from "mediasoup";
|
|
|
|
const app = express();
|
|
|
|
app.use(cors());
|
|
|
|
const server = http.createServer(app);
|
|
const io = new Server(server, {
|
|
path: '/chad/ws',
|
|
cors: {
|
|
origin: '*'
|
|
}
|
|
});
|
|
|
|
let worker;
|
|
let router;
|
|
const transports = new Map(); // socketId -> [transports]
|
|
const producers = new Map(); // socketId -> [producers]
|
|
const consumers = new Map(); // socketId -> [consumers]
|
|
|
|
async function createWorker() {
|
|
worker = await mediasoup.createWorker();
|
|
worker.on("died", () => {
|
|
console.error("mediasoup worker died, exiting...");
|
|
process.exit(1);
|
|
});
|
|
|
|
router = await worker.createRouter({
|
|
mediaCodecs: [
|
|
{
|
|
kind: "audio",
|
|
mimeType: "audio/opus",
|
|
clockRate: 48000,
|
|
channels: 2,
|
|
}
|
|
],
|
|
});
|
|
|
|
console.log("Mediasoup worker & router created");
|
|
}
|
|
|
|
createWorker();
|
|
|
|
io.on("connection", (socket) => {
|
|
console.log("Client connected:", socket.id);
|
|
|
|
socket.emit('producers', Array.from(producers.values()).flatMap(producers => {
|
|
return producers.map(producer => {
|
|
return {
|
|
producerId: producer.id,
|
|
kind: producer.kind,
|
|
}
|
|
})
|
|
}))
|
|
|
|
socket.on("getRtpCapabilities", (cb) => {
|
|
cb(router.rtpCapabilities);
|
|
});
|
|
|
|
socket.on("createTransport", async (cb) => {
|
|
try {
|
|
const transport = await router.createWebRtcTransport({
|
|
listenInfos: [
|
|
{
|
|
protocol: 'udp',
|
|
ip: "0.0.0.0",
|
|
announcedIp: "91.144.171.182",
|
|
portRange: {
|
|
min: 40000,
|
|
max: 40100
|
|
}
|
|
}
|
|
],
|
|
enableUdp: true,
|
|
preferUdp: true,
|
|
});
|
|
|
|
transports.set(socket.id, [...(transports.get(socket.id) || []), transport]);
|
|
|
|
cb({
|
|
id: transport.id,
|
|
iceParameters: transport.iceParameters,
|
|
iceCandidates: transport.iceCandidates,
|
|
dtlsParameters: transport.dtlsParameters,
|
|
});
|
|
|
|
transport.observer.on("close", () => {
|
|
console.log("transport closed", transport.id);
|
|
});
|
|
} catch (err) {
|
|
console.error("createTransport error:", err);
|
|
cb({ error: err.message });
|
|
}
|
|
});
|
|
|
|
socket.on("connectTransport", async ({ transportId, dtlsParameters }, cb) => {
|
|
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
|
|
if (!transport) return cb({ error: "transport not found" });
|
|
await transport.connect({ dtlsParameters });
|
|
cb({ connected: true });
|
|
});
|
|
|
|
socket.on("produce", async ({ transportId, kind, rtpParameters }, cb) => {
|
|
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
|
|
if (!transport) return cb({ error: "transport not found" });
|
|
|
|
const producer = await transport.produce({ kind, rtpParameters });
|
|
producers.set(socket.id, [...(producers.get(socket.id) || []), producer]);
|
|
|
|
cb({ id: producer.id });
|
|
socket.broadcast.emit("newProducer", { producerId: producer.id, kind: producer.kind });
|
|
|
|
producer.observer.on("close", () => {
|
|
console.log("producer closed", producer.id);
|
|
});
|
|
});
|
|
|
|
socket.on("consume", async ({ producerId, transportId, rtpCapabilities }, cb) => {
|
|
try {
|
|
if (!router.canConsume({ producerId, rtpCapabilities })) {
|
|
return cb({ error: "cannot consume" });
|
|
}
|
|
|
|
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
|
|
if (!transport) return cb({ error: "transport not found" });
|
|
|
|
const consumer = await transport.consume({
|
|
producerId,
|
|
rtpCapabilities,
|
|
paused: false,
|
|
});
|
|
|
|
consumers.set(socket.id, [...(consumers.get(socket.id) || []), consumer]);
|
|
|
|
cb({
|
|
id: consumer.id,
|
|
producerId,
|
|
kind: consumer.kind,
|
|
rtpParameters: consumer.rtpParameters,
|
|
});
|
|
} catch (err) {
|
|
console.error("consume error:", err);
|
|
cb({ error: err.message });
|
|
}
|
|
});
|
|
|
|
socket.on("disconnect", () => {
|
|
console.log("Client disconnected:", socket.id);
|
|
|
|
transports.get(socket.id)?.forEach((t) => t.close());
|
|
producers.get(socket.id)?.forEach((p) => p.close());
|
|
consumers.get(socket.id)?.forEach((c) => c.close());
|
|
|
|
transports.delete(socket.id);
|
|
producers.delete(socket.id);
|
|
consumers.delete(socket.id);
|
|
});
|
|
});
|
|
|
|
server.listen(process.env.PORT || 3000);
|