September 29, 2014
In this blog post we will see how to make outbound phone calls from the browser to a phone using Twilio . We will make use of the Twilio-JS library and Twilio-Ruby gem.
The Rails App we will be creating, is based on the Twilio Client Quick-start tutorial. That Twilio tutorial makes use of Sinatra. We will see how we can achieve this in a Rails application.
We need to setup twilio credentials. We can find account ID and auth token from our account information.
When the call is made using browser then the phone that is receiving the call has to see a number from which the call is coming. So now we need to setup a Twilio verified number. This number will be used to place the outgoing calls from. How to setup a verified number can be found here.
When our app make a call from the browser using twilio-js client, Twilio first creates a new call connection from our Browser to Twilio. It then sends a request back to our server to get information about what to do next. We can respond by asking twilio to call a number, say something to the person after a call is connected, record a call etc.
Sending of this instructions is controlled by setting up a TwiML application. This application provides information about the end point on our server, where twilio should send the request to fetch instructions. TwiML is a set of instructions, that we can use to tell Twilio what to do in different cases like when an outbound phone call is made or when an inbound SMS message is received.
Given below is an example that will say a short message How are you today?
in a call.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="woman">How are you today?</Say>
</Response>
The TwiML app can be created here. Once the app is configured then we will get appsid
.
We need to configure following information in our Rails Application:
twilio:
verified_number: <%= ENV['TWILIO_VERIFIED_NUMBER']%>
account_sid: <%= ENV['TWILIO_ACCOUNT_SID'] %>
auth_token: <%= ENV['TWILIO_AUTH_TOKEN'] %>
call_app_sid: <%= ENV['TWILIO_CALL_APP_SID'] %>
After we have the config setup, we will proceed to create the capability token. This token will be generated using the ruby gem, and passed to the javascript SDK. The token helps the twilio-js client determine, what permissions the application has like making calls, accepting calls, sending SMS, etc.
We define a TwilioTokenGeneratorService
for this purpose.
class TwilioTokenGeneratorService
def process
capability = twilio_capability()
capability.generate
end
private
def twilio_capability
capability ||= Twilio::Util::Capability.new Settings.twilio.account_sid, Settings.twilio.auth_token
capability.allow_client_outgoing Settings.twilio.call_app_sid
capability
end
end
As you can see, we first define a new Twilio::Util::Capability
instance and pass credentials to it.
We then call allow_client_outgoing
method and pass the client Sid to it. This is the identifier for the TwiML application we have previously created on Twilio.
Calling allow_client_outgoing
gives permission to the client to make outbound calls from Twilio.
Finally we call the generate
method to create a token from the capability object.
The generated token will now be passed to the Twilio JS client for connecting with Twilio. In our App we define CallsController
,
and index
action in this controller. This action takes care of setting the capability token. Our index view consists of
two buttons- to place and hangup a call, a number input field, call logs, and data field to pass capability token to the
javascript bindings. We import the Twilio-JS library in the view. The css styling being used is from the
Twilio example.
<div id="twilioToken" data-token="<%= @twilio_token %>"></div>
<button id="caller" class="call">Call</button>
<button id="hangup" class="hangup">Hangup</button>
<input type="text" id="phoneNumber" placeholder="Enter a phone number to call"/>
<div id="log">Loading pigeons...</div>
<script type="text/javascript" src="//static.twilio.com/libs/twiliojs/1.2/twilio.min.js"></script>
Next we setup coffeescript bindings to handle initialization of TwilioDevice
and making use of entered number
to place calls Twilio. We are taking care of various events like connect
, disconnect
, ready
,
etc. on TwilioDevice
instance. More information about TwilioDevice
usage can be found here.
class TwilioDevice
constructor: ->
@initTwilioDeviceBindings()
@initFormBindings()
initTwilioDeviceBindings: ->
twilio_token = $('#twilioToken').data('token')
twilio_device = Twilio.Device
# Create the Client with a Capability Token
twilio_device.setup(twilio_token, {debug: true});
#/* Let us know when the client is ready. */
twilio_device.ready ->
$("#log").text("Ready")
#/* Report any errors on the screen */
twilio_device.error (error) ->
$("#log").text("Error: " + error.message)
#/* Log a message when a call connects. */
twilio_device.connect (conn) ->
$("#log").text("Successfully established call")
#/* Log a message when a call disconnects. */
twilio_device.disconnect (conn) ->
$("#log").text("Call ended")
initFormBindings: ->
$('#caller').bind "click", (event) ->
params = {"phone_number": $('#phoneNumber').val()}
Twilio.Device.connect(params)
$('#hangup').bind "click", (event) ->
Twilio.Device.disconnectAll()
$ ->
new TwilioDevice()
If we now load this page, we should be able to see our app saying its ready to take calls.
The final step before we place calls from our App is to handle callbacks from Twilio and return TwiML
response. For
this we are going to define TwilioCallTwiMLGeneratorService
which takes care of generating this response. More information
about how we need to define the response and individual fields can be found from Twilio's docs.
What we need to define is a response as below:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+15005550000">
<Number>+15005550001</Number>
</Dial>
</Response>
We are making use of two elements here - Dial
, which makes Twilio place a call using defined callerId
value,
as the number from which the call is made, which is displayed on the callee's phone. Note that this is the same verified
number that we had specified before. Then we specify Number
which is the number, to which we want to place the call to.
This number is passed first by the javascript client to Twilio, and then back to our application by Twilio,
which we use to generate the response as above.
We define our TwilioCallTwiMLGeneratorService
to take in a phone number as parameter. It creates an instance of
Twilio::TwiML::Response
and tapping on this instance we provide Dial
element with a :callerId
value, and the Number
to place the call to. We validate the number before passing it back, and return an error if the number is invalid.
class TwilioCallTwiMLGeneratorService
attr_reader :phone_number
VALID_PHONE_NUMBER_REGEX = /^[\d\+\-\(\) ]+$/ # Matches valid phone numbers acceptable to Twilio
def initialize phone_number
@phone_number = phone_number
end
def process
Twilio::TwiML::Response.new do |r|
if VALID_PHONE_NUMBER_REGEX.match(phone_number)
r.Dial :callerId => Settings.twilio.verified_number do |d| # callerId is number from which call is made.
d.Number(CGI::escapeHTML phone_number) # The number to call
end
else
r.Error("Invalid number!")
end
end.text.strip
end
end
We are now set to define twilio's callback handler. This will be handled by the create_call
action in CallsController
.
Twilio will be sending this endpoint a POST
request along with some information specified here.
We make use of phone_number
being passed to us by Twilio and pass it along to the TwilioCallTwiMLGeneratorService
, which
return us with valid TwiML
response. Since TwiML
is a flavor of XML
, we make using render xml
to return the response.
def create_call
response_to_twilio_callback = TwilioCallTwiMLGeneratorService.new(call_params[:phone_number]).process
render xml: response_to_twilio_callback
end
def call_params
params.permit(:phone_number)
end
As create_call
endpoint will be used by Twilio API, we need to skip
authenticity token check for this action.
class CallsController < ApplicationController
skip_before_action :verify_authenticity_token, only: [:create_call]
end
Finally we need to specify the callback url in our TwiML
App on Twilio. For testing this locally, we can make use of a
service like https://ngrok.com/
, to expose this endpoint.
Our service is now ready to place calls. The complete Rails application code that we have created can be found here.
Happy calling everyone!
If this blog was helpful, check out our full blog archive.