Build Zoom Clone Video Chat Web App in Node.js Express and Socket.io Using WebRTC and PeerJS Library

Build Zoom Clone Video Chat Web App in Node.js Express and Socket.io Using WebRTC and PeerJS Library

Welcome folks today in this tutorial we will be building a zoom clone video chat app in node.js express and socket.io using webrtc and peerjs library. All the source code of the application is given as follows. A step by step youtube video is shown below.

 

 

Screenshots

x
Build Zoom Clone Video Chat Web App in Node.js Express and Socket.io Using WebRTC and PeerJS Library
 

Dependencies

 

  1. Socket.io
  2. Express
  3. ejs
  4. uuid
  5. nodemon
  6. peerjs library

 

Now to install these create a package.json inside your root folder of your project.

{
  "name": "zoom-clone",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "devStart": "nodemon server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ejs": "^3.1.3",
    "express": "^4.17.1",
    "socket.io": "^2.3.0",
    "uuid": "^8.1.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.4"
  }
}

 

Now execute npm install command to install these dependencies

Now create the starting point of the application index.js and import all the dependencies like this

const express = require('express')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server)
const { v4: uuidV4 } = require('uuid')

app.set('view engine', 'ejs')
app.use(express.static('public'))

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`)
})

server.listen(3000)

 

Now if you execute this and now if you go to localhost:3000 you will see your app and it will have a random uuid generated for you. Every user which is connected will have a random roomid attached to the url

 

 

Now we need to make the route for this specific dynamic roomId. So make a new Get request for this route and we will load an ejs file for that like this.

But first of all make a views directory and make a new file called as room.ejs like this

 

 

And now copy paste the following html code into this

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script>
    const ROOM_ID = "<%= roomId %>"
  </script>
  <script defer src="https://unpkg.com/peerjs@1.2.0/dist/peerjs.min.js"></script>
  <script src="/socket.io/socket.io.js" defer></script>
  <script src="script.js" defer></script>
  <title>Zoom Clone Video Chat</title>
  <style>
    #video-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, 300px);
      grid-auto-rows: 300px;
    }
    
    video {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  </style>
</head>
<body>
  <div id="video-grid"></div>
</body>
</html>

 

Now inside index.js make a get request to load this view like this

app.get('/:room', (req, res) => {
  res.render('room', { roomId: req.params.room })
})

 

Now in this block of code we are making the html for video tags. And also we are importing socket.io.js file and also peerjs library and also we are including custom script.js file. And also here we are dynamically getting the ROOM_ID which is passed from index.js file to ejs file.

Now we need to create a public directory which is static by default and create a script.js file and in this file we will write custom javascript code for the application.

 

 

So now inside index.js we need to write the socket.io code such that when a user is connected then we need to pass the roomid and the user id which is associated with the user.

io.on('connection', socket => {
  socket.on('join-room', (roomId, userId) => {
    socket.join(roomId)
    socket.to(roomId).broadcast.emit('user-connected', userId)

    socket.on('disconnect', () => {
      socket.to(roomId).broadcast.emit('user-disconnected', userId)
    })
  })
})

 

See also  RecordRTC.js Example to Build a WebRTC Video Recorder From Webcam and Play, Download Recorded Video as MP4 File in Browser Using Javascript Full Project For Beginners

In this block of code we have two events when the user has joined the room then we are getting two things from the client the roomid of the user and the userid of the user. And in the next step we are broadcasting this information to all the users except the user which is sending the information. We are emitting this event user-connected and then we are passing the userid of the user which is connected. And also we have a disconnected event also in that case also we inform all the users except the user which has been disconnected again passing the user-id of the disconnnected user.

Now we need to move to script.js file and write the code like this

First of all we also need to install the peerjs library globally inside your cli. To do that open a cmd window and write this command as follows

 

After installing it we can start the peerjs server in the same directory of your project. To start it execute the following command inside the cmd of your project

 

After running this server the peerjs server has started so everytime a new user is connected it will assign a new userid to it automatically. So now inside your script.js file write this followinng code

 

const socket = io('/')
const myPeer = new Peer(undefined, {
  host: '/',
  port: '3001'
})
myPeer.on('open', id => {
  socket.emit('join-room', ROOM_ID, id)
})
socket.on('user-connected', userId => {
    console.log("User Connected " + userId)
  })

 

And now inside this block of code we first of all calling the socket.io server and then we are initializing the peerjs library passing some parameters such as host and the port number. And then when the peer has a open connection then a random id has been assigned by peerjs. Then we emit a event passing the current Room_id and the user_id of the user.

And then lastly when a socket is connected then this event will fire and then we can see on the console what is the user id of the person who is connected to our room.

 

Now we will be displaying our webcam inside our application. Inside our html we have a video tag and then inside your script.js we will write this code.

const videoGrid = document.getElementById('video-grid')

const myVideo = document.createElement('video')
myVideo.muted = true

navigator.mediaDevices.getUserMedia({
  video: true,
  audio: true
}).then(stream => {
  addVideoStream(myVideo, stream)

})


function addVideoStream(video, stream) {
  video.srcObject = stream
  video.addEventListener('loadedmetadata', () => {
    video.play()
  })
  videoGrid.append(video)
}

 

See also  Build a Youtube API Video Thumbnail Extractor or Grabber From URL in Vanilla Javascript Full Project For Beginners

Now inside this block of code we are using the navigator api to get reference to our webcam to display our stream. And then we are appending that stream to the video grid element.

Calling Other User

 

Now the fun part begins in the app. In this block of code we will call the other user or in other words when the other user joins our room with the same room id then we need to display his stream to our window

socket.on('user-connected', userId => {
    console.log("User Connected " + userId)
    connectToNewUser(userId, stream)
  })

 

function connectToNewUser(userId, stream) {
  const call = myPeer.call(userId, stream)
  const video = document.createElement('video')
  call.on('stream', userVideoStream => {
    addVideoStream(video, userVideoStream)
  })
  call.on('close', () => {
    video.remove()
  })

  peers[userId] = call
}

 

Here in this method we are using the peerjs call method to call the other user with the userid and also passing our stream and then we are creating another video element and then when the call is successful then we are again adding the stream to our video element.

When the call is closed then we are removing the video.

Also here if you execute this your friend video will not show up because we need to add a little piece of code like this

myPeer.on('call', call => {
    call.answer(stream)
    const video = document.createElement('video')
    call.on('stream', userVideoStream => {
      addVideoStream(video, userVideoStream)
    })
  })

 

Here in this block of code we are binding a event on the peer object when the call is there we need to answer the call and then allow our stream to show up in friend tabs or browser.

Now the app is almost complete we can join the call and chat. But one option is missing when we want to leave the chat we want to remove the video of the user which has left the chat. To do this you need to write this code

const peers = {}

 

Create a simple object of all the users which are there in the video chat.

 

function connectToNewUser(userId, stream) {
  const call = myPeer.call(userId, stream)
  const video = document.createElement('video')
  call.on('stream', userVideoStream => {
    addVideoStream(video, userVideoStream)
  })
  call.on('close', () => {
    video.remove()
  })

  peers[userId] = call
}

 

Here inside when we connect with a new user we copy the user which is connected inside this peers object.

socket.on('user-disconnected', userId => {
  if (peers[userId]) peers[userId].close()
})

 

Now when the user leaves the chat this event will fire automatically by socket.io and then we can close the call using peerjs.

SCRIPT.JS

 

const socket = io('/')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
  host: '/',
  port: '3001'
})
const myVideo = document.createElement('video')
myVideo.muted = true
const peers = {}
navigator.mediaDevices.getUserMedia({
  video: true,
  audio: true
}).then(stream => {
  addVideoStream(myVideo, stream)

  myPeer.on('call', call => {
    call.answer(stream)
    const video = document.createElement('video')
    call.on('stream', userVideoStream => {
      addVideoStream(video, userVideoStream)
    })
  })

  socket.on('user-connected', userId => {
    console.log("User Connected " + userId)
    connectToNewUser(userId, stream)
  })
})

socket.on('user-disconnected', userId => {
  if (peers[userId]) peers[userId].close()
})

myPeer.on('open', id => {
  socket.emit('join-room', ROOM_ID, id)
})

function connectToNewUser(userId, stream) {
  const call = myPeer.call(userId, stream)
  const video = document.createElement('video')
  call.on('stream', userVideoStream => {
    addVideoStream(video, userVideoStream)
  })
  call.on('close', () => {
    video.remove()
  })

  peers[userId] = call
}

function addVideoStream(video, stream) {
  video.srcObject = stream
  video.addEventListener('loadedmetadata', () => {
    video.play()
  })
  videoGrid.append(video)
}

Leave a Reply