Simplified Peer to Peer Communication with PeerJS

JavaScript library that acts as a wrapper around WebRTC

Implementing peer-to-peer communication is a challenging task. But, if you know the correct tools, you can make it a whole lot easier.

So, in this article, I will discuss PeerJS, a JavaScript library that acts as a wrapper around WebRTC, making it easier to implement peer-to-peer communication in web applications.

How PeerJS Simplifies WebRTC?

When it comes to real-time P2P communication in web applications, WebRTC is the standard used by many developers. But, it comes with some complexities as follows;

  • If you use pure WebRTC, first, you define a STUN (Session Traversal Utilities for NAT) server to generate ICE (Interactive Connectivity Establishment) candidates for each peer involved in communication.
  • Then you need to use your servers to store these ICE candidate details.
  • Finally, you need to implement WebSockets to handle real-time updates.

Even you haven’t worked with WebRTC before; I’m sure you must be feeling the complexity of its implementation. But, don’t worry, PeerJS is here for the rescue.

With PeerJS, we don’t have to worry about STUNs, ICE candidates, or server creation. We can even avoid implementing WebSockets as well.

PeerJs provides a complete, configurable peer-to-peer connection API and a server called PeerServer to easily establish connections between PeerJS clients.

So, let’s see how we can use PeerJS to create a simple chat application.

Building Your First Chat Room with PeerJS and React

Step 1 — Installing PeerJS

First, we need to install PeerJS library to your project as a node module and the peer library as a global dependency.

// Installing PeerJS
npm i peerjs
// Installing Peer
npm i -g peer

Note: PeerJS library is used to start the PeerServer locally. You can also use the PeerServer Cloud instance as well.

Step 2 — Implementing the Chat Room

Now, let’s move to our React application and get things started by initializing the state of the chat component.

Inside the state, we will be handling our ID, peer ID, chat messages, and an instance of Peer object.

state = {
myId: '',
friendId: '',
peer: {},
message: '',
messages: []
}

Then we need to create a Peer instance by defining hostname, port, and path to manage our P2P connection. We will use this instance throughout the communication process.

const peer = new Peer('', {
host: 'localhost',
port: '3001',
path: '/'
});

Tip: You can use your own ID as the first argument or leave it undefined for the PeerServer to generate a random ID. If you use const peer = new Peer(); you will be connected to PeerServer Cloud.

Peer instance has several methods to handle communication between peers. peer.on is used to listen to peer events, and it is useful when receiving calls from remote peers.

open event will be emitted after successfully connecting to PeerServer, and we will use this event to update the state of myId and peer instance.

peer.on('open', (id) => {
this.setState({
myId: id,
peer: peer
});
});

Then, we need to use the connection event to listen to remote peer connections, and we can use its callback to grab the message sent by the remote peer.

peer.on('connection', (conn) => {
conn.on('data', (data) => {
      this.setState({
messages: [...this.state.messages, data]
});
   });
});

Now, we have implemented all the functionalities to receive messages. As the final step, let’s create a method to send a message.

peer.connect method allows us to connect to the peer by specifying peer id. Then it returns a DataConnection object which can be used to send message data to the peer.

send = () => {
const conn = this.state.peer.connect(this.state.friendId);
  conn.on('open', () => {
    const msgObj = {
sender: this.state.myId,
message: this.state.message
};
   conn.send(msgObj);
    this.setState({
messages: [...this.state.messages, msgObj],
message: ''
});
  });
}

Step 3 — Video Chat Implementation

Now, let’s modify our chat room to send video messages. Implementing it is pretty much similar to what we discussed in the previous step. We can use the call event inside peer.on method to listen to calls from the remote peer. It will provide a callback with an object named MediaConnection and receiver’s video and audio streams are provided to the answer method of MediaConnection object.

peer.on('call', (call) => {
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
getUserMedia({ video: true, audio: true }, (stream) => {
  this.myVideo.srcObject = stream;
this.myVideo.play();

call.answer(stream);
  call.on('stream', (remoteStream) => {
this.friendVideo.srcObject = remoteStream;
this.friendVideo.play();
});
}, err => { console.log('Error!') });
});

Now let’s make a video call to the peer from our end. This approach is similar to answering a call. We need to use the call method of the initial peer instance and provide peer ID and video stream as arguments.

call method will then return a MediaConnection object which we can use to access the peer’s stream.

videoCall = () => {
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
getUserMedia({ video: true, audio: true }, (stream) => {
  this.myVideo.srcObject = stream;
this.myVideo.play();
  const call = this.state.peer.call(this.state.friendId, stream);
  call.on('stream', (remoteStream) => {
this.friendVideo.srcObject = remoteStream;
this.friendVideo.play();
});
}, err => { console.log('Error!') });
}

Step 4 — Finalizing Things

Finally, it’s time to add some JSX to render our chat room. Let’s add two input fields for peer ID and chat messages. We will use the ref attribute to access the video element.

