Building a Video Chat App with Node.js + Socket.io + WebRTC

This tutorial will show you how to build a video chat app using JavaScript and NodeJS. It will also show you how to use PeerJS, WebRTC, and Socket.io.

Click Here to see live example of the app we’ll be building.

Pre-Project Setup

Here’s what you’ll need:

  • NodeJS: Visit the official Node.js website to download and install Node.
  • NPM: NPM program gets installed on your computer when you install Node.js.

Project Setup

All the code for this project can be found in the GitHub Repo

  1. Create an empty directory named video-chat-app.
  2. Open up your console, navigate to our new directory, and run npm init.
  3. Fill out the required information to initialize our project.
  4. Within video-chat-app the directory, and run npm install express ejs socket.io uuid peer. This will install all the dependency that we need to build this application.
  5. And also as a dev dependency, we will install Nodemon. runnpm install — dev nodemon. This will install nodemon as a dev dependency.
  6. Create a file named server.js — this file will keep all our server-side logic

Now that we have our project setup, we can start building!

Creating our Server (with Express JS)

The first thing we need to do is get our server up and running. We’re going to use Express to accomplish this. Express is a minimalist web framework for Node.js — Express makes it very easy to create and run a web server with Node.

Let’s create a boilerplate Express starter app 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 we have our server running, We can test our server by running:

> nodemon server.js

Now open your browser and visit: localhost:3000 and you should see Hello World.

Creating our first View

Instead of responding with text when someone visits our root route, we’d like to respond with an HTML file. For this, we’ll be using EJS (Embedded JavaScript). EJS is a templating language.

In order to use EJS in Express, we need to set up our template engine. To setup add this line of code in server.js file.

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

EJS is accessed by default in the views directory. Now create a new folder named views in your directory. Within that views folder, add a file named room.ejs. Think of our room.ejs file as an HTML file for now.

Here’s what our file structure looks like so far:

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

Now we have our boilerplate forroom.ejsthe file. Now we will add our HTML code to room.ejs thefile.

https://medium.com/media/b6e1b6bd512cbd5ae26ab243a1546186/href

Once you copy the above code, we need to replace our app. js get code:

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

Above is the old code where we send the text ‘Hello World!’ to the client. Instead, we want to send our room.ejs file:

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

Now open your browser and visit: localhost:3030 and you should see our room.ejs file being displayed!

Adding a CSS File

This doesn’t look good right? That is because we don’t have any stylesheet files in our project. So let’s add some CSS.

We’ll need to add a new folder to our project called public. Within that folder create a file named style.css and script.js. Here’s our new file structure:

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

Express won’t allow access to this file by default, so we need to expose it with the following line of code:

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

This code allows us to access all of the static files within the ‘public’ folder.
Finally, we need our CSS. Since this isn’t a CSS course, I’m not going to be going over the specifics, but if you’d like to use my CSS, you can copy it from here.

Once you added CSS. you can visit: localhost:3030/ you will notice your application looks a little nicer.

Setting up our Rooms

By now, your server.jsfile should look like this:

https://medium.com/media/9ae6fc029c87da8665909e8beb12633b/href

We have one get route, and then we create our server. However, for our application to work, Whenever a new user visits our default route we will redirect him to a unique URL. We will use uuid library to create a random unique URL for each room.

UUID is a javascript library that allows us to create unique Ids. In our application, we will use uuid version 4 to create our unique URL. But first let’s import uuid in our server.js file.

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

Now, We will use uuid library to create a random unique id for each room. and we will redirect our user to that room.

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

And Before we test this I also wanted to add a view for every unique room and we will pass the current URL to that view.

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

We have passedroomId to room.ejs and with this we are done setting our Rooms. and now if you visit localhost:3030. you will be redirected to a unique URL.

Adding Current User Video

We will work on our script.js file that we have created earlier. script.js will contain all our client-side code.

So here what we need to do, we need to get the video stream aka user media, and then we will add that stream to a 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 we will create addVideoStream function. which will add the 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 user stream to the video element. you can test this by visiting localhost:3030 and you will see your video popup in the video element

5. Adding the ability to allow others to stream their video

Now it’s time to use Socket.io and PeerJS. For those who don’t know Socket.io allows us to do real-time communication. and PeerJS allow us to implement WebRTC.

First, we will import socket.io and peerjs in our server.js file and listen for join-room 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);

Now, We have our server actively listening for a join room event. Next, we will set up our 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 joins the room we will see their video.

6. Building User Interface

