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
Post a Comment