<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
<script>
const h = {
getIceServer() {
return {
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:global.stun.twilio.com:3478",
],
},
],
};
},
getUserFullMedia() {
return navigator.mediaDevices.getUserMedia({
video: true,
audio: {
echoCancellation: true,
noiseSuppression: true,
},
});
},
};
function getPartnerNameFromUrl() {
const pathSegments = window.location.pathname.split("/");
return pathSegments[2];
}
(async function initWebRTC() {
const partnerName = getPartnerNameFromUrl();
if (!partnerName) {
console.error("partnerName not found in URL");
return;
}
let pc = new RTCPeerConnection(h.getIceServer());
let socket = io("/stream");
let username = "";
let myStream = "";
try {
myStream = await h.getUserFullMedia();
socket.emit("subscribe", {
room: partnerName,
username: username,
});
socket.on("newUserStart", (data) => {
init(false, data.sender);
});
socket.on("ice candidates", async (data) => {
if (data.candidate) {
await pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
});
socket.on("sdp", async (data) => {
if (data.description.type === "offer") {
await pc.setRemoteDescription(new RTCSessionDescription(data.description));
myStream = await h.getUserFullMedia();
myStream.getTracks().forEach((track) => {
pc.addTrack(track, myStream);
});
let answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
socket.emit("sdp", {
description: pc.localDescription,
to: data.sender,
sender: username,
});
} else if (data.description.type === "answer") {
// Ensure we're in the correct state to set the remote description
if (pc.signalingState === "have-local-offer") {
await pc.setRemoteDescription(new RTCSessionDescription(data.description));
} else {
console.error("Unexpected state for setting remote description:", pc.signalingState);
}
}
});
} catch (error) {
console.error("Error initializing WebRTC:", error);
}
function init(createOffer, partnerName) {
if (createOffer) {
pc.onnegotiationneeded = async () => {
let offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit("sdp", {
description: pc.localDescription,
to: partnerName,
sender: username,
});
};
}
pc.onicecandidate = ({ candidate }) => {
socket.emit("ice candidates", {
candidate: candidate,
to: partnerName,
sender: username,
});
};
pc.ontrack = (e) => {
displayRemoteStream(e.streams[0]);
};
}
function displayRemoteStream(stream) {
const existingVideo = document.querySelector(".remote-video");
if (existingVideo) {
existingVideo.srcObject = stream;
} else {
const partnerName = getPartnerNameFromUrl();
const video = document.createElement("video");
video.id = `${partnerName}-video`;
video.srcObject = stream;
video.autoplay = true;
video.controls = true;
video.className = "remote-video";
const videoContainer = document.getElementById("videos");
videoContainer.appendChild(video);
}
}
})();
</script>