const socket = io(); const peerConnections = {}; const startBtn = document.getElementById('startBtn'); const localVideo = document.getElementById('localVideo'); const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); let activeStream; const config = { iceServers: [ { urls: "stun:stun.l.google.com:19302" } ] }; socket.on('viewer', id => { if (!activeStream) return; const peerConnection = new RTCPeerConnection(config); peerConnections[id] = peerConnection; activeStream.getTracks().forEach(track => { peerConnection.addTrack(track, activeStream); }); peerConnection.onicecandidate = event => { if (event.candidate) { socket.emit('candidate', id, event.candidate); } }; peerConnection .createOffer() .then(sdp => peerConnection.setLocalDescription(sdp)) .then(() => { socket.emit('offer', id, peerConnection.localDescription); }); }); socket.on('answer', (id, description) => { if (peerConnections[id]) { peerConnections[id].setRemoteDescription(description); } }); socket.on('candidate', (id, candidate) => { if (peerConnections[id]) { peerConnections[id].addIceCandidate(new RTCIceCandidate(candidate)); } }); socket.on('disconnectPeer', id => { if (peerConnections[id]) { peerConnections[id].close(); delete peerConnections[id]; } }); startBtn.addEventListener('click', async () => { try { const stream = await navigator.mediaDevices.getDisplayMedia({ video: { width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 60 } }, audio: false }); activeStream = stream; localVideo.srcObject = stream; localVideo.classList.add('active'); startBtn.style.display = 'none'; statusDot.classList.add('active'); statusText.innerText = 'Sharing Screen (1080p60)'; socket.emit('broadcaster'); stream.getVideoTracks()[0].onended = () => { stopSharing(); }; } catch (err) { console.error("Error accessing display media.", err); statusText.innerText = 'Failed to access screen'; statusDot.style.backgroundColor = 'var(--error-color)'; } }); function stopSharing() { startBtn.style.display = 'inline-block'; localVideo.classList.remove('active'); statusDot.classList.remove('active'); statusText.innerText = 'Not Sharing'; activeStream = null; socket.emit('disconnect'); }