Creating a video chat with Node.js + Socket.io + WebRTC

7 min


Today, especially for the start a new stream on web development, Let’s share with you a tutorial on how to create a video chat using JavaScript and NodeJS. You will also learn how to use PeerJS, WebRTC and Socket.io.


Here you can see a live example of the application you will be building.

Preparing for the project

Here’s what you need:

  • NodeJS: visit the official Node.js websiteto download and install Node;

  • NPM: NPM is installed on your computer when you install Node.js.

Project setup

All the code for this project can be found in the GitHub repository.

  1. Create an empty directory named video-chat-app.

  2. Open your console, go to our new directory and run npm init.

  3. Fill in the required information to initialize our project.

  4. Run npm install express ejs socket.io uuid peer. The command will install all the dependencies required to build this application.

  5. And also as a dev dependency, install Nodemon… You need to run npm install-dev nodemon. This will install nodemon as a dev dependency.

  6. Create a server.js file – this file will hold all of your server logic.

Now that you have our project set up, you can start building your application!

Server creation (with Express JS)

The first thing you need to do is start your server. We’re going to use Express for this. Express is a minimalistic web framework for Node.js. Express makes it very easy to create and run a web server using Node.

Let’s create an Express starter application template file.

// server.js
const express = require(“express”);
const app = express();
const server = require(“http”).Server(app);
app.get(“/”, (req, res) => {
    res.status(200).send(“Hello World”);
});
server.listen(3030);

Now your server is running, you can test it by running:

> nodemon server.js

Now open your browser and go to localhost: 3000, you should see Hello World.

Creating the first page

Instead of displaying text when someone visits your root route, you would like to send in HTML. To do this, you need to use EJS (Inline JavaScript). EJS is a templating language.

To use EJS in Express, you need to configure your template engine. To configure, add this line of code to your server.js file.

app.set(‘view engine’, ‘ejs’)

EJS is accessed by default in the views directory. Now create a new views folder in the directory. In this folder, add a file named room.ejs. For now, think of our room.ejs file as an HTML file.

This is what your file structure looks like:

|-- video-chat-app
   |-- views
      |-- room.ejs
   |-- package.json
   |-- server.js

Now add the HTML to the room.ejs file.

Once you copy the above code, you need to change app.js a bit:

app.get(‘/’, function (req, res) {
 // OLD CODE
 res.status(200).send("Hello World");
})

Above is the old code where you send the text “Hello World!” To the client. You want to send the room.ejs file instead:

app.get(‘/’, function (req, res) {
 // NEW CODE
 res.render(‘room’);
})

Now open your browser and go to: localhost: 3030 and you will see the room.ejs file displayed!

Adding CSS

Doesn’t look good, does it? This is because there are no styles in your project. So add some CSS.

We will need to add a new folder to the project called public. In this folder create style.css and script.js files. Here’s your new file structure:

|-- weather-app
   |-- views
      |-- index.ejs
   |-- public
      |-- style.css
      |-- script.js
   |-- package.json
   |-- server.js

Express does not allow access to this file by default, so you need to open it with the following line of code:

app.use(express.static(‘public’));

This code allows you to access all static files in the “public” folder. Finally, you need CSS. Since this is not a CSS course, I won’t go into details, but if you want to use my styles, you can copy them from here

Once you’ve added your CSS, you can visit: localhost: 3030. You will notice that the app looks slightly better.

Setting up rooms

By now, your server.js file should look like this:

You have one GET route and server start. However, for your application to work, you need to redirect to a unique URL whenever a new user visits your default route. The uuid library should be used to generate a random unique URL for each room.

UUID is a javascript library that allows you to create unique identifiers. In your application, you will use uuid version 4 to create a unique URL. But first import the uuid into server.js.

const { v4: uuidv4 } = require("uuid");

Now you need to use uuid to generate a random unique ID for each room and redirect the user to that room.

app.get(“/”, (req, res) => {
    res.redirect(`/${uuidv4()}`);
});

And, before you test this, I also wanted to add a page for each unique room, and you pass the current url to that page.

app.get(“/:room”, (req, res) => {
    res.render(“room”, { roomId: req.param.room });
});

You have passed the roomId to room.ejs and this is how you set up your rooms. Now, if you visit localhost: 3030, you will be redirected to a unique URL.

Add user video

You will be working with the script.js file you created earlier. script.js will contain all the client code for the application.

So, here’s what you need to do: you need to get a video stream, and then add that stream to the video element.

let myVideoStream;
const videoGrid = document.getElementById("video-grid");
const myVideo = document.createElement("video");
myVideo.muted = true;
navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
})
.then((stream) => {
    myVideoStream = stream;
    addVideoStream(myVideo, stream);
});

Now let’s create the addVideoStream function, which will add a stream to the video element.

const addVideoStream = (video, stream) => {
    video.srcObject = stream;
    video.addEventListener("loadedmetadata", () => {
       video.play();
       videoGrid.append(video);
    });
};

This code will add a custom stream to the video item. You can check this by visiting localhost: 3030 and you will see a video popup

Adding the ability to allow other users to stream their videos.

It’s time to use Socket.io and PeerJS. For those who don’t know, Socket.io allows real-time communication between server and client. PeerJS allows you to implement WebRTC.

First, import socket.io and peerjs into server.js and listen for the connection event.

