End of Life for Twilio Programmable Video - Upgrade to VideoSDKLearn More

How to Build PeerJS WebRTC App with JavaScript?

Learn how to create a real-time, peer-to-peer WebRTC application using PeerJS and Node.js. This comprehensive guide covers setup, implementation, and troubleshooting for building robust video chat applications.

Introduction to PeerJS WebRTC

What is PeerJS?

PeerJS is a popular JavaScript library that simplifies the process of building peer-to-peer (P2P) applications using WebRTC. WebRTC, or Web Real-Time Communication, is a technology that allows audio, video, and data sharing between browsers without requiring an intermediary server. This P2P connection enables faster and more efficient communication, which is essential for applications like video conferencing, file sharing, and real-time multiplayer games.

Importance of WebRTC and P2P Communication

WebRTC is a game-changer in the realm of real-time communication, offering high-quality audio and video calls directly from the browser. The primary advantage of WebRTC is that it eliminates the need for plugins or external applications, making it easier for developers to integrate real-time communication into their web applications.
PeerJS leverages WebRTC to facilitate P2P communication by handling the complex signaling process required to establish and maintain connections. This allows developers to focus on building their applications without getting bogged down in the intricate details of WebRTC.

Use Cases of Using PeerJS with WebRTC

  • Video Chat Applications: PeerJS can be used to create seamless video chat applications, enabling users to connect and communicate in real-time.
  • File Sharing: With PeerJS, you can build applications that allow users to share files directly between their browsers without relying on a central server.
  • Real-Time Collaboration Tools: PeerJS is ideal for applications like whiteboards or coding environments where real-time collaboration is crucial.
  • Gaming: PeerJS can be used to create real-time multiplayer games where players can interact directly with each other.

Benefits of Using PeerJS with WebRTC

  • Ease of Use: PeerJS abstracts the complexity of WebRTC, providing a simple API for developers.
  • Scalability: By using P2P connections, the load on central servers is reduced, making applications more scalable.
  • Performance: P2P connections typically offer lower latency and higher bandwidth compared to traditional client-server models.
  • Flexibility: PeerJS supports various types of data transmission, including audio, video, and arbitrary data, giving developers the flexibility to build diverse applications.
In conclusion, PeerJS combined with WebRTC offers a powerful solution for building real-time, P2P applications. Its simplicity, combined with the robust capabilities of WebRTC, makes it an excellent choice for developers looking to integrate real-time communication features into their web applications.

Getting Started with PeerJS and Node.js

Create a New PeerJS App

To begin building a PeerJS application, you'll first need to set up a new Node.js project. This will serve as the foundation for your PeerJS signaling server and client application. Follow these steps to get started:

[a] Initialize a New Node.js Project

Open your terminal and create a new directory for your project. Navigate into this directory and initialize a new Node.js project by running:

bash

1   mkdir peerjs-webrtc-app
2   cd peerjs-webrtc-app
3   npm init -y
This will create a package.json file with default settings.

[b] Install PeerJS and Express

You'll need to install PeerJS, Express, and a few other dependencies. Run the following command to install these packages:

bash

1   npm install peer peerjs express

Project Structure

To keep your project organized, it's essential to structure your files and folders properly. Here's a suggested structure:
1peerjs-webrtc-app/
2├── public/
3│   ├── index.html
4│   └── main.js
5├── server.js
6├── package.json
7└── package-lock.json
  • public/: Contains static files served to the client, including HTML, CSS, and JavaScript files.
  • server.js: The main server file where you'll set up the PeerJS signaling server and Express server.

App Architecture

peerjs-webrtc
The architecture of your PeerJS application will consist of a signaling server and a client application. The signaling server, built using Node.js and PeerJS, will handle the initial connection setup between peers. The client application will run in the browser and use PeerJS to manage peer connections and media streams.
Here's an overview of the architecture:
  1. Signaling Server: Manages the signaling process required to establish peer-to-peer connections. It runs on Node.js and uses the PeerJS server library.
  2. Client Application: Runs in the browser and uses the PeerJS client library to connect to the signaling server and manage peer connections.

