const socket = io(); const urlParams = new URLSearchParams(window.location.search); const roomId = urlParams.get("room"); const name = urlParams.get("name"); document.getElementById("roomTitle").innerText = "Room: " + roomId; let localStream; let peers = {}; async function start() { localStream = await navigator.mediaDevices.getUserMedia({ audio: true }); socket.emit("join-room", { roomId, name }); socket.on("all-users", (users) => { for (let id in users) { if (id !== socket.id) createPeer(id); addUser(users[id]); } }); socket.on("user-joined", ({ id, name }) => { createPeer(id); addUser(name); }); socket.on("signal", async ({ from, data }) => { if (!peers[from]) createPeer(from, false); if (data.sdp) { await peers[from].setRemoteDescription(data.sdp); if (data.sdp.type === "offer") { const answer = await peers[from].createAnswer(); await peers[from].setLocalDescription(answer); socket.emit("signal", { to: from, data: { sdp: peers[from].localDescription } }); } } if (data.candidate) { await peers[from].addIceCandidate(data.candidate); } }); socket.on("user-left", (id) => { if (peers[id]) peers[id].close(); }); } function createPeer(id, initiator = true) { const peer = new RTCPeerConnection(); localStream.getTracks().forEach(track => peer.addTrack(track, localStream)); peer.onicecandidate = (e) => { if (e.candidate) { socket.emit("signal", { to: id, data: { candidate: e.candidate } }); } }; peer.ontrack = (e) => { const audio = document.createElement("audio"); audio.srcObject = e.streams[0]; audio.autoplay = true; document.body.appendChild(audio); }; peers[id] = peer; if (initiator) { peer.createOffer().then(offer => { peer.setLocalDescription(offer); socket.emit("signal", { to: id, data: { sdp: offer } }); }); } } function addUser(name) { const div = document.createElement("div"); div.innerText = "👤 " + name; document.getElementById("users").appendChild(div); } start();