We are done with our video part. Now let’s do some styling. but first, let’s add some content to room.ejs file. (Add font awesome CDN inside your 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>

Next, Lets’s Open our style.css file 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 it! Congrats, you have made your video chat app successfully. Now you can deploy it to Heroku and show it to the world.

Live Demo: https://video-chat-app-v1.herokuapp.com/

Source Code: https://github.com/itstaranarora/video-chat-v1

Do follow me on LinkedIn and Github if you find this post useful


Building a Video Chat App with Node.js + Socket.io + WebRTC was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Taran Arora

This tutorial will show you how to build a video chat app using JavaScript and NodeJS. It will also show you how to use PeerJS, WebRTC, and Socket.io.

Click Here to see live example of the app we’ll be building.

Pre-Project Setup

Here’s what you’ll need:

  • NodeJS: Visit the official Node.js website to download and install Node.
  • NPM: NPM program gets installed on your computer when you install Node.js.

Project Setup

All the code for this project can be found in the GitHub Repo
  1. Create an empty directory named video-chat-app.
  2. Open up your console, navigate to our new directory, and run npm init.
  3. Fill out the required information to initialize our project.
  4. Within video-chat-app the directory, and run npm install express ejs socket.io uuid peer. This will install all the dependency that we need to build this application.
  5. And also as a dev dependency, we will install Nodemon. runnpm install — dev nodemon. This will install nodemon as a dev dependency.
  6. Create a file named server.js — this file will keep all our server-side logic

Now that we have our project setup, we can start building!

Creating our Server (with Express JS)

The first thing we need to do is get our server up and running. We’re going to use Express to accomplish this. Express is a minimalist web framework for Node.js — Express makes it very easy to create and run a web server with Node.

Let’s create a boilerplate Express starter app 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 we have our server running, We can test our server by running:

> nodemon server.js

Now open your browser and visit: localhost:3000 and you should see Hello World.

Creating our first View

Instead of responding with text when someone visits our root route, we’d like to respond with an HTML file. For this, we’ll be using EJS (Embedded JavaScript). EJS is a templating language.

In order to use EJS in Express, we need to set up our template engine. To setup add this line of code in server.js file.

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

EJS is accessed by default in the views directory. Now create a new folder named views in your directory. Within that views folder, add a file named room.ejs. Think of our room.ejs file as an HTML file for now.

Here’s what our file structure looks like so far:

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

Now we have our boilerplate forroom.ejsthe file. Now we will add our HTML code to room.ejs thefile.

Once you copy the above code, we need to replace our app. js get code:

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

Above is the old code where we send the text ‘Hello World!’ to the client. Instead, we want to send our room.ejs file:

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

Now open your browser and visit: localhost:3030 and you should see our room.ejs file being displayed!

Adding a CSS File

This doesn't look good right? That is because we don't have any stylesheet files in our project. So let's add some CSS.

We’ll need to add a new folder to our project called public. Within that folder create a file named style.css and script.js. Here’s our new file structure:

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

Express won't allow access to this file by default, so we need to expose it with the following line of code:

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

This code allows us to access all of the static files within the ‘public’ folder.
Finally, we need our CSS. Since this isn’t a CSS course, I’m not going to be going over the specifics, but if you’d like to use my CSS, you can copy it from here.

Once you added CSS. you can visit: localhost:3030/ you will notice your application looks a little nicer.

Setting up our Rooms

By now, your server.jsfile should look like this:

We have one get route, and then we create our server. However, for our application to work, Whenever a new user visits our default route we will redirect him to a unique URL. We will use uuid library to create a random unique URL for each room.

UUID is a javascript library that allows us to create unique Ids. In our application, we will use uuid version 4 to create our unique URL. But first let's import uuid in our server.js file.

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

Now, We will use uuid library to create a random unique id for each room. and we will redirect our user to that room.

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

And Before we test this I also wanted to add a view for every unique room and we will pass the current URL to that view.

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

We have passedroomId to room.ejs and with this we are done setting our Rooms. and now if you visit localhost:3030. you will be redirected to a unique URL.

Adding Current User Video

We will work on our script.js file that we have created earlier. script.js will contain all our client-side code.

So here what we need to do, we need to get the video stream aka user media, and then we will add that stream to a 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 we will create addVideoStream function. which will add the 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 user stream to the video element. you can test this by visiting localhost:3030 and you will see your video popup in the video element

5. Adding the ability to allow others to stream their video

Now it’s time to use Socket.io and PeerJS. For those who don’t know Socket.io allows us to do real-time communication. and PeerJS allow us to implement WebRTC.

First, we will import socket.io and peerjs in our server.js file and listen for join-room 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);

Now, We have our server actively listening for a join room event. Next, we will set up our 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 joins the room we will see their video.

6. Building User Interface

We are done with our video part. Now let’s do some styling. but first, let’s add some content to room.ejs file. (Add font awesome CDN inside your 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>

Next, Lets’s Open our style.css file 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 it! Congrats, you have made your video chat app successfully. Now you can deploy it to Heroku and show it to the world.

Live Demo: https://video-chat-app-v1.herokuapp.com/

Source Code: https://github.com/itstaranarora/video-chat-v1

Do follow me on LinkedIn and Github if you find this post useful


Building a Video Chat App with Node.js + Socket.io + WebRTC was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Taran Arora


Print Share Comment Cite Upload Translate Updates
APA

Taran Arora | Sciencx (2021-03-28T21:48:56+00:00) Building a Video Chat App with Node.js + Socket.io + WebRTC. Retrieved from https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/

MLA
" » Building a Video Chat App with Node.js + Socket.io + WebRTC." Taran Arora | Sciencx - Sunday March 28, 2021, https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/
HARVARD
Taran Arora | Sciencx Sunday March 28, 2021 » Building a Video Chat App with Node.js + Socket.io + WebRTC., viewed ,<https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/>
VANCOUVER
Taran Arora | Sciencx - » Building a Video Chat App with Node.js + Socket.io + WebRTC. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/
CHICAGO
" » Building a Video Chat App with Node.js + Socket.io + WebRTC." Taran Arora | Sciencx - Accessed . https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/
IEEE
" » Building a Video Chat App with Node.js + Socket.io + WebRTC." Taran Arora | Sciencx [Online]. Available: https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/. [Accessed: ]
rf:citation
» Building a Video Chat App with Node.js + Socket.io + WebRTC | Taran Arora | Sciencx | https://www.scien.cx/2021/03/28/building-a-video-chat-app-with-node-js-socket-io-webrtc/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.