How can my App receive calls?
To be able to receive incoming calls, you need to setup your push certificate in the Console and your app needs to register for incoming calls using [TwilioVoiceSDK registerWithAccessToken:deviceToken:completion]. Twilio will send you a push notification through APNS (Apple Push Notification Service). Check our quickstart implementation for how it is done.
Can the App receive incoming VoIP calls while it's not running or in the background?
Yes! See the FAQ "How can my App receive calls" to register for incoming calls. Once the app is registered, it will receive calls even when it's in the background or not running.
How often should I register my device token?
The device token must be registered every time it changes or if the device has not received a push notification for 1 year. We recommend you implement the following logic:
What's the difference between an Access Token and a Device Token?
An Access Token is required to access Twilio's services. A device token is a token that identifies the device so it can receive a push notification.
VoiceGrant
to the access token for the Programmable Voice SDK.identity
.PKPushRegistry
and use it in the registration methods. Also be sure to notice that the description
method on the NSData
class has changed in iOS 13, and your code may need to be updated. To properly convert an NSData object to a String, use one of these examples:1/* Obj-C */2- (void)pushRegistry:(PKPushRegistry *)registry3didUpdatePushCredentials:(PKPushCredentials *)credentials4forType:(NSString *)type {5const unsigned *tokenBytes = [credentials.token bytes];6self.deviceTokenString = [NSString stringWithFormat:@"<%08x %08x %08x %08x %08x %08x %08x %08x>",7ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),8ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),9ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];10// Call registerWithAccessToken\:deviceToken\:completion: ...11}
1/* Swift */2func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, forType type: PKPushType) {3let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()4self.deviceTokenString = deviceToken5// Call registerWithAccessToken\:deviceToken\:completion: ...6}
pod install
, but it couldn't find the latest version of the SDK
pod repo update
before trying to install new versions of the Voice SDK.@"com.apple.CallKit.error.requesttransaction" - code: 1
" error when sending the CXStartCallAction
request to the CXCallController
and was not able to make outgoing calls using the SDK
Capabilities
page of the app's project settings and make sure you have the Voice over IP
option enabled.AVAudioSession
to be .playAndRecord
so that it can access the system audio device properly. In case you need to do special manipulation to the AVAudioSession
, please make sure the category is restored to .playAndRecord
before making/accepting calls.AVAudioRecorder
to record the audio during active calls, but the limitation is that it can only record the audio of the device's input source.My phone has been off for a while and when I turn it back on, I get calls that were already hung up
Note: The following does not apply to sdk versions 2.1 onwards and 5.0 onwards. The push notification sent to those versions will only be delivered if the device is reachable when the call is placed.
Twilio Voice SDKs use push notifications (APNS, FCM/GCM) as a mechanism to notify the callee of an incoming call. However, a problem presents itself when the callee's device is offline or not reachable: the push notification services cache the notification and re-attempt delivery at a much later time. The delayed notification may arrive after the call has already been terminated. The callee's device will briefly alert the user of a call that has already terminated leading to a poor user experience. Twilio plans to address this issue in a later release. However, in the meantime the following is a proposal for a work around you can implement to avoid the poor user experience.
The following 4 step proposal allows an app developer to use time information as an additional criteria to determine whether or not to display a call notification to the user.
Step 1 Generate a UTC based timestamp on the TwiML Application Server based on the Unix epoch in milliseconds.
var timeInMS = Date.now()
Step 2 Add this generated timestamp to the <Dial>
used to reach the callee
Parameters can be sent to a callee by initiating a TwiML <Dial>
. Use the attribute to specify your key/value parameters as shown below. The value shown below is an example of a timestamp obtained in step 1. You must pass the value as string.
Pass the time as custom parameters in TwiML
1<?xml version="1.0" encoding="UTF-8"?>2<Response>3<Dial answerOnBridge="false" callerId="client:alice">4<Client>5<Identity>bob</Identity>6<Parameter name="timestamp" value="1555825985" />7</Client>8</Dial>9</Response>
When the call invite push message arrives to the callee it will have the specified parameters.
Step 3 Get the timestamp from the bundle or message provided by APNS when it arrives to the iOS application.
When receiving the push notification from Twilio, you can obtain the parameter from the bundle or message. The parameters are provided by APNS payload as the key: twi_params. The following shows how you can parse the contents of the data to get a map of the parameters you passed into the Dial. The "data" variable is the map provided by APNS
1NSString *customParams = notificationPayload[@”twi_params”];2NSMutableDictionary *customParamsDict = [NSMutableDictionary dictionary];3If ([customParams length] > 0) {4NSArray *paramPairs = [customParams componentsSeparatedByString:@"&"];5for (NSString *param in paramPairs) {6NSArray *keyValue = [param componentsSeparatedByString:@"="];7if ([keyValue count] == 2) {8NSString *decodedValue = [keyValue[1] stringByReplacingOccurrencesOfString:@"+" withString:@"%20"];9customParamsDict[keyValue[0]] = [decodedValue stringByRemovingPercentEncoding];10}11}12}
When receiving the push notification from Twilio, you can obtain the parameter from TVOCallInvite with the following:
1NSDictionary *customParameters = callInvite.customParameters;2NSString *timestamp = customParameters[@”timestamp”];
Step 4 Compare the UTC based timestamp to the UTC time on the device and discard the notification if the device time is significantly later than the timestamp generated by the server.
1// Get the timestamp from the customParameters map and the current device time2NSUInteger timestampValue = [customParameters[@”timestamp”] unsignedIntegerValue];3NSDate now = [NSDate date];45// Compare the time difference6if ([now timeIntervalSince1970] > timestampValue + 60000) {7// discard notification...8} else {9// display notification...10}
We love feedback and questions especially those with helpful debugging information so we can diagnose and respond in time.
We prefer that you create GitHub issues - that way the entire community benefits.
Please make sure you do not include any sensitive information in your GitHub issue, e.g. auth tokens, signing key secrets, Account SIDs, Calls SIDs and the like.
If you ever need to share any sensitive information with us to troubleshoot a specific issue, please contact Twilio Support through the Console or Help Center and reference your GitHub issue.
When submitting Github issues or support tickets, it would be awesome if you could also add the following:
Configure the SDK log level:
1/* Obj-C */2[VoiceClient setLogLevel:TVOLogLevelDebug];
1/* Swift */2VoiceClient.logLevel = .debug
When you have gathered all this helpful info, you can open a Github issue in the applicable Github repository:
If you are opening a support ticket through Console or Help Center, you should also submit your Twilio Account SID and Twilio Call SID, if applicable.