|
# client.js (modified JavaScript) |
|
const localVideo = document.getElementById('localVideo'); |
|
const remoteVideo = document.getElementById('remoteVideo'); |
|
const callBtn = document.getElementById('callBtn'); |
|
const endCallBtn = document.getElementById('endCallBtn'); |
|
|
|
|
|
let peerConnection; |
|
let localStream; |
|
let socket; |
|
let roomId; |
|
let clientId; |
|
|
|
async function init() { |
|
try { |
|
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); |
|
localVideo.srcObject = localStream; |
|
roomId = uuid.v4(); |
|
clientId = uuid.v4(); |
|
socket = new WebSocket(`ws://localhost:8000/ws/${roomId}/${clientId}`); |
|
socket.onmessage = handleSocketMessage; |
|
socket.onopen = startCall; |
|
setupEventListeners(); |
|
optimizerPanel.classList.remove('hidden'); |
|
applyBandwidthPreset(currentBandwidthPreset); |
|
} catch (error) { |
|
console.error('Initialization error:', error); |
|
} |
|
} |
|
|
|
async function startCall() { |
|
if (!localStream) { |
|
alert('Please allow camera and microphone access first.'); |
|
return; |
|
} |
|
|
|
connectionModal.classList.remove('hidden'); |
|
simulateConnectionProgress(); |
|
|
|
try { |
|
peerConnection = new RTCPeerConnection({ |
|
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] |
|
}); |
|
|
|
peerConnection.onicecandidate = handleICECandidate; |
|
peerConnection.ontrack = handleTrack; |
|
|
|
localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream)); |
|
|
|
const offer = await peerConnection.createOffer(); |
|
await peerConnection.setLocalDescription(offer); |
|
|
|
socket.send(JSON.stringify({ type: 'offer', sdp: offer.sdp })); |
|
|
|
} catch (error) { |
|
console.error('Error starting call:', error); |
|
connectionModal.classList.add('hidden'); |
|
alert('Failed to start call. Please try again.'); |
|
} |
|
} |
|
|
|
function handleSocketMessage(event) { |
|
const data = JSON.parse(event.data); |
|
|
|
if (data.type === 'offer' || data.type === 'answer') { |
|
peerConnection.setRemoteDescription(new RTCSessionDescription(data)); |
|
if (data.type === 'offer') { |
|
peerConnection.createAnswer() |
|
.then(answer => peerConnection.setLocalDescription(answer)) |
|
.then(() => socket.send(JSON.stringify({ type: 'answer', sdp: peerConnection.localDescription.sdp }))); |
|
} |
|
} else if (data.type === 'candidate') { |
|
peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate)); |
|
} |
|
|
|
} |
|
|
|
function handleICECandidate(event) { |
|
if (event.candidate) { |
|
socket.send(JSON.stringify({ type: 'candidate', candidate: event.candidate })); |
|
} |
|
} |
|
|
|
function handleTrack(event) { |
|
remoteVideo.srcObject = event.streams[0]; |
|
connectionStatus.textContent = 'Connected'; |
|
connectionStatus.className = 'font-medium text-green-400'; |
|
bandwidthIndicator.classList.remove('hidden'); |
|
updateBandwidthDisplay(); |
|
callBtn.classList.add('hidden'); |
|
endCallBtn.classList.remove('hidden'); |
|
connectionModal.classList.add('hidden'); |
|
isCallActive = true; |
|
} |
|
|
|
|