Setting Up the Signaling Server

[a] Create the Server File

In the root directory of your project, create a file named server.js and add the following code to set up a basic Express server:

JavaScript

1   const express = require('express');
2   const { ExpressPeerServer } = require('peer');
3   const http = require('http');
4
5   const app = express();
6   const server = http.createServer(app);
7   const peerServer = ExpressPeerServer(server, {
8       debug: true
9   });
10
11   app.use('/peerjs', peerServer);
12
13   app.use(express.static('public'));
14
15   server.listen(9000, () => {
16       console.log('Server is running on http://localhost:9000');
17   });
This code sets up an Express server that serves static files from the public directory and configures a PeerJS server on the /peerjs route.

[b] Client HTML Structure

Create an index.html file in the public directory. This file will serve as the main entry point for your client application:

HTML

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>PeerJS WebRTC App</title>
7</head>
8<body>
9    <h1>PeerJS WebRTC Application</h1>
10    <div>
11        <label for="peer-id">Your ID:</label>
12        <input type="text" id="peer-id" readonly>
13    </div>
14    <div>
15        <label for="connect-id">Connect to Peer ID:</label>
16        <input type="text" id="connect-id">
17        <button id="connect-button">Connect</button>
18    </div>
19    <div id="remote-video-container"></div>
20    <script src="main.js"></script>
21</body>
22</html>
This HTML file includes a simple user interface with fields for displaying the user's peer ID, entering a peer ID to connect to, and a container for displaying remote video streams.

Step 1: Setting Up the Signaling Server

The signaling server is a crucial component in a PeerJS application. It helps peers discover each other and establish a direct connection. PeerJS simplifies this process by providing an easy-to-use server setup. In this section, we will install and configure the peerjs-server.

Get Started with Installing and Setting Up peerjs-server

[a] Install PeerJS Server

Ensure you have already installed PeerJS and Express as outlined in Part 2. If not, you can install peerjs-server by running the following command:

bash

1   npm install peer

[b] Basic Configuration

The signaling server will be part of your server.js file. Here’s how you can set it up:

JavaScript

1   const express = require('express');
2   const { ExpressPeerServer } = require('peer');
3   const http = require('http');
4
5   const app = express();
6   const server = http.createServer(app);
7
8   // Create a PeerJS server instance
9   const peerServer = ExpressPeerServer(server, {
10       debug: true
11   });
12
13   // Mount the PeerJS server on the /peerjs route
14   app.use('/peerjs', peerServer);
15
16   // Serve static files from the 'public' directory
17   app.use(express.static('public'));
18
19   // Start the server
20   server.listen(9000, () => {
21       console.log('Server is running on http://localhost:9000');
22   });

[c] Run the Server

To start your server, run the following command in your terminal:

bash

1   node server.js
You should see the message Server is running on http://localhost:9000 indicating that your signaling server is up and running.

Code Snippet: Basic Server Setup

Here is the complete server.js file with comments explaining each part:

JavaScript

1const express = require('express');
2const { ExpressPeerServer } = require('peer');
3const http = require('http');
4
5// Initialize Express app
6const app = express();
7
8// Create an HTTP server
9const server = http.createServer(app);
10
11// Create a PeerJS server instance with debug enabled
12const peerServer = ExpressPeerServer(server, {
13    debug: true
14});
15
16// Mount the PeerJS server on the /peerjs route
17app.use('/peerjs', peerServer);
18
19// Serve static files from the 'public' directory
20app.use(express.static('public'));
21
22// Start the server on port 9000
23server.listen(9000, () => {
24    console.log('Server is running on http://localhost:9000');
25});

Testing Your Signaling Server

To verify that your signaling server is working correctly:
  1. Open your browser and navigate to http://localhost:9000/peerjs.
  2. You should see a JSON response indicating the PeerJS server is running.
By setting up the signaling server, you've established the backbone for your PeerJS WebRTC application. The signaling server facilitates peer discovery and connection setup, which is essential for real-time communication. In the next part, we will focus on creating the client application, which will connect to this signaling server and manage peer-to-peer communication.

