Creating a PhoneRTC Calling App – Server Side

Wern Ancheta
Share

In the first part of this series we created the client side of our PhoneRTC application and in this article we create the server side that coordinates clients.

Signaling Server

The server-side component of the app is called the “signaling server”, as it’s used for exchanging information between peers.

Start by creating a new koler-server directory outside the www directory. Everything inside the www directory is packaged when building the app and we don’t want the server component included. Inside the new directory, open your terminal and install express, lodash and Socket.io as dependencies.

npm install express lodash socket.io

Create a new JavaScript file called koler.js and require the dependencies installed.

var express = require('express');
var app = express();
var _ = require('lodash');
var sock = require('socket.io');

Create a new server instance that will run on port 4000.

var server = app.listen(4000, function(){

  var host = server.address().address
  var port = server.address().port

  console.log('Example app listening at http://%s:%s', host, port)

});

Use the new server instance for Socket.io.

var io = sock.listen(server);

Create an array for storing users. When a user logs in, push an object containing the ID and socket ID assigned to the user. This allows us to refer to this user later when sending messages or removing the user from the users array.

var users = [];

io.on('connection', function(socket){

  socket.on('login', function(data){
    users.push({'id': data.id, 'socket': socket.id});
  });

});

Earlier we were sending messages using SocketService.emit('sendMessage') and passing an object containing the data we want to pass. The following is the server-side code for processing that message.

The name of the message you are sending on the front-end should match the name of the event on the server. In this case the name of the message is sendMessage. Once the message is received, the peer ID passed is converted to a number so it can be used with the find method in lodash to find the user with that ID. The socket ID was stored as a number and that’s why the lodash condition wouldn’t match if the data type is different.

The message is then sent to that user. So when we were sending messages from the front end, we were actually sending it to the server. The server then sends that message to its destination. That is accomplished by using the to method in Socket.io. This method accepts the socket ID of the user you want to send the message to.

socket.on('sendMessage', function(message){

  var peer_id = Number(message.peer_id);
  var contact = _.find(users, { 'id': peer_id });

  io.to(contact.socket).emit('messageReceived', message);
});

To avoid populating the users array with users that are already disconnected we add the following code. It removes the user from the users array when they disconnect. Socket.io has a disconnect event built in to it, so all we have to do is determine which users need to be removed by using the current socket ID as the basis.

The remove function in lodash accepts the array as its first argument and the function containing the condition to be checked for each user. It loops through each user and checks if the current value of the socket property is the same as the socket ID of the current socket connection.

socket.on('disconnect', function(){

  _.remove(users, function(user){
    return user.socket == socket.id;
  });

});

Now we can start the server by executing node koler.js in terminal.

Deployment

Returning to the front end, we can now install PhoneRTC. As mentioned earlier I’m only going to mention deployment in Android since I don’t have access to the Mac platform for iOS. If you’re on a Mac and are planning to deploy on iOS, you can follow the installation instructions on the official wiki of the PhoneRTC project.

When I first deployed an app that uses phoneRTC, I didn’t have any luck with the original project. Even the phoneRTC demo app didn’t work when I tested it on my phone (the audio from the phone comparable to that of a choking person). What worked for me is the fork from cesterlizi.

However I encourage you to install the original project first as it has the most activity, my phone might be a special case. Here’s the command for installing phoneRTC from the original project:

cordova plugin add https://github.com/alongubkin/phonertc.git

Note that installing the plugin might take some time depending on your internet connection.

If you decided to install the cesterlizi fork you need to update the PhoneRTCPlugin.java file. Search for that file inside the plugins/com.dooble.phonertc directory. It should be inside the plugins/com.dooble.phonertc/src/android/com/dooble/phonertc directory. Open the file and look for the createVideoView function:

private void createVideoView() {
  Point size = new Point();
  size.set(_videoConfig.getContainer().getWidth() * _videoConfig.getDevicePixelRatio(),
  _videoConfig.getContainer().getHeight() * _videoConfig.getDevicePixelRatio());

  _videoView = new VideoGLView(cordova.getActivity(), size);
  VideoRendererGui.setView(_videoView);

  webView.addView(_videoView, _videoParams);
}

Replace the last line of the function with:

//webView.addView(_videoView, _videoParams); //remove this line
((WebView) webView.getView()).addView(_videoView, _videoParams);

And inside the refreshVideoView function, replace:

if (_videoView != null) {
  webView.removeView(_videoView); //remove this line
  _videoView = null;
}

With:

if (_videoView != null) {
  ((WebView) webView.getView()).removeView(_videoView); //replacement
  _videoView = null;
}

And in the onSessionDisconnect function, replace:

if (_videoView != null) {
  _videoView.setVisibility(View.GONE);
  webView.removeView(_videoView); //remove this line
}

With:

if (_videoView != null) {
  _videoView.setVisibility(View.GONE);
  ((WebView) webView.getView()).removeView(_videoView); //replacement
}

The changes made relate to the pluggable webviews in Cordova. If you stick with the old code, you will see an error when compiling the app to Android

Once those changes are made, compile the app. Do this by executing cordova build in terminal. If the build completes successfully, connect your device and copy the apk file to it. You can find the apk file in the platforms/android/build/outputs/apk directory. If you’ve used the original project and the build returns an error then uninstall the plugin using:

cordova plugin rm com.dooble.phonertc

And install the fork.

cordova plugin add https://github.com/cesterlizi/phonertc.git

Once you’ve installed the app on your phone, you can test the app by installing the browser platform so that you can test with your phone and browser. To do that, execute the following.

cordova platform add browser

This should add a browser folder in the platforms directory. Open the platforms/browser/cordova/run file. If you’re on linux, you can add either of the following in the switch statement for the browser to run.

case 'linux': spawn('google-chrome', ['--test-type', '--disable-web-security', '--user-data-dir=/tmp/temp_chrome_user_data_dir_for_cordova_browser', project]);
case 'linux': spawn('chromium-browser', ['--test-type', '--disable-web-security', '--user-data-dir=/tmp/temp_chromium_user_data_dir_for_cordova_browser', project]);

Once added, you can run a browser instance which has all the features for running a Cordova app.

cordova run browser

Here’s how the app looks in the browser:

koler app in the browser

You can use the device emulator on Chrome to make it look more like an actual mobile app.

Here’s how it looks on mobile:

mobile default

When the user is initiating a call:

user initiates call

And when the call is in progress:

call in progress

Conclusion

That’s it! In this tutorial you’ve learned how to build an audio calling app with Ionic, Cordova, PhoneRTC and Socket.io. You can find the complete code that I’ve used in this tutorial on Github.

I would love to hear your experiences and ideas on what you’ve learnt.