Building an Omegle Clone with React.js, WebRTC, and Socket.io
In this blog post, we'll walk you through the process of creating a real-time video chat application similar to Omegle using popular web technologies. We'll leverage React.js to handle the frontend user interface, WebRTC for real-time peer-to-peer video streaming, and Socket.io for establishing seamless connections between users.
#Server Side Setup
1) Create A server
const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const cors = require("cors");
const { Server } = require("socket.io");
const io = new Server(server);
const port = process.env.PORT || 5000;
app.use(cors());
server.listen(port, () => {
console.log("listening on *:5000"); // Correct the console log port number to match the actual port
});
2) Setup the socket.io
const updateTextChatUsers = (userid, updatedAvailable, updatedRoom) => {
textChatUsers = textChatUsers.map((user) => {
if (user.userid === userid) {
return {
...user,
available: updatedAvailable,
room: updatedRoom,
};
}
return user;
});
};
const updateConnectedUser = (userid, updatedAvailable, updatedRoom) => {
connectedUsers = connectedUsers.map((user) => {
if (user.userid === userid) {
return {
...user,
available: updatedAvailable,
room: updatedRoom,
};
}
return user;
});
};
socket.on("userJoined", ({ userid, type }) => {
try {
if (userid == null) {
return;
}
console.log(userid, type);
// check the type of connection either video or text and push the user accordingly
if (type == "video") {
connectedUsers.push({
userid: userid,
available: true,
room: null,
});
pair.set(userid, "video");
io.emit("videoChatCount", { length: connectedUsers.length });
// if there is morethan 2 users in the room and if they are not connected to anyone then two users will be picked and connected randomly
if (connectedUsers.length >= 2) {
const usersArray = Array.from(connectedUsers);
const excludeme = usersArray.filter(
(user) => user.userid !== userid && user.available === true
);
if (excludeme.length > 0) {
const randomIndex1 = Math.floor(Math.random() * excludeme.length);
const user1 = excludeme[randomIndex1].userid;
const user2 = userid;
const room = `room-${user1}-${user2}`;
const updateConnectedUser = (
userid,
updatedAvailable,
updatedRoom
) => {
connectedUsers = connectedUsers.map((user) => {
if (user.userid === userid) {
return {
...user,
available: updatedAvailable,
room: updatedRoom,
};
}
return user;
});
};
updateConnectedUser(user1, false, room);
updateConnectedUser(user2, false, room);
socket.join(room);
io.to(user1).emit("roomCreated", {
roomName: room,
remoteUser: user2,
});
io.to(user2).emit("roomCreated", {
roomName: room,
remoteUser: user1,
createPermission: true,
});
}
}
} else {
textChatUsers.push({
userid: userid,
available: true,
room: null,
});
pair.set(userid, "text");
io.emit("textChatCount", { length: textChatUsers.length });
if (textChatUsers.length >= 2) {
const usersArray = Array.from(textChatUsers);
const excludeme = usersArray.filter(
(user) => user.userid !== userid && user.available === true
);
if (excludeme.length > 0) {
const randomIndex1 = Math.floor(Math.random() * excludeme.length);
const user1 = excludeme[randomIndex1].userid;
const user2 = userid;
const room = `room-${user1}-${user2}`;
updateTextChatUsers(user1, false, room);
updateTextChatUsers(user2, false, room);
socket.join(room);
io.to(user1).emit("roomCreated", {
roomName: room,
remoteUser: user2,
});
io.to(user2).emit("roomCreated", {
roomName: room,
remoteUser: user1,
createPermission: true,
});
}
}
}
} catch (error) {
console.log("error", error);
}
});3) Handle the socket.io on user disconnect
socket.on("disconnect", () => {
try {
const roomType = pair.get(socket.id);
if (roomType == undefined) {
return;
}
console.log("Disconnected", socket.id, roomType, connectedUsers);
if (roomType == "video") {
const leavinguser = connectedUsers.find(
(user) => user.userid == socket.id
);
if (!leavinguser) {
return;
}
if (!leavinguser.room) {
connectedUsers = connectedUsers.filter(
(user) =>
user.userid !== undefined && user.userid !== leavinguser.userid
);
return;
}
connectedUsers = connectedUsers.filter(
(user) => user.userid !== socket.id
);
console.log(socket.id, "disconnected", leavinguser);
const findRemoteUser = connectedUsers.find(
(user) => user.room == leavinguser.room
);
updateConnectedUser(findRemoteUser.userid, true, null);
socket.to(findRemoteUser.userid).emit("userDisconnected");
io.emit("videoChatCount", { length: connectedUsers.length });
socket.disconnect();
// console.log(findUser);
console.log(leavinguser, connectedUsers, "here");
// console.log(findUser[0]);
// delete connectedUsers[findUser[0]];
} else {
const leavinguser = textChatUsers.find(
(user) => user.userid == socket.id
);
if (!leavinguser) {
return;
}
if (!leavinguser.room) {
textChatUsers = textChatUsers.filter(
(user) =>
user.userid !== undefined && user.userid !== leavinguser.userid
);
return;
}
textChatUsers = textChatUsers.filter(
(user) => user.userid !== socket.id
);
console.log(socket.id, "disconnected", leavinguser);
const findRemoteUser = textChatUsers.find(
(user) => user.room == leavinguser.room
);
updateTextChatUsers(findRemoteUser.userid, true, null);
console.log(findRemoteUser);
socket.to(findRemoteUser.userid).emit("userDisconnected");
io.emit("textChatCount", { length: textChatUsers.length });
socket.disconnect();
}
// console.log(findUser);
// console.log(leavinguser,connectedUsers,textChatUsers);
} catch (error) {
console.log("error", error);
}
});
});4) Handle the webrtc connection
socket.on("answer", ({ ans, to }) => {
io.to(to).emit("answer", { ans: ans });
});
socket.on("offer", ({ offer, to }) => {
io.to(to).emit("offer", { offer: offer, from: socket.id });
});
socket.on("peer:nego:needed", ({ to, offer }) => {
console.log("peer:nego:needed", offer);
io.to(to).emit("peer:nego:needed", { from: socket.id, offer });
});
socket.on("peer:nego:done", ({ to, ans }) => {
console.log("peer:nego:done", ans);
io.to(to).emit("peer:nego:final", { from: socket.id, ans });
});
socket.on("iceCandidate", ({ iceCandidate, to }) => {
console.log(iceCandidate, to);
io.to(to).emit("iceCandidate", { iceCandidate: iceCandidate });
});
#Client Side Setup
See the full code
Demo
Hope you like this Project...