Step 2: Creating the Client Application

With the signaling server up and running, the next step is to build the client-side application. This application will connect to the signaling server, handle peer-to-peer connections, and manage media streams.

Wireframing the Components

Before diving into the code, it's important to outline the components of the client application. The main components include:
  1. User Interface (UI): Basic HTML structure to input peer IDs and display video streams.
  2. PeerJS Client: JavaScript code to handle peer connections and media streams.

Creating the Basic HTML Structure

Start by creating the HTML file that will serve as the interface for your client application. This file will include fields for the user’s peer ID, a field to enter the peer ID to connect to, a connect button, and a container to display video streams.
Create an index.html file in the public directory with the following content:

HTML

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>PeerJS WebRTC App</title>
7    <style>
8        body {
9            font-family: Arial, sans-serif;
10            text-align: center;
11            padding: 20px;
12        }
13        #remote-video-container video {
14            width: 45%;
15            margin: 5px;
16        }
17    </style>
18</head>
19<body>
20    <h1>PeerJS WebRTC Application</h1>
21    <div>
22        <label for="peer-id">Your ID:</label>
23        <input type="text" id="peer-id" readonly>
24    </div>
25    <div>
26        <label for="connect-id">Connect to Peer ID:</label>
27        <input type="text" id="connect-id">
28        <button id="connect-button">Connect</button>
29    </div>
30    <div id="remote-video-container"></div>
31    <script src="main.js"></script>
32</body>
33</html>
This HTML file sets up a basic layout with fields for displaying the user’s peer ID, entering the peer ID to connect to, and a button to initiate the connection. There is also a container to display remote video streams.

Implementing the Client-Side JavaScript

Next, create a main.js file in the public directory. This file will contain the JavaScript code to handle peer connections and media streams using PeerJS.

[a] Initialize the PeerJS Client

JavaScript

1   const peer = new Peer({
2       host: 'localhost',
3       port: 9000,
4       path: '/peerjs'
5   });
6
7   peer.on('open', id => {
8       document.getElementById('peer-id').value = id;
9   });
This code initializes the PeerJS client and connects it to the signaling server. When the connection is established, it displays the user’s peer ID.

[b] Handle Connection Requests

JavaScript

1   document.getElementById('connect-button').addEventListener('click', () => {
2       const peerId = document.getElementById('connect-id').value;
3       const call = peer.call(peerId, localStream);
4
5       call.on('stream', remoteStream => {
6           addVideoStream(remoteStream);
7       });
8   });
9
10   peer.on('call', call => {
11       call.answer(localStream);
12
13       call.on('stream', remoteStream => {
14           addVideoStream(remoteStream);
15       });
16   });
17
18   function addVideoStream(stream) {
19       const video = document.createElement('video');
20       video.srcObject = stream;
21       video.addEventListener('loadedmetadata', () => {
22           video.play();
23       });
24       document.getElementById('remote-video-container').append(video);
25   }
This code adds event listeners to handle outgoing and incoming calls. When the connect button is clicked, it retrieves the peer ID from the input field and initiates a call. It also handles incoming calls and streams the video.

[c] Get User Media

To capture and stream video from the user’s webcam, add the following code:

JavaScript

1   let localStream;
2
3   navigator.mediaDevices.getUserMedia({
4       video: true,
5       audio: true
6   }).then(stream => {
7       localStream = stream;
8   }).catch(error => {
9       console.error('Error accessing media devices.', error);
10   });
This code accesses the user's webcam and microphone and stores the media stream in the localStream variable.
Your client application can now connect to the signaling server, initiate calls, and display video streams. In the next section, we will focus on enhancing the user interface and adding additional functionality to the application.

Step 3: Implementing the Join Screen

The join screen is a crucial component of the client application, allowing users to connect to other peers easily. This section will guide you through creating a user-friendly join screen, connecting to the PeerJS server, and handling user interactions.

Join Screen Functionality

