CallKit error com.apple.CallKit.error.requesttransaction error 7 - ios

I'm using Twilio voice quickstart code https://github.com/twilio/voice-quickstart-swift.
When I make a client to client call, call doesn't connect. CallKit runs in the background though, I can see the green notification bar when I send app in the background.
Following is the error:
StartCallAction transaction request failed: The operation couldn’t be completed. (com.apple.CallKit.error.requesttransaction error 7.)
As you can see Googling doesn't help as there doesn't seem to be any solution around?
Does anyone know how to fix or debug it further?
Updated:
Attaching VoIP settings, it's certainly enabled.

Problem is in your code which you write to handle and initialise variables. There is nothing wrong in the Twilio sdk either so don't look there. Anything which you are doing beyond twilio sample code is the place to look for the problem.
I've also wasted months of my time on similar issue and found out that there was issue with initialising one variable.

You are trying to request CXStartCallAction right after another CXStartCallAction was requested. You need to end the first call correctly.
In any case you must follow correct sequence of actions. Once you user wrong action in a sequence, CallKit will return one or another error.
And DO NOT request one action immediately after another is processed. There should be some time between two requests. For example, you initiated CXStartCallAction, then you checked that user is offline and trying to end the call. If that check is quick, then "end action" may result in error. You need to wait a few milliseconds before cancelling the outgoing call.

Twilio developer evangelist here.
Have you enabled capabilities for Voice over IP in the project settings?

Try to initialize CXProvider and CXCallController sooner, before requesting CXStartCallAction

I had the same problem because the Provider and the CallController have been lazy loaded.
It looks like that the CXProvider initWithConfiguration runs asynchronously which means you need to call this early otherwise you run into the risk of having a call without the completion of the initWithConfiguration function.
Thanks to #Allen for pointing me in the right direction.

Related

iOS CallKit - no 'missed call notifications'

I am using CallKit, and it is working fine, it calls on my phone properly, I can answer and deny it.
The problem is there is no 'missed call' notification when I do not answer it.
Is there any setting in CallKit that toggles it?
We were also facing the same issues, and the solution was to manage UILocalNotifications yourself. CallKit only provides triggers and callbacks for events.
Check out the method reportCall(with:endedAt:reason) on CXProvider. You can specify the end reason to let CallKit know why the call ended.
https://developer.apple.com/documentation/callkit/cxprovider/1930701-reportcall
The reasons include:
case failed - An error occurred while attempting to service the call.
case remoteEnded - The remote party explicitly ended the call.
case unanswered - The call never started connecting and was never
explicitly ended, such as when an outgoing or incoming call times
out.
case answeredElsewhere - Another device answered the call.
case declinedElsewhere - Another device declined the call.
If you call reportCall with a reason of unanswered, then it will show up as a missed call in the recent calls section of the phone app.

How to control upload extension initiated from controller center?

I implemented upload extension and setup RTMP server for broadcasting via upload extension. The broadcasting is initiated from control center, not through SetupUI extension. Since the SampleHandler.m doesn't provide RPBroadcastController, I can't programmatically pause or stop the broadcasting. I'd like to at least stop the broadcasting and show error message that the server is not available. I've looking through all WWDC docs, but couldn't find much info. Mobcrush is showing error message like "Not logged in", how they do that?
I found a mistakes in my code, finishBroadcastWithError function should call [super finishBroadcastWithError:] to call RPBroadcastController to stop broadcasting and show proper error message. You don't need to access RPBroadcastController nor need SetupUI to controller broadcast. That was it, I wasted 2 days on this, I wish no one do that.

Token expiration in Twilio

