I am working on a WebRTC application using JavaScript and WebSockets. The issue I am encountering is that the remote video stream is being added automatically without the user clicking the “Answer” button. I need the remote video to only be added after the “Answer” button is clicked.I am using websoket to handle signaling in django framework.Any advice is acceptable,thanks in advance.
const url = "ws://127.0.0.1:8000/ws/wc/?group=manish";
const socket = new WebSocket(url);
let localVideo = document.getElementById("localVideo");
let remoteVideo = document.getElementById("remoteVideo");
let peerConnection;
let iceCandidatesQueue = [];
let awaitingAnswer = false;
function createPeerConnection() {
peerConnection = new RTCPeerConnection();
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
console.log("Sending ICE candidate:", event.candidate);
socket.send(JSON.stringify({ type: "ice", ice: event.candidate }));
}
};
peerConnection.ontrack = (event) => {
console.log("Received remote track:", event.track);
if (event.track.kind === "video") {
console.log("Received video track");
if (remoteVideo.srcObject !== event.streams[0]) {
remoteVideo.srcObject = event.streams[0];
console.log("Remote video stream added.");
}
}
};
peerConnection.oniceconnectionstatechange = () => {
console.log("ICE connection state:", peerConnection.iceConnectionState);
};
peerConnection.onsignalingstatechange = () => {
console.log("Signaling state:", peerConnection.signalingState);
};
}
function getUserMediaAndAddTracks() {
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
.then((stream) => {
localVideo.srcObject = stream;
stream
.getTracks()
.forEach((track) => peerConnection.addTrack(track, stream));
})
.catch((error) => {
console.error("Error accessing media devices:", error);
});
}
socket.onopen = (e) => {
console.log("Connection opened:", e);
createPeerConnection();
getUserMediaAndAddTracks();
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Data received:", data);
if (data.type === "sdp") {
const sdp = new RTCSessionDescription(data.sdp);
console.log("SDP received:", sdp);
if (sdp.type === "offer") {
handleOffer(sdp);
} else if (sdp.type === "answer") {
handleAnswer(sdp);
}
} else if (data.type === "ice") {
handleIce(data.ice);
}
};
socket.onclose = (e) => {
console.log("Connection closed:", e);
};
socket.onerror = (e) => {
console.error("WebSocket error:", e);
};
document
.getElementById("send_message_btn")
.addEventListener("click", function (e) {
socket.send(JSON.stringify({ message: "Hello World", type: "message" }));
});
document.getElementById("sdp_btn").addEventListener("click", function (e) {
if (peerConnection.signalingState === "stable") {
peerConnection
.createOffer()
.then((offer) => peerConnection.setLocalDescription(offer))
.then(() => {
console.log("Sending SDP offer...");
socket.send(
JSON.stringify({
type: "sdp",
sdp: peerConnection.localDescription,
})
);
})
.catch((error) => {
console.error("Error creating offer:", error);
});
} else {
console.warn(
"Cannot create offer in signaling state:",
peerConnection.signalingState
);
}
});
document.getElementById("answer").addEventListener("click", function (e) {
if (peerConnection.signalingState === "have-remote-offer") {
peerConnection
.createAnswer()
.then((answer) => peerConnection.setLocalDescription(answer))
.then(() => {
console.log("Sending SDP answer...");
socket.send(
JSON.stringify({
type: "sdp",
sdp: peerConnection.localDescription,
})
);
})
.catch((error) => {
console.error("Error creating answer:", error);
});
} else {
console.warn(
"Cannot create answer in signaling state:",
peerConnection.signalingState
);
}
});
function handleOffer(offer) {
if (peerConnection.signalingState === "stable") {
peerConnection
.setRemoteDescription(offer)
.then(() => {
console.log("Remote description set, creating answer...");
return peerConnection.createAnswer();
})
.then((answer) => {
console.log("Answer created, setting local description...");
return peerConnection.setLocalDescription(answer);
})
.then(() => {
console.log("Local description set, sending SDP answer...");
socket.send(
JSON.stringify({
type: "sdp",
sdp: peerConnection.localDescription,
})
);
processIceCandidates();
})
.catch((error) => {
console.error("Error handling offer:", error);
});
} else {
console.warn(
"Received offer in invalid state:",
peerConnection.signalingState
);
}
}
function handleAnswer(answer) {
if (peerConnection.signalingState === "have-local-offer") {
peerConnection
.setRemoteDescription(answer)
.then(() => {
console.log(
"Remote description set from answer, processing ICE candidates..."
);
processIceCandidates();
})
.catch((error) => {
console.error("Error handling answer:", error);
});
} else {
console.warn(
"Received answer in invalid state:",
peerConnection.signalingState
);
}
}
function handleIce(candidate) {
console.log("Handling ICE candidate:", candidate);
if (peerConnection.remoteDescription) {
peerConnection
.addIceCandidate(new RTCIceCandidate(candidate))
.catch((error) => {
console.error("Error adding ICE candidate:", error);
});
} else {
iceCandidatesQueue.push(candidate);
}
}
function processIceCandidates() {
while (iceCandidatesQueue.length) {
const candidate = iceCandidatesQueue.shift();
peerConnection
.addIceCandidate(new RTCIceCandidate(candidate))
.catch((error) => {
console.error("Error adding queued ICE candidate:", error);
});
}
}
});