The join screen will include:
  • A display of the user's unique PeerJS ID.
  • An input field to enter the PeerJS ID of the peer to connect to.
  • A connect button to initiate the connection.

Enhancing the HTML Structure

Modify the existing index.html file to improve the join screen UI:

HTML

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>PeerJS WebRTC App</title>
7    <style>
8        body {
9            font-family: Arial, sans-serif;
10            text-align: center;
11            padding: 20px;
12        }
13        #remote-video-container video {
14            width: 45%;
15            margin: 5px;
16        }
17        #join-screen {
18            margin-bottom: 20px;
19        }
20        #join-screen input, #join-screen button {
21            padding: 10px;
22            margin: 5px;
23            font-size: 16px;
24        }
25    </style>
26</head>
27<body>
28    <h1>PeerJS WebRTC Application</h1>
29    <div id="join-screen">
30        <div>
31            <label for="peer-id">Your ID:</label>
32            <input type="text" id="peer-id" readonly>
33        </div>
34        <div>
35            <label for="connect-id">Connect to Peer ID:</label>
36            <input type="text" id="connect-id">
37            <button id="connect-button">Connect</button>
38        </div>
39    </div>
40    <div id="remote-video-container"></div>
41    <script src="main.js"></script>
42</body>
43</html>

Implementing Join Screen Interactions

Update main.js to handle user interactions on the join screen:

[a] Display the User's PeerJS ID

Ensure the user's PeerJS ID is displayed as soon as it is generated.

JavaScript

1   const peer = new Peer({
2       host: 'localhost',
3       port: 9000,
4       path: '/peerjs'
5   });
6
7   peer.on('open', id => {
8       document.getElementById('peer-id').value = id;
9   });

[b] Handle Connection Requests

Add functionality to initiate a connection when the connect button is clicked.

JavaScript

1   document.getElementById('connect-button').addEventListener('click', () => {
2       const peerId = document.getElementById('connect-id').value;
3       if (peerId) {
4           const call = peer.call(peerId, localStream);
5
6           call.on('stream', remoteStream => {
7               addVideoStream(remoteStream);
8           });
9
10           call.on('error', err => {
11               console.error('Failed to connect:', err);
12               alert('Failed to connect to peer.');
13           });
14       } else {
15           alert('Please enter a peer ID to connect.');
16       }
17   });

[c] Handle Incoming Calls

Update the code to manage incoming calls and display the video streams.

JavaScript

1   peer.on('call', call => {
2       call.answer(localStream);
3
4       call.on('stream', remoteStream => {
5           addVideoStream(remoteStream);
6       });
7
8       call.on('error', err => {
9           console.error('Call failed:', err);
10           alert('Call failed.');
11       });
12   });
13
14   function addVideoStream(stream) {
15       const video = document.createElement('video');
16       video.srcObject = stream;
17       video.addEventListener('loadedmetadata', () => {
18           video.play();
19       });
20       document.getElementById('remote-video-container').append(video);
21   }

[d] Capture User Media

Ensure the application has access to the user's webcam and microphone.

JavaScript

1   let localStream;
2
3   navigator.mediaDevices.getUserMedia({
4       video: true,
5       audio: true
6   }).then(stream => {
7       localStream = stream;
8   }).catch(error => {
9       console.error('Error accessing media devices.', error);
10   });
The join screen now displays the user's unique PeerJS ID, allows users to enter the ID of a peer they wish to connect to, and handles the connection process. The next step will focus on implementing user controls, such as managing the connection and handling media streams more effectively.

Step 4: Implementing Controls

In this part, we will implement user controls to manage the peer-to-peer connection and media streams. These controls will allow users to connect, disconnect, mute/unmute audio, and start/stop video.

Adding UI Controls

First, update the index.html file to include buttons for controlling the media streams:

