Twilio SDK Integration for Calls in Mobile Application
Twilio Voice SDK handles media transport, audio encoding, TURN infrastructure and global routing via own data centers. Developer remains: signaling via Twilio, audio session management on platform and system call interface integration. Faster than WebRTC from scratch but less flexible and expensive on scale.
Server Side: Access Token
Twilio Voice SDK authenticates via short-lived Access Token generated by your backend using Twilio Helper Library. Token contains VoiceGrant — permissions for incoming and outgoing calls.
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
token = AccessToken(
account_sid=ACCOUNT_SID,
signing_key_sid=API_KEY_SID,
private_key=API_KEY_SECRET,
identity=user_id,
ttl=3600
)
token.add_grant(VoiceGrant(
outgoing_application_sid=TWIML_APP_SID,
incoming_allow=True
))
return token.to_jwt()
Mobile client gets token on startup and updates before expiration. Twilio SDK notifies via delegate accessTokenInvalidOrExpired — then make request for new token and call updateAccessToken.
Android SDK
Dependency: com.twilio:voice-android:6.x.x. SDK works over WebRTC but provides high-level API.
// Initialization
Voice.initialize(context, LogLevel.DEBUG)
// Outgoing call
val connectOptions = ConnectOptions.Builder(accessToken)
.params(mapOf("To" to phoneNumber))
.build()
val call = Voice.connect(context, connectOptions, object : Call.Listener {
override fun onConnected(call: Call) { /* call established */ }
override fun onDisconnected(call: Call, error: CallException?) { /* terminated */ }
override fun onConnectFailure(call: Call, error: CallException) { /* error */ }
})
Incoming calls arrive via FCM. Twilio SDK processes FCM payload via Voice.handleMessage():
override fun onMessageReceived(message: RemoteMessage) {
if (Voice.handleMessage(context, message.data, object : MessageListener {
override fun onCallInvite(callInvite: CallInvite) {
// show incoming call notification
showIncomingCallNotification(callInvite)
}
override fun onCancelledCallInvite(cancelledInvite: CancelledCallInvite, ...) {
// call cancelled before answer
}
})) { /* this is Twilio push */ }
}
Accepting call: callInvite.accept(context, callListener).
iOS SDK
CocoaPods: pod 'TwilioVoice', '~> 6.x'. PushKit mandatory for incoming calls — APNs VoIP channel.
// Register PushKit token in Twilio
func pushRegistry(_ registry: PKPushRegistry,
didUpdate credentials: PKPushCredentials,
for type: PKPushType) {
TwilioVoice.register(accessToken: token,
deviceToken: credentials.token) { error in }
}
// Incoming call via PushKit
func pushRegistry(_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType,
completion: @escaping () -> Void) {
TwilioVoice.handleNotification(payload.dictionaryPayload,
delegate: self,
delegateQueue: nil)
// MUST call CallKit reportNewIncomingCall before completion
}
Breaking rule of CallKit call before completion in PushKit delegate — forced iOS app termination. This isn't warning — it's crash.
CallKit integration via TVODefaultAudioDevice — Twilio provides ready AVAudioSession manager correctly interacting with CallKit. Can replace with custom via TwilioVoice.audioDevice = customDevice.
TwiML and Server Routing
When mobile client calls via Twilio, request goes to your TwiML Application webhook. Backend responds with TwiML — XML instructions for Twilio:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+1234567890">
<Client>recipient_user_id</Client>
</Dial>
</Response>
For calls to regular phone numbers — <Number> instead of <Client>. Twilio acts intermediary, your server manages routing logic.
Call Recording and Analytics
Recording via TwiML <Record> or programmatically via REST API — available without SDK changes. Twilio stores recordings on its servers providing download URL. Call analytics (duration, quality, statuses) — via Twilio Console or REST API.
Limitations and When to Look at WebRTC
Twilio Voice adds latency via relay — all media streams go through Twilio data centers not P2P. For most tasks unnoticeable (< 50 ms extra latency at nearest PoP) but in regions without close Twilio data center (Central Asia, parts of Africa) latency noticeable.
Cost: Twilio Voice billing — per connection minute. On large volume (10,000+ minutes/day) own WebRTC + TURN cheaper but more expensive develop and maintain.
What's Included
Setup Twilio account (TwiML App, API Keys, Push Credentials), implement backend for Access Token generation and webhook, integrate Twilio Voice SDK on Android and/or iOS with CallKit/ConnectionService, test incoming/outgoing calls on real devices.
Timeline: 1–3 weeks depending on routing complexity and call UI requirements.