I'm working on embedding a soft phone into a web page that will go into Odoo (web based ERP system). It will allow inbound and outbound calls for employees.
The token expires every hour. So this means the user will have to refresh the page every hour. I could do an http refresh but if the user is on a call when it does the refresh it will knock them off the call.
How do we get around this so we can build a fully working dialer?
Twilio evangelist here.
I'd suggest using JavaScript to do an asynchronous HTTP request to get a new token from your server and then updating the instance of client with it.
Hope that helps.
Another Twilio evangelist here!
You can actually listen for the offline event on the Twilio.Device object. From the documentation:
.offline( handler(device) )
Register a handler function to be called when the offline event is
fired. This is triggered when the connection to Twilio drops or the
device's capability token is invalid/expired. In either of these
scenarios, the device cannot receive incoming connections or make
outgoing connections. If the token expires during an active connection
the offline event handler will be called, but the connection will not
be terminated. In this situation you will have to call
Twilio.Device.setup() with a valid token before attempting or
receiving the next connection.
So you want something like:
Twilio.Device.offline(function(device) {
fetchTokenFromServer(function(token) {
device.setup(token);
});
});
where fetchTokenFromServer makes the HTTP request that Devin suggested in his answer.
Let me know if this helps.
I just ran into this issue so hopefully my solution can help you and others.
I was using twilio.js v1.3 and tried implementing my offline callback like #philnash recommended, but kept getting the error device.setup is not a function. I then tried using Twilio.Device.setup(newToken) and was able to get the capability token refreshed but also ended up getting a new error: Cannot read property 'setToken' of undefined.
I ended up having to use twilio.js v1.4 to make the error go away. My working solution looks like this:
Twilio.Device.offline(function(device) {
$.ajax(urlToGetNewToken, type: 'get').done(function(newToken) {
Twilio.Device.setup(newToken)
})
})

Twilio SDK General error #31000

We use Twilio SDK in our iOS app. It works fine but sometimes didStopListeningForIncomingConnections callback is called with error=31000 ("General error"). After that, the device turns to a strange state: it seems to be online but it's impossible to call it. And it shows "unconnected" state on the device.
So the questions are:
1. What does this 31000 error means?
2. What should we do in such a case? How to reconnect device to Twilio?
Megan from Twilio here.
You can see what an error for Twilio Client means here: https://www.twilio.com/docs/api/client/errors
However, 31000 is a rather vague and less than ideal error message as you describe. In this case, it is likely that the Twilio capability token has probably expired while the application is in the background, and if you merely call the listen method whenever they are receiving the 31000 generic error, it might cause the client SDK to result in a error-retry loop and crash the application eventually.
At the time of your writing with TwilioClient iOS SDK v1.2.5, it is suggested to use the following sample code in your did-stop-listening callback:
- (void)device:(TCDevice*)device didStopListeningForIncomingConnections:(NSError*)error {
if ( [self checkCapabilityTokenStillValid] ) {
// if the token has not yet expired, use the `listen` method of `TCDevice` to resume the listening state
[self.device listen];
}
else {
// restart all over by requesting a new capability token and initialize/update the `TCDevice` instance again
[self login];
}
}
The TwilioClient iOS SDK takes care of dispatching the listen and updateCapabilitiyToken: methods to the current thread for execution, therefore it's safe to call them directly in the didStopListeningForIncomingConnections. The did-stop-listening delegate method is always triggered with dispatch_get_main_queue() of Grand Central Dispatch.
Hope this may help others if they run into the same generic error.
This may or may not be the issue, we have encountered 31000 errors two times in our development and both were a result of generating the JWT on our server api. To be clear the error was a 31000 on the client, but the reason for this was in the construction of the JWT, and the params we wanted twilio to send back to our application.
When passing in an object to allow_client_outgoing or allow_client_incoming the twilio sdk concats this all in their scope attribute in their JWT. It added it to the scope:client:outgoing?appSid= which looks like a query string. That means it has a size limit of 2048. So exceeding this length generates a 31000 error.
In addition adding the objects doesn't seem to always implicitly serialize the object correctly, it introduces characters that can generate errors in their corresponding mobile sdks (but not their web sdk ... weird) so we took care of this by explicitly serializing objects to JSON before they are inserted into the JWT.
I hope both of these examples help you track down the issue.

iOS telprompt - can you get the status of the call?

The app I'm working on makes calls when the user tells it to, using telprompt to come back to the app when the call is over. Is there any way to tell what caused the call to end? If the call failed, I'd like to do one thing, but if it succeeded and the user just hit "END" I want to do something else. I'm not seeing anything in the documentation about it, though.
TIA
Janene

Resources