HTML

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>PeerJS WebRTC App</title>
7    <style>
8        body {
9            font-family: Arial, sans-serif;
10            text-align: center;
11            padding: 20px;
12        }
13        #remote-video-container video {
14            width: 45%;
15            margin: 5px;
16        }
17        #join-screen, #controls {
18            margin-bottom: 20px;
19        }
20        #join-screen input, #join-screen button, #controls button {
21            padding: 10px;
22            margin: 5px;
23            font-size: 16px;
24        }
25    </style>
26</head>
27<body>
28    <h1>PeerJS WebRTC Application</h1>
29    <div id="join-screen">
30        <div>
31            <label for="peer-id">Your ID:</label>
32            <input type="text" id="peer-id" readonly>
33        </div>
34        <div>
35            <label for="connect-id">Connect to Peer ID:</label>
36            <input type="text" id="connect-id">
37            <button id="connect-button">Connect</button>
38        </div>
39    </div>
40    <div id="controls">
41        <button id="disconnect-button">Disconnect</button>
42        <button id="mute-button">Mute</button>
43        <button id="stop-video-button">Stop Video</button>
44    </div>
45    <div id="remote-video-container"></div>
46    <script src="main.js"></script>
47</body>
48</html>

Implementing Control Functions

Now, add the necessary functionality in main.js to handle these controls.

[a] Disconnect Button

This button will allow users to disconnect from the current peer connection.

JavaScript

1   let currentCall;
2
3   document.getElementById('connect-button').addEventListener('click', () => {
4       const peerId = document.getElementById('connect-id').value;
5       if (peerId) {
6           currentCall = peer.call(peerId, localStream);
7
8           currentCall.on('stream', remoteStream => {
9               addVideoStream(remoteStream);
10           });
11
12           currentCall.on('error', err => {
13               console.error('Failed to connect:', err);
14               alert('Failed to connect to peer.');
15           });
16       } else {
17           alert('Please enter a peer ID to connect.');
18       }
19   });
20
21   document.getElementById('disconnect-button').addEventListener('click', () => {
22       if (currentCall) {
23           currentCall.close();
24           currentCall = null;
25           alert('Disconnected from peer.');
26           document.getElementById('remote-video-container').innerHTML = '';
27       }
28   });

[b] Mute/Unmute Button

This button will toggle the audio track on or off.

JavaScript

1   let audioEnabled = true;
2
3   document.getElementById('mute-button').addEventListener('click', () => {
4       audioEnabled = !audioEnabled;
5       localStream.getAudioTracks()[0].enabled = audioEnabled;
6       document.getElementById('mute-button').textContent = audioEnabled ? 'Mute' : 'Unmute';
7   });

[c] Stop/Start Video Button

This button will toggle the video track on or off.

JavaScript

1   let videoEnabled = true;
2
3   document.getElementById('stop-video-button').addEventListener('click', () => {
4       videoEnabled = !videoEnabled;
5       localStream.getVideoTracks()[0].enabled = videoEnabled;
6       document.getElementById('stop-video-button').textContent = videoEnabled ? 'Stop Video' : 'Start Video';
7   });

[d] Handle Incoming Calls

Ensure the application can handle incoming calls and manage streams appropriately.

JavaScript

1   peer.on('call', call => {
2       call.answer(localStream);
3
4       call.on('stream', remoteStream => {
5           addVideoStream(remoteStream);
6       });
7
8       call.on('error', err => {
9           console.error('Call failed:', err);
10           alert('Call failed.');
11       });
12
13       currentCall = call;
14   });
15
16   function addVideoStream(stream) {
17       const video = document.createElement('video');
18       video.srcObject = stream;
19       video.addEventListener('loadedmetadata', () => {
20           video.play();
21       });
22       document.getElementById('remote-video-container').append(video);
23   }

[e] Capture User Media

Ensure the application has access to the user's webcam and microphone.

JavaScript

1   let localStream;
2
3   navigator.mediaDevices.getUserMedia({
4       video: true,
5       audio: true
6   }).then(stream => {
7       localStream = stream;
8   }).catch(error => {
9       console.error('Error accessing media devices.', error);
10   });
In this part, you have added essential user controls to manage the peer-to-peer connections and media streams in your PeerJS WebRTC application. Users can now connect to peers, disconnect, mute/unmute audio, and start/stop video. The next step will be implementing the participant view to manage and display multiple video streams effectively.

