preface

When we learn WebRTC, we should first set up the experimental environment, so that we can do all kinds of experiments on it.

For WebRTC, there is a whole set of specifications, such as the interface to make it use, media negotiation using SDP, address collection through ICE, connectivity detection, and so on. In addition, WebRTC also requires room server to gather multiple terminals together for management, and signaling server to exchange signaling data (such as exchange of media description information SDP and exchange of connection address, etc.). However, there is no regulation on this part in WebRTC specification, so it needs to be handled by users themselves.

You can choose a server of your choice (such as Apache, Nginx or Nodejs), and TODAY I will show you how to build a signaling server using Nodejs.

Why Nodejs

Apache, Nginx, and Nodejs are all mature Web servers, and Nginx is arguably the best performing Web server. But going forward, Nodejs may have the edge.

Browsers like Chrome are becoming more powerful, making it easier to do things that were previously thought impossible through a browser. With the advent of H5, WebSocket and now WebRTC, there is a growing sense that the browser of the future can do anything. As a result, the development of JavaScript language is getting faster and faster. This can be confirmed by the popularity of JavaScript technology and the emergence of various cascading JS frameworks.

The biggest advantage of Nodejs is that you can use JS to develop server programs. This allows a large number of front-end students to seamlessly transfer to the server development, and it is even possible to use the same set of code at the front and back ends. I think this is a big temptation for both individuals and enterprises.

  • On the one hand, the simplicity of JS language can facilitate the development of a variety of functions of the server program.

  • What’s more, the Nodejs ecosystem is very complete, with a variety of libraries. You can use the installation tool NPM to install it quickly according to your needs, which makes it popular with developers.

Nodejs is now a very popular Web server that uses the V8(JavaScript) engine on the server side to control the behavior of the server by parsing JavaScript scripts. This for the majority of JS students is really too happy, in 10 years ago, it was hard to imagine that you can write server programs through JS scripting language.

Of course, if you want to extend Nodejs capabilities, you still need to write C/C++ libraries and load them into Nodejs.

The fundamentals of Nodejs

Nodejs works as shown above, with a V8 engine at its heart. With this engine, you can have JS call C/C++ methods or objects. Conversely, it is also possible to give C/C++ access to javascript methods and variables.

Nodejs first hands the JavaScript application to V8 for parsing. After V8 understands the semantics of the application, it invokes Nodejs’ underlying C/C++ API to start the service. The power of Nodejs lies in the fact that JS can directly call C/C++ methods, making it infinitely scalable.

Take developing an HTTP service as an example. After Nodejs opens the listening service port, libuv is called to process all HTTP requests on that port. Its network event processing is shown in the figure below:

When a network request comes in, it is first inserted into an event processing queue. Libuv will monitor the event queue. When it finds an event, it will judge the request first. If it is a simple request, it will directly return the response. If it is a complex request, a thread is taken from the thread pool and processed asynchronously;

After the thread finishes processing, there are two possibilities: one is to send a response to the user after the processing is complete; Another case is that further processing is needed, it is regenerated into an event and inserted into the event queue for processing; Event processing continues in a never-ending loop.

Two V8s

As you can see above, there are actually two V8s after we use Nodejs. A V8 JS application that parses the server and gets the service started. The other V8 is the V8 engine in the browser, which controls the behavior of the browser.

It’s easy to get confused when you’re new to Nodejs because you have to put at least two JS scripts on the server. One is a server-side program that controls Nodejs behavior and is parsed by the Nodejs V8 engine. The other is the client program, it is to be requested by the browser, delivered to the browser, by the browser’s V8 engine parsing processing. If you can’t tell this apart, you’re in big trouble.

Install Nodejs

Let’s take a look at how to install Nodejs.

Installing Nodejs is very simple:

Run in Ubuntu:

apt install nodejs
Copy the code

Or on a Mac system:

brew install nodejs
Copy the code

After the above steps we have Nodejs installed. The Nodejs version I have installed here is v8.10.0.

Install the NPM

In addition to installing Nodejs, we also need to install NPM(Node Package Manager), which is the Package Manager for Nodejs. Similar to apt on Ubuntu or BREW on Mac, it is designed to manage dependent libraries.

We had a lot of trouble installing a package before they showed up. Using Linux as an example, suppose you want to install a tool that follows the following basic steps:

  • Download the source code for this tool first.
  • Execute./configure to generate the Makefile.
  • Run the make command to compile it.
  • Finally, run make Install to install it in the specified directory.
  • If a dependent library is found during compilation, perform the previous four steps to install the dependency library before installing the tool.

You can see how cumbersome it used to be to install a program or tool under Linux.

Linux with APT makes everything easier. Just execute apt install XXX and it will do all of the above for you.

The same is true for Nodejs installation packages. NPM is the Linux equivalent of APT, which has greatly improved productivity.

Installing NPM is as simple as installing Nodejs:

Run in Ubuntu:

apt install npm
Copy the code

Or run on a Mac:

brew install npm
Copy the code

socket.io

This time, we use the socket. IO library under Nodejs to implement WebRTC signaling server. Socket. IO is particularly suitable for developing WebRTC signaling servers, and it is particularly easy to build signaling servers from it, mainly because of the built-in room concept.