return (
<div className="wrapper">
<div className="col">
<h1>My ID: {this.state.myId}</h1>
    <label>Friend ID:</label>
<input
type="text"
value={this.state.friendId}
onChange={e => { this.setState({ friendId: e.target.value });}} />
<br />
<br />
    <label>Message:</label>
<input
type="text"
value={this.state.message}
onChange={e => { this.setState({ message: e.target.value }); }} />
    <button onClick={this.send}>Send</button>
<button onClick={this.videoCall}>Video Call</button>
{
this.state.messages.map((message, i) => {
return (
<div key={i}>
<h3>{message.sender}:</h3>
<p>{message.message}</p>
</div>
)
});
}
</div>
<div className="col">
<div>
<video ref={ref => this.myVideo = ref} />
</div>
<div>
<video ref={ref => this.friendVideo = ref} />
</div>
</div>
</div>
);

That’s it! Now we are all set for a quick video chat. The final implementation will look like this and you can find the full code in my GitHub repository.

Note: Some browsers (especially mobile browsers) may not allow camera and microphone access without an HTTPS connection. You can refer to this article to set up a local HTTPS connection in few steps.

Build & share JS components with Bit

Bit is an extensible tool that lets you create truly modular applications with independently authored, versioned, and maintained components.

Use it to build modular apps & design systems, author and deliver micro frontends, or share components between applications.

An independently source-controlled and shared “card” component. On the right => its dependency graph, auto-generated by Bit.

Bit: The platform for the modular web

Final Words

Web RTC is the browser standard that enables real-time peer-to-peer communication. But implementing WebRTC is a bit complex due to the involvement of STUN Servers, ICE candidates, SDPs, and WebSockets.

PeerJS simplifies the whole process by acting as a wrapper to WebRTC and provides us with much simpler events and methods to work.

So, I invite you to try PeerJS and let me know your thoughts in the comments section.

Thank you for Reading !!!

Learn More


Simplified Peer to Peer Communication with PeerJS was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Dulanka Karunasena

JavaScript library that acts as a wrapper around WebRTC

Implementing peer-to-peer communication is a challenging task. But, if you know the correct tools, you can make it a whole lot easier.

So, in this article, I will discuss PeerJS, a JavaScript library that acts as a wrapper around WebRTC, making it easier to implement peer-to-peer communication in web applications.

How PeerJS Simplifies WebRTC?

When it comes to real-time P2P communication in web applications, WebRTC is the standard used by many developers. But, it comes with some complexities as follows;

  • If you use pure WebRTC, first, you define a STUN (Session Traversal Utilities for NAT) server to generate ICE (Interactive Connectivity Establishment) candidates for each peer involved in communication.
  • Then you need to use your servers to store these ICE candidate details.
  • Finally, you need to implement WebSockets to handle real-time updates.

Even you haven’t worked with WebRTC before; I’m sure you must be feeling the complexity of its implementation. But, don’t worry, PeerJS is here for the rescue.

With PeerJS, we don’t have to worry about STUNs, ICE candidates, or server creation. We can even avoid implementing WebSockets as well.

PeerJs provides a complete, configurable peer-to-peer connection API and a server called PeerServer to easily establish connections between PeerJS clients.

So, let’s see how we can use PeerJS to create a simple chat application.

Building Your First Chat Room with PeerJS and React

Step 1 — Installing PeerJS

First, we need to install PeerJS library to your project as a node module and the peer library as a global dependency.

// Installing PeerJS
npm i peerjs
// Installing Peer
npm i -g peer
Note: PeerJS library is used to start the PeerServer locally. You can also use the PeerServer Cloud instance as well.

Step 2 — Implementing the Chat Room

Now, let’s move to our React application and get things started by initializing the state of the chat component.

Inside the state, we will be handling our ID, peer ID, chat messages, and an instance of Peer object.

state = {
myId: '',
friendId: '',
peer: {},
message: '',
messages: []
}

Then we need to create a Peer instance by defining hostname, port, and path to manage our P2P connection. We will use this instance throughout the communication process.

const peer = new Peer('', {
host: 'localhost',
port: '3001',
path: '/'
});
Tip: You can use your own ID as the first argument or leave it undefined for the PeerServer to generate a random ID. If you use const peer = new Peer(); you will be connected to PeerServer Cloud.

Peer instance has several methods to handle communication between peers. peer.on is used to listen to peer events, and it is useful when receiving calls from remote peers.

open event will be emitted after successfully connecting to PeerServer, and we will use this event to update the state of myId and peer instance.

peer.on('open', (id) => {
this.setState({
myId: id,
peer: peer
});
});

Then, we need to use the connection event to listen to remote peer connections, and we can use its callback to grab the message sent by the remote peer.

peer.on('connection', (conn) => {
conn.on('data', (data) => {
      this.setState({
messages: [...this.state.messages, data]
});
   });
});

Now, we have implemented all the functionalities to receive messages. As the final step, let’s create a method to send a message.

peer.connect method allows us to connect to the peer by specifying peer id. Then it returns a DataConnection object which can be used to send message data to the peer.

