const socket = io(); const remoteVideo = document.getElementById('remoteVideo'); const overlay = document.getElementById('overlay'); let peerConnection; const config = { iceServers: [ { urls: "stun:localhost:3478" }, { urls: "turn:localhost:3478", username: "myuser", credential: "mypassword" } ] }; socket.on('offer', (id, description) => { peerConnection = new RTCPeerConnection(config); peerConnection.ontrack = event => { remoteVideo.srcObject = event.streams[0]; remoteVideo.classList.add('active'); overlay.classList.add('hidden'); }; peerConnection.onicecandidate = event => { if (event.candidate) { socket.emit('candidate', id, event.candidate); } }; peerConnection .setRemoteDescription(description) .then(() => peerConnection.createAnswer()) .then(sdp => peerConnection.setLocalDescription(sdp)) .then(() => { socket.emit('answer', id, peerConnection.localDescription); }); }); socket.on('candidate', (id, candidate) => { if (peerConnection) { peerConnection.addIceCandidate(new RTCIceCandidate(candidate)) .catch(e => console.error(e)); } }); socket.on('broadcaster', () => { socket.emit('viewer'); }); socket.on('disconnectPeer', () => { if (peerConnection) { peerConnection.close(); peerConnection = null; } remoteVideo.classList.remove('active'); remoteVideo.srcObject = null; overlay.classList.remove('hidden'); overlay.querySelector('h1').innerText = 'Stream Ended'; overlay.querySelector('.status-indicator span:last-child').innerText = 'Waiting for new stream...'; }); socket.on('connect', () => { socket.emit('viewer'); });