Get Free 10,000 Minutes Every Months

No credit card required to start.

Step 5: Implementing Participant View

In this part, we will implement the participant view to manage and display multiple video streams effectively. This functionality is crucial for applications like video conferencing where multiple users need to see each other's video feeds.

Enhancing the Participant View

First, update the HTML structure to better handle multiple video streams. You may already have a basic setup for displaying videos, but we need to ensure it can handle multiple participants.

HTML

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>PeerJS WebRTC App</title>
7    <style>
8        body {
9            font-family: Arial, sans-serif;
10            text-align: center;
11            padding: 20px;
12        }
13        #remote-video-container video {
14            width: 45%;
15            margin: 5px;
16        }
17        #join-screen, #controls {
18            margin-bottom: 20px;
19        }
20        #join-screen input, #join-screen button, #controls button {
21            padding: 10px;
22            margin: 5px;
23            font-size: 16px;
24        }
25        .video-wrapper {
26            display: inline-block;
27            position: relative;
28        }
29        .video-wrapper video {
30            width: 100%;
31        }
32        .video-wrapper .label {
33            position: absolute;
34            bottom: 10px;
35            left: 10px;
36            background: rgba(0, 0, 0, 0.5);
37            color: white;
38            padding: 5px;
39            border-radius: 5px;
40        }
41    </style>
42</head>
43<body>
44    <h1>PeerJS WebRTC Application</h1>
45    <div id="join-screen">
46        <div>
47            <label for="peer-id">Your ID:</label>
48            <input type="text" id="peer-id" readonly>
49        </div>
50        <div>
51            <label for="connect-id">Connect to Peer ID:</label>
52            <input type="text" id="connect-id">
53            <button id="connect-button">Connect</button>
54        </div>
55    </div>
56    <div id="controls">
57        <button id="disconnect-button">Disconnect</button>
58        <button id="mute-button">Mute</button>
59        <button id="stop-video-button">Stop Video</button>
60    </div>
61    <div id="remote-video-container"></div>
62    <script src="main.js"></script>
63</body>
64</html>

Updating JavaScript for Multiple Participants

Manage Multiple Connections

Modify the connection handling logic to support multiple participants.

JavaScript

1   let localStream;
2   let peers = {};
3
4   navigator.mediaDevices.getUserMedia({
5       video: true,
6       audio: true
7   }).then(stream => {
8       localStream = stream;
9   }).catch(error => {
10       console.error('Error accessing media devices.', error);
11   });
12
13   const peer = new Peer({
14       host: 'localhost',
15       port: 9000,
16       path: '/peerjs'
17   });
18
19   peer.on('open', id => {
20       document.getElementById('peer-id').value = id;
21   });
22
23   document.getElementById('connect-button').addEventListener('click', () => {
24       const peerId = document.getElementById('connect-id').value;
25       if (peerId) {
26           connectToPeer(peerId);
27       } else {
28           alert('Please enter a peer ID to connect.');
29       }
30   });
31
32   document.getElementById('disconnect-button').addEventListener('click', () => {
33       for (let peerId in peers) {
34           peers[peerId].close();
35       }
36       peers = {};
37       document.getElementById('remote-video-container').innerHTML = '';
38   });
39
40   document.getElementById('mute-button').addEventListener('click', () => {
41       localStream.getAudioTracks()[0].enabled = !localStream.getAudioTracks()[0].enabled;
42       document.getElementById('mute-button').textContent = localStream.getAudioTracks()[0].enabled ? 'Mute' : 'Unmute';
43   });
44
45   document.getElementById('stop-video-button').addEventListener('click', () => {
46       localStream.getVideoTracks()[0].enabled = !localStream.getVideoTracks()[0].enabled;
47       document.getElementById('stop-video-button').textContent = localStream.getVideoTracks()[0].enabled ? 'Stop Video' : 'Start Video';
48   });
49
50   peer.on('call', call => {
51       call.answer(localStream);
52       handleIncomingCall(call);
53   });
54
55   function connectToPeer(peerId) {
56       const call = peer.call(peerId, localStream);
57       handleIncomingCall(call);
58       peers[peerId] = call;
59   }
60
61   function handleIncomingCall(call) {
62       call.on('stream', remoteStream => {
63           addVideoStream(call.peer, remoteStream);
64       });
65
66       call.on('close', () => {
67           document.getElementById(call.peer).remove();
68           delete peers[call.peer];
69       });
70
71       call.on('error', err => {
72           console.error('Call failed:', err);
73           alert('Call failed.');
74       });
75   }
76
77   function addVideoStream(peerId, stream) {
78       if (document.getElementById(peerId)) {
79           return;
80       }
81
82       const videoWrapper = document.createElement('div');
83       videoWrapper.id = peerId;
84       videoWrapper.className = 'video-wrapper';
85
86       const video = document.createElement('video');
87       video.srcObject = stream;
88       video.addEventListener('loadedmetadata', () => {
89           video.play();
90       });
91
92       const label = document.createElement('div');
93       label.className = 'label';
94       label.textContent = `Peer: ${peerId}`;
95
96       videoWrapper.append(video);
97       videoWrapper.append(label);
98
99       document.getElementById('remote-video-container').append(videoWrapper);
100   }

