WebRTC video call with ionic, nodejs and twilio

Start with nodejs to have the foundation setup: 


(*Note: This guide will work for those who have basic knowledge of ionic)

Install the following which will be required in nodejs application

  • npm install express
  • npm install twilio
  • npm install body-parser
  • npm install cors



// load all node modules
var express = require('express');
var app = express();
var cors=require('cors');
var http = require('http');
var path = require('path');
var AccessToken = require('twilio').AccessToken;
var ConversationsGrant = AccessToken.ConversationsGrant;
var bodyParser = require('body-parser');

var server = require('http').Server(app); // create and start express server
server.listen(5000, function(){ // change 5000 to process.env.PORT if you are deploying to Heroku
    console.log('The chatroom is now live at port # ' + 5000);
});

app.get('/token', function(request, response) {
    var TWILIO_ACCOUNT_SID="your twilio SID";
    var TWILIO_API_KEY="your twilio Api Key";
    var TWILIO_API_SECRET="your twilio secret";
    var TWILIO_CONFIGURATION_SID="your twilio config sid";
    // Create an access token which we will sign and return to the client,
    // containing the grant we just created
    var token = new AccessToken(
        TWILIO_ACCOUNT_SID,
        TWILIO_API_KEY,
        TWILIO_API_SECRET
    );
    //assign the generated identity to the token
    token.identity = request.query.name;
     
    //grant the access token Twilio Video capabilities
    var grant = new ConversationsGrant();
    grant.configurationProfileSid =TWILIO_CONFIGURATION_SID;
    token.addGrant(grant);
     response.json({identity: request.query.name,
        token: token.toJwt()});
 
});

Create an account in twilio. You get your TWILIO_ACCOUNT_SID and TWILIO_API_KEY from that. You can create your TWILIO_API_SECRET and TWILIO_CONFIGURATION_SID from twilio console.

With this we have set up our API to grant the video capablities to any name we pass in the query.

I will be going through the function on the calling end and receiving end with every possible events on ionic side.  

First include the following on your index.html 


<script src="https://media.twiliocdn.com/sdk/js/common/v0.1/twilio-common.min.js"></script>
<script src="https://media.twiliocdn.com/sdk/js/conversations/v0.13/twilio-conversations.min.js"></script>

Recieving End: 

Controller:

angular.module('IonicChat.controllers')
  .controller('RecieverCtrl', function($scope, $state) {
    var accessToken;
    var conversationsClient;
    var activeConversation;
    var previewMedia;
    var accessToken;
 
    $scope.$on('$ionicView.beforeEnter', function() {
      $scope.incall = false;
      $http({
          method: 'GET',
          url: 'http://localhost:5000/token',
          params: {
            name: recieverName
          }
        })
        .success(function(data, status, headers, config) {
          accessToken = data.token;
          connectTwilio();
        }).error(function(data, status, headers, config) {
          console.log("http error", data);
        });
    })

    function connectTwilio() {
      var accessManager = new Twilio.AccessManager(accessToken);
      conversationsClient = new Twilio.Conversations.Client(accessManager);
      $localStorage.conversationsClient = conversationsClient;
      conversationsClient.listen().then(function() {
        clientConnected();
      }, function(error) {
        console.log('Could not connect to Twilio: ' + error.message);
      });
    }

    // successfully connected!
    function clientConnected() {
      conversationsClient.on('invite', function(invite) {
        if ($scope.incall == true) {
          $scope.$apply(function() {
            invite.reject();
          });
        }
        else {
          //cancel event is invoked when caller cancels the call
          invite.on('canceled', function(event) {
            console.log(event);
            conversationsClient.unlisten();
            $state.go('recievingState', {}, {
              reload: true
            });
          });
          //failed event is invoked when the ringing from caller timeouts
          invite.on('failed', function(event) {
            conversationsClient.unlisten();
            $state.go('recievingState', {}, {
              reload: true
            });
          })
          $scope.acceptCall = function() {
            invite.accept().then(conversationStarted);
          }
          $scope.rejectCall = function() {
            invite.reject();
            conversationsClient.unlisten();
            $state.go('recievingState', {}, {
              reload: true
            });
          }
        } //end of incall else logic
      });
      conversationsClient.on('reject', function(invite) {
        invite.reject();
        conversationsClient.unlisten();
        $state.go('recievingState', {}, {
          reload: true
        });
      });
    }
    // conversation is live
    function conversationStarted(conversation) {
      activeConversation = conversation;
      document.getElementById("local-media").innerHTML = "";
      document.getElementById("remote-media").innerHTML = "";
      if (!previewMedia) {
        conversation.localMedia.attach('#local-media');
      }
      conversation.on('participantConnected', function(participant) {
        $scope.$apply(function() {
          $scope.incall = true;
          participant.media.attach('#remote-media');
        })
      });
      conversation.on('participantDisconnected', function(participant) {
        $scope.incall = false;
        conversationsClient.unlisten();
        $state.go('recievingState', {}, {
          reload: true
        });
      });
      $scope.hangCall = function() {
        $scope.incall = false;
        conversation.disconnect();
        conversationsClient.unlisten();
        $state.go('recievingState', {}, {
          reload: true
        });
      }
    };
  })


Html side for both calling and recieving ends. 

Manage the design. Include the part with buttons and div which will have you hangCall and RecieveCall. 


<div id="local-media" autoplay></div><div id="remote-media"></div>  

Calling End:

Controller: 


angular.module('IonicChat.controllers')
.controller('CallerCtrl', function($scope,$state) {
    var accessToken;
    var conversationsClient;
    var activeConversation;
    var previewMedia;
    var accessToken;
   
    $scope.$on('$ionicView.beforeEnter', function() {
        $http({
                method: 'GET',
                url: 'http://localhost:5000/token',
                params: {
                    name: callerName
                }
            })
            .success(function(data, status, headers, config) {
                accessToken = data.token;
                connectTwilio();
            }).error(function(data, status, headers, config) {
                console.log("http error", data);
            });
    })

    function connectTwilio() {
        var accessManager = new Twilio.AccessManager(accessToken);
        conversationsClient = new Twilio.Conversations.Client(accessManager);
    }

    // bind button to create conversation
    $scope.callUser = function(recieverName) {
       
                //last i checked, options has no effect on the callwhatsoever
                var options = {};
             
                   $scope.invitePromise = conversationsClient.inviteToConversation(recieverName, options);
                    $scope.invitePromise.then(
                        conversationStarted,
                        function(error) {
                            //logic falls here when timeout, or user rejects the call and other errors
                            if($scope.selfDecline == false){
                                toastr.error('User is Busy', 'Error');
                            }
                          $state.go('callerState',{}, {reload: true});
                        }
                    );
                 
                    $scope.declineInvt = function(){
                        $scope.selfDecline = true;
                        $scope.invitePromise.cancel();
                   }
         
    };



    // conversation is live
    function conversationStarted(conversation) {
        activeConversation = conversation;
                document.getElementById("local-media").innerHTML = "";
                document.getElementById("remote-media").innerHTML = "";
                    conversation.localMedia.attach('#local-media');
        conversation.on('participantConnected', function(participant) {
            $scope.$apply(function(){
            participant.media.attach('#remote-media');
            });
        });
        conversation.on('participantDisconnected', function(participant) {
                          $state.go('callerState',{}, {reload: true});
        });
   
        $scope.hangCall = function() {
            conversation.disconnect();
            $state.go('callerState',{}, {reload: true});
        }
    };
});










Comments

Popular posts from this blog

Beginners Guide For installation of ionic and building the android project in ionic for windows.

Integration of Ionic with Visual Studio 2015