The diagram above shows the logical relationship between socket. IO and Nodejs. The logic is very simple. Socket. IO consists of a server and a client. IO is loaded by Nodejs and listens for a service port. To connect to the server, the client first loads the socket. IO client library and then calls IO. It’s connected to the server.

Special emphasis is placed on the sending and receiving of socket. IO messages. Socket. IO has many different ways to send messages. The most common ones are the following, which we must support:

  • Send a message to this connection

    socket.emit()
    
    Copy the code
  • Send a message to everyone in a room

    io.in(room).emit()
    
    Copy the code
  • Send a message to everyone in a room except this connection

    socket.to(room).emit()
    
    Copy the code
  • Send messages to all people in addition to this link

    socket.broadcast.emit()
    Copy the code

How should messages be received?

  • Send command

    S: socket.emit('cmd’);
    C: socket.on('cmd',function(){... });Copy the code
  • Send a command with data

    S: socket.emit('action', data);
    C: socket.on('action'.function(data){... });Copy the code
  • I sent command, and I sent two pieces of data

    S: socket.emit(action,arg1,arg2);
    C: socket.on('action'.function(arg1,arg2){... });Copy the code

With this knowledge, we can realize signaling data communication.

Setting up a Signaling Server

Let’s look at how to build a server using socket. IO under Nodejs:

This is client-side code, that is, code that executes in the browser. Index.html:

<! DOCTYPE html> <html> <head> <title>WebRTC client</title> </head> <body> <script src='/socket.io/socket.io.js'></script>
    <script src='js/client.js'></script>
  </body>
</html>

Copy the code

This code is quite simple, just introducing two pieces of JS code inside the body. Socket.io. Js is used to establish a socket connection with the server. The function of client.js is to do some business logic, and finally communicate with the server through socket.

Here is the code for client.js:

var isInitiator;

room = prompt('Enter room name:'); // pop up an input window const socket = io.connect(); // Establish a socket connection with the serverif(room ! = =' ') {// If the room is not empty, send"create or join"The message console. The log ('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {// If received from server"full"The message console. The log ('Room ' + room + ' is full');
});

socket.on('empty', (room) => {// If received from server"empty"Message isInitiator =true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {// If "Join" is received from the server"Message console.log('Making Request to join room '+ room); console.log('You are the initiator! '); }); socket.on('log', (array) => { console.log.apply(console, array); });Copy the code

In this code:

  • An input box pops up asking the user to write the room to join.
  • The connection to the server is then established through io.connect(),
  • Different processing is performed according to the message returned by the socket:
    • When the room is “full”;
    • What happens when you receive “empty” for the room;
    • When receiving join” join”;

This is the code that executes on the client side (that is, in the browser). Let’s take a look at the server-side processing logic:

Server-side code, server.js:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app); // Listen for 2013 IO. Sockets. On ('connection', (socket) => {

  // convenience function to log server messages to the client
  function log(){ 
    const array = ['>>> Message from server: ']; 
    for (var i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    } 
      socket.emit('log', array);
  }

  socket.on('message', (message) => {// Broadcast the message when receivedlog('Got message:', message);
    // for a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message); // In real applications, this should only be broadcast in the room}); socket.on('create or join', (room) => {// The create or Join message is received var clientsInRoom = io.sockets.Adapter. rooms[room]; var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; // The number of people in the roomlog('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if(numClients === 0){// If no one is in the room socket.join(room); socket.emit('created', room); / / send"created"Message}else if(numClients === 1) {// If there is one person in the room io.sockets. In (room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room); // Send the "joined" message}else { // max two clients
      socket.emit('full', room); / / send"full"Message} socket. Emit ('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});
Copy the code

The node-static library is introduced on the server side to enable the server to publish static files. When the server has this function, when the client (browser) makes a request to the server, the server obtains the code that the client (browser) runs through this module, that is, the index. HTML and client.js we mentioned above, and sends them to the client (browser).

The server listens on port 2013 and processes different messages accordingly:

  • When the server receives a Message, it broadcasts the message directly, and all clients connected to the server receive the broadcast message.
  • When the server receives the “Create or Join” message, it counts the number of people in the room. If no one is in the room, it sends the “Created” message. If there is one person in the room, send the “Join” message and the “joined” message. If there are more than two people, send a “full” message.

To run the program, use NPM to install socket. IO and Node-static as follows:

npm install socket.io
npm install node-static
Copy the code

Start the server and test

With the above steps we have built a server using socket. IO. Now we can start the service with the following command:

node server.js
Copy the code

If you are setting up the service on your computer, enter localhost:2013 in the browser, then create a TAB and enter localhost:2013 again. At this point, open the console and see what’s going on?

In Chrome you can access the console using the DevTools shortcut command-option-j or Ctrl-shift-j.

summary

Above, I introduced the working principle of Nodejs, installation and deployment of Nodejs, and how to use Sokcet. IO to build WebRTC signaling server. Socket. IO is a good match with WebRTC because of the concept of room, and it is very convenient to develop WebRTC signaling server.

In addition, the example in this article is a simple one and does not have much practical value. In my “WebRTC Real-time interactive live broadcasting Technology Introduction and actual combat” class, I will teach you how to realize the WebRTC signaling server step by step based on the above examples, and cooperate with WebRTC to realize the 1-to-1 audio and video real-time interactive live broadcasting system.

Courses address

WebRTC real-time interactive live broadcast technology introduction and actual combat