Explanation of Code

  • peers Object: Keeps track of all connected peers to manage multiple connections.
  • handleIncomingCall Function: Handles incoming calls, adds video streams, and manages disconnections.
  • addVideoStream Function: Adds the video stream of a peer to the DOM, ensuring multiple streams can be displayed.
  • Connection Management: The connectToPeer function initiates calls to peers, while the disconnect button now properly handles multiple connections.
In this part, you've implemented the participant view to manage and display multiple video streams in your PeerJS WebRTC application. This allows for a more dynamic and interactive user experience, essential for applications like video conferencing. In the next section, we will focus on final testing and troubleshooting to ensure your application runs smoothly.

Step 6: Running and Testing Your Code

Running the Application

To see your PeerJS WebRTC application in action, follow these steps to run and test your code:

Start the Signaling Server

Ensure your signaling server is running by navigating to your project directory and running:

bash

1   node server.js
You should see the message Server is running on http://localhost:9000.

Open the Client Application

Open your browser and navigate to http://localhost:9000. You should see the join screen of your PeerJS WebRTC application.

Testing Peer Connections

Open the application in two different browser windows or tabs. Copy the Peer ID from one window and paste it into the "Connect to Peer ID" field in the other window. Click the "Connect" button to establish a connection between the two peers.

Testing Media Controls

Use the "Mute", "Stop Video", and "Disconnect" buttons to test the functionality of the media controls. Ensure that the video and audio streams are toggled correctly and that disconnections are handled properly.

Troubleshooting Common Issues

Despite careful implementation, you might encounter some common issues while running your application. Here are a few tips to help you troubleshoot and resolve them:

No Video/Audio Stream

  • Ensure that your browser has permission to access the webcam and microphone.
  • Check the console for any errors related to media devices.

Failed to Connect to Peer

  • Verify that the signaling server is running and accessible.
  • Ensure that the correct Peer ID is being used for the connection.
  • Check for any network-related issues that might be blocking the connection.

Video Not Displaying

  • Make sure the video element is correctly added to the DOM.
  • Ensure that the srcObject of the video element is correctly set to the media stream.
  • Check the console for any errors related to video playback.

Connection Drops Frequently

  • Check the network stability and ensure there are no disruptions.
  • Verify that the signaling server is running without errors.
  • Look for any errors in the console related to peer connections.

Conclusion

In this article, we've walked through the process of building a PeerJS WebRTC application using Node.js. Starting from setting up the signaling server to creating a client application, implementing user controls, and managing multiple video streams, you've learned how to create a fully functional real-time communication application. This foundation can be expanded to build more complex applications like video conferencing, collaborative tools, and real-time gaming.

Want to level-up your learning? Subscribe now

Subscribe to our newsletter for more tech based insights

FAQ