How socket.io interacts with node.js in a WebRTC application.

jerrymcdonald

JerryMcDonald

Posted on July 10, 2020

How socket.io interacts with node.js in a WebRTC application.

Are you building an application that will utilize webRTC for real-time communication features? If so, and you have a node.js environment in the back end of your application, you will likely want to use Socket.io to create connections. In this blog, I will add Socket.io to your server-side code and create some event listeners and handlers.

Let's first talk a little about the WebRTC portion of our application. WebRTC stands for real-time Web communication, and as the name suggests, we are talking about how peers communicate in real-time from inside their browser. What is interesting about webRTC streams (for example, voice and video) is they are 'server-less communication.' But I do not mean they do not require a server to create the connection; once established, the streaming in your web application will continue in the browser. They do not need more work from your server.

To get the video and voice stream communication established between the two web browsers, we can use socket.io to establish the 'handshake.'

Socket.io enables real-time, bi-directional communication between web clients and servers. It has two parts: a client-side library that runs in the browser and a server-side library for Node.js. Both components have a nearly identical API.

Down below, we will watch the server-side library, listening for a connection from our webRTC front end application.


The first thing you want to do in your Node.js application is to make sure you have express installed. Express.js is considered the de facto standard server framework for Node.js.

$ npm install express
Enter fullscreen mode Exit fullscreen mode

Now install socket.io, and we can get started.

npm i socket.io
Enter fullscreen mode Exit fullscreen mode

The following code is in the server.js file. The first thing you want to do is require and Call the express function "express()" that will put a new Express application inside the app variable (to start a new Express application)

const express = require('express');
const app = express();
Enter fullscreen mode Exit fullscreen mode

HTTP is a built-in Node.js module that allows Node.js to transfer data over the HyperText Transfer Protocol (HTTP). It will enable us to use the HTTP.createServer() method to create the server object. We are turning our computer into an HTTP server.

const http = require('http');
const server = http.createServer(app);
Enter fullscreen mode Exit fullscreen mode

Now we can import socket.io and create a socket server

const socket = require('socket.io');
const io = socket(server);
Enter fullscreen mode Exit fullscreen mode

Then creating a room object will allow us to store users that connect to our video chat.

const rooms = {};
Enter fullscreen mode Exit fullscreen mode

We will create an event listener with io that will wait for that 'connection' signal. I will show the whole connection function at once.

io.on('connection', socket => {
  // attach an event listener
  // Grab the room ID from the browser
  socket.on('join room', roomID => {
    // check if roomID exists
    if (rooms[roomID]) {
      // if so add the joining users socket id to the ids array
      // (each socket will have a unique id)
      rooms[roomID].push(socket.id);
    } else {
      // else create the key/value pair
      rooms[roomID] = [socket.id];
    }
    // check if you are currently user a joining or user b
    const otherUser = rooms[roomID].find(id => id !== socket.id);
    if (otherUser) {
      // if the other user exists in the room..
      // (user b) emit a 'current' back up to ourselves with the other users socket id
      socket.emit('other user', otherUser);
      // emit the other users socket.id
      socket.to(otherUser).emit('user joined', socket.id);
      // you can see how this plays out more on the front end.
    }
  });
Enter fullscreen mode Exit fullscreen mode

In the above code snippet. Once a connection is established with io.on('connection'), a socket object is created. This object will allow us to create more event listeners, and it will have a unique socket id. We then create the socket.on('join room') event listener that will wait from a signal from our front end app called join room. When this event fires, we can store the unique room id (also generated in the front) along with the unique socket id.

Because the current webRTC application's scope is only a peer to peer video connection (not group), that means there will only be two users in the room. You can use some creative JavaScript to check if another user is present in the room you joined.
rooms[roomID].find(id => id !== socket.id)
And if there is another user, we can 'emit' another signal back to the front of the application that will carry along the other user's socket information.

      socket.emit('other user', otherUser);
      // emit to user a our socket.id
      socket.to(otherUser).emit('user joined', socket.id);
Enter fullscreen mode Exit fullscreen mode

Because socket.io deals with bi-directional communication, we need to establish the 'offer' and 'answer' listeners to create the 'handshake' between servers. In each case of receiving an offer and sending out an answer, we handle a payload. The payload is essentially the data carried within a packet or other transmission unit.

  // Now, let us create a 'handshake.'

  // when offer gets fired
  socket.on('offer', payload => {
    io.to(payload.target).emit('offer', payload);
  });

  // the payload contains who we are as a user and the 'offer' object.

  // listen for the answer event
  socket.on('answer', payload => {
    io.to(payload.target).emit('answer', payload);
  });
Enter fullscreen mode Exit fullscreen mode

The next bit of code in establishing our connection is ice-candidate. The ICE stands for Interactive Connectivity Establishment. It is all about finding the best method for connecting to the network of the other peer. Think of your network as a large neighborhood; an ICE candidate would be the route you would take to reach a particular house. Because a lot is going on behind the networking scenes, socket.io needs to know what connection points it has to contact the other peer.

  // each peer will come up with an 'ice server'
  socket.on('ice-candidate', incoming => {
    io.to(incoming.target).emit('ice-candidate', incoming.candidate);
  });
});
Enter fullscreen mode Exit fullscreen mode

We now can create our HTTP server and have it listen on our port

server.listen(8000, () => console.log('server is running on port 8000'));
Enter fullscreen mode Exit fullscreen mode

That does it for setting up and understanding the back-end library of our socket.io application. Because the front end library has a nearly identical API. Once you understand how the event listeners and emitters work, you can find a webRTC library you would like to use and begin building your application.

As Always,
Stay Focused || Love your code!

Resources:

  1. Chaim is an excellent YouTuber that loves to talk about working with WebRTC and socket.io
  2. Socket.io docs
  3. tutorialpoint on socket.io
💖 💪 🙅 🚩
jerrymcdonald
JerryMcDonald

Posted on July 10, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related