send = () => {
const conn = this.state.peer.connect(this.state.friendId);
  conn.on('open', () => {
    const msgObj = {
sender: this.state.myId,
message: this.state.message
};
   conn.send(msgObj);
    this.setState({
messages: [...this.state.messages, msgObj],
message: ''
});
  });
}

Step 3 — Video Chat Implementation

Now, let’s modify our chat room to send video messages. Implementing it is pretty much similar to what we discussed in the previous step. We can use the call event inside peer.on method to listen to calls from the remote peer. It will provide a callback with an object named MediaConnection and receiver’s video and audio streams are provided to the answer method of MediaConnection object.

peer.on('call', (call) => {
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
getUserMedia({ video: true, audio: true }, (stream) => {
  this.myVideo.srcObject = stream;
this.myVideo.play();

call.answer(stream);
  call.on('stream', (remoteStream) => {
this.friendVideo.srcObject = remoteStream;
this.friendVideo.play();
});
}, err => { console.log('Error!') });
});

Now let’s make a video call to the peer from our end. This approach is similar to answering a call. We need to use the call method of the initial peer instance and provide peer ID and video stream as arguments.

call method will then return a MediaConnection object which we can use to access the peer’s stream.

videoCall = () => {
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
getUserMedia({ video: true, audio: true }, (stream) => {
  this.myVideo.srcObject = stream;
this.myVideo.play();
  const call = this.state.peer.call(this.state.friendId, stream);
  call.on('stream', (remoteStream) => {
this.friendVideo.srcObject = remoteStream;
this.friendVideo.play();
});
}, err => { console.log('Error!') });
}

Step 4 — Finalizing Things

Finally, it’s time to add some JSX to render our chat room. Let’s add two input fields for peer ID and chat messages. We will use the ref attribute to access the video element.

return (
<div className="wrapper">
<div className="col">
<h1>My ID: {this.state.myId}</h1>
    <label>Friend ID:</label>
<input
type="text"
value={this.state.friendId}
onChange={e => { this.setState({ friendId: e.target.value });}} />
<br />
<br />
    <label>Message:</label>
<input
type="text"
value={this.state.message}
onChange={e => { this.setState({ message: e.target.value }); }} />
    <button onClick={this.send}>Send</button>
<button onClick={this.videoCall}>Video Call</button>
{
this.state.messages.map((message, i) => {
return (
<div key={i}>
<h3>{message.sender}:</h3>
<p>{message.message}</p>
</div>
)
});
}
</div>
<div className="col">
<div>
<video ref={ref => this.myVideo = ref} />
</div>
<div>
<video ref={ref => this.friendVideo = ref} />
</div>
</div>
</div>
);

That’s it! Now we are all set for a quick video chat. The final implementation will look like this and you can find the full code in my GitHub repository.

Note: Some browsers (especially mobile browsers) may not allow camera and microphone access without an HTTPS connection. You can refer to this article to set up a local HTTPS connection in few steps.

Build & share JS components with Bit

Bit is an extensible tool that lets you create truly modular applications with independently authored, versioned, and maintained components.

Use it to build modular apps & design systems, author and deliver micro frontends, or share components between applications.

An independently source-controlled and shared “card” component. On the right => its dependency graph, auto-generated by Bit.

Bit: The platform for the modular web

Final Words

Web RTC is the browser standard that enables real-time peer-to-peer communication. But implementing WebRTC is a bit complex due to the involvement of STUN Servers, ICE candidates, SDPs, and WebSockets.

PeerJS simplifies the whole process by acting as a wrapper to WebRTC and provides us with much simpler events and methods to work.

So, I invite you to try PeerJS and let me know your thoughts in the comments section.

Thank you for Reading !!!

Learn More


Simplified Peer to Peer Communication with PeerJS was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Dulanka Karunasena


Print Share Comment Cite Upload Translate Updates
APA

Dulanka Karunasena | Sciencx (2021-08-04T20:44:24+00:00) Simplified Peer to Peer Communication with PeerJS. Retrieved from https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/

MLA
" » Simplified Peer to Peer Communication with PeerJS." Dulanka Karunasena | Sciencx - Wednesday August 4, 2021, https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/
HARVARD
Dulanka Karunasena | Sciencx Wednesday August 4, 2021 » Simplified Peer to Peer Communication with PeerJS., viewed ,<https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/>
VANCOUVER
Dulanka Karunasena | Sciencx - » Simplified Peer to Peer Communication with PeerJS. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/
CHICAGO
" » Simplified Peer to Peer Communication with PeerJS." Dulanka Karunasena | Sciencx - Accessed . https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/
IEEE
" » Simplified Peer to Peer Communication with PeerJS." Dulanka Karunasena | Sciencx [Online]. Available: https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/. [Accessed: ]
rf:citation
» Simplified Peer to Peer Communication with PeerJS | Dulanka Karunasena | Sciencx | https://www.scien.cx/2021/08/04/simplified-peer-to-peer-communication-with-peerjs/ |

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.