// server.js
const express = require(“express”);
const app = express();
const server = require(“http”).Server(app);
const { v4: uuidv4 } = require(“uuid”);
app.set(“view engine”, “ejs”);
const io = require(“socket.io”)(server);
const { ExpressPeerServer } = require(“peer”);
const peerServer = ExpressPeerServer(server, {
    debug: true,
});
app.use(“/peerjs”, peerServer);
app.use(express.static(“public”));
app.get(“/”, (req, res) => {
    res.redirect(`/${uuidv4()}`);
});
app.get(“/:room”, (req, res) => {
    res.render(“room”, { roomId: req.param.room });
});
io.on(“connection”, (socket) => {
    socket.on(“join-room”, (roomId, userId) => {
    socket.join(roomId);
    socket.to(roomId).broadcast.emit(“user-connected”, userId);
    });
});
server.listen(3030);

Your server is now listening for the room join event. Next, set up your script.js.

// public/script.js
const socket = io(“/”);
const videoGrid = document.getElementById(“video-grid”);
const myVideo = document.createElement(“video”);
myVideo.muted = true;
var peer = new Peer(undefined, {
  path: “/peerjs”,
  host: “/”,
  port: “3030”,
});
let myVideoStream;
navigator.mediaDevices
  .getUserMedia({
  audio: true,
  video: true,
})
.then((stream) => {
  myVideoStream = stream;
  addVideoStream(myVideo, stream);
  peer.on(“call”, (call) => {
    call.answer(stream);
    const video = document.createElement(“video”);
    call.on(“stream”, (userVideoStream) => {
      addVideoStream(video, userVideoStream);
      });
    });
  socket.on(“user-connected”, (userId) => {
      connectToNewUser(userId, stream);
  });
});
const connectToNewUser = (userId, stream) => {
  const call = peer.call(userId, stream);
  const video = document.createElement(“video”);
  call.on(“stream”, (userVideoStream) => {
      addVideoStream(video, userVideoStream);
  });
};
peer.on(“open”, (id) => {
    socket.emit(“join-room”, ROOM_ID, id);
});
const addVideoStream = (video, stream) => {
  video.srcObject = stream;
  video.addEventListener(“loadedmetadata”, () => {
    video.play();
    videoGrid.append(video);
  });
};

Now, if a new user enters the room, you will see his video.

Creating a user interface

The video part is finished. Now get started with styling. But first add the content to the room.ejs file. (Add CDN font-awesome inside the head tag.)

// views/room.ejs
<body>
  <div class="header">
    <div class="logo">
      <h3>Video Chat</h2>
    </div>
  </div>
  <div class="main">
    <div class="main__left">
      <div class="videos__group">
        <div id="video-grid"></div>
      </div>
      <div class="options">
        <div class="options__left">
          <div class="options__button">
            <i class="fa fa-video-camera" aria-hidden="true"></i>
          </div>
        <div class="options__button">
            <i class="fa fa-microphone" aria-hidden="true"></i>
        </div>
       </div>
       <div class="options__right">
         <div class="options__button background__red">
           <i class="fa fa-phone" aria-hidden="true"></i>
         </div>
       </div>
     </div>
    </div>
    <div class="main__right">
      <div class="main__chat_window">
        <ul class="messages"></ul>
     </div>
     <div class="main__message_container">
       <input id="chat_message" type="text" placeholder="Type message here...">
       <div class="options__button">
         <i class="fa fa-plus" aria-hidden="true"></i>
       </div>
     </div>
    </div>
  </div>
</body>

Then open the style.css file and add some CSS.

@import url(“https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap");
:root {
  — main-darklg: #1d2635;
  — main-dark: #161d29;
  — primary-color: #2f80ec;
  — main-light: #eeeeee;
  font-family: “Poppins”, sans-serif;
}
* {
  margin: 0;
  padding: 0;
}
.header {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 8vh;
  width: 100%;
  background-color: var( — main-darklg);
}
.logo > h3 {
    color: var( — main-light);
}
.main {
  overflow: hidden;
  height: 92vh;
  display: flex;
}
.main__left {
  flex: 0.7;
  display: flex;
  flex-direction: column;
}
.videos__group {
  flex-grow: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1rem;
  background-color: var( — main-dark);
}
video {
  height: 300px;
  border-radius: 1rem;
  margin: 0.5rem;
  width: 400px;
  object-fit: cover;
  transform: rotateY(180deg);
  -webkit-transform: rotateY(180deg);
  -moz-transform: rotateY(180deg);
}
.options {
  padding: 1rem;
  display: flex;
  background-color: var( — main-darklg);
}
.options__left {
    display: flex;
}
.options__right {
    margin-left: auto;
}
.options__button {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: var( — primary-color);
  height: 50px;
  border-radius: 5px;
  color: var( — main-light);
  font-size: 1.2rem;
  width: 50px;
  margin: 0 0.5rem;
}
.background__red {
    background-color: #f6484a;
}
.main__right {
flex: 0.3;
    background-color: #242f41;
}
.main__chat_window {
    flex-grow: 1;
}
.main__message_container {
  padding: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.main__message_container > input {
  height: 50px;
  flex: 1;
  border-radius: 5px;
  padding-left: 20px;
  border: none;
}
#video-grid {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
}

That’s all! Congratulations, you have successfully created a video chat! Now you can deploy it to Heroku and show it to the world. Demo and source

This is just a small example of what a web developer can do alone. Export music to Spotify just for fun and gain popularity while a huge company thinks about solving the problem for a long time – no problem. In one evening, sketching and rolling out a browser extension that will simplify the lives of millions of users is also within our power. What else is web development capable of depends only on the imagination of the programmer. Come learn to master jutsu web development and become a real samurai of the Internet.

find outhow to upgrade in other specialties or master them from scratch:

Other professions and courses

0 Comments

Leave a Reply