One-Way Speech Path After Hold/Resume VoIP Call Through CallKit - ios

We've been able to establish a VoIP call using CallKit. However, Hold and Resume operation on this established VoIP call causes one-way speech path issue. I'm able to hear far-end after I hold and resume. Far-end is not able to hear me.
I've already taken Wireshark traces and confirmed that after the resume, there is only one-way audio. Audio is not sent from my device to far-end.
Since Wireshark already showed the problem, I checked WebRTC code for media session errors. I see no errors in startSend or startPlayout (audio unit processing for send and receive)
I re-checked by CallKit integration code to confirm correct sequences
HOLD OPERATION
Press HOLD button on App UI or long-press MUTE button on CallKit UI.
App requests CXSetHeldCallAction transaction to CallKit with onHold as YES.
App receives provider delegate call back performSetHeldCallAction.
App puts the call on hold and then fulfils performSetHeldCallAction.
App receives provider delegate call back didDeactivateAudioSession.
RESUME OPERATION
Press RESUME button on App UI or HELD button on CallKit UI.
App requests CXSetHeldCallAction transaction to CallKit with onHold as NO.
App receives provider delegate call back performSetHeldCallAction.
App configures audio session (AVAudioSessionCategoryPlayAndRecord, AVAudioSessionModeVoiceChat, preferredSampleRate:44100) and then fulfils performSetHeldCallAction but remembers the call to be taken off-hold.
App receives provider delegate call back didActivateAudioSession. Using this App takes the call off-hold (resumes the call). The call is the one that was stored in the above step.
We've already raised an Apple Ticket using bugreport (with no update) and are pursuing raising an Apple Technical Support Incident (Apple TSI).
Hoping for some valuable inputs.

Related

How to implement callkit with connectycube on cordova ios application

Dear Connectycube Team,
I hope this email finds you well.
Our company has integrated Connectycube into our application, which primarily relies on video calling for communication between users and service providers. To ensure a seamless user experience, it's imperative that the video calling system is robust and reliable.
Unfortunately, our development team is facing challenges in making the system highly robust and 100% reliable. The issue lies in the connection dropping when the application is killed or the phone is locked.
issue: We are trying to integrate connecticube onto cordova app. We are using callkit to implement native incoming screen. The issue is that whenever the app is killed or the phone's screen is locked, accepting the call on callkit leads to failure since the accept call function gets called before the connecticube oncall event listener is called.
I would like to request a call with your technical team to discuss this matter and receive any insights or recommendations that could improve the video calling system.
Thank you for your assistance.
Best regards,
Kanhu
Once we receive incoming call using callkit and the user accepts the call, we try to send the accept call command to connectycube. But since the oncall event is not fired immediately, we create a callback loop to wait for the oncall event to get fired. This works sometimes but fails most of the time. Is there any other way ro achieve the accept call functionalities using callkit and connectycube on cordova.

PushKit notification arriving after call has ended

I have an application that implements PushKit and CallKit. The scenario in which the problem occurs is as follow:
Device A initiates a call, sending a PushKit notification to Device B.
Device B has no internet connection, and therefore does not receive the call.
Device A ends the call.
Device B connects to the internet after some time.
Device B receives the PushKit notification that Device A sent earlier and displays CallKit Incoming Call UI.
As you can see, Device B will display CallKit Incoming Call UI even after Device A ended the call.
How to prevent Device B from receiving the incoming call?
Thanks
You should send the end-call signal through a PushKit notification so that, as soon as device B reconnects, it will receive both the start-call and end-call notifications.
In iOS 13 you must report an incoming call before you leave the PushKit completion handler, otherwise your app will be blocked from receiving further PushKit pushes. Obviously, this is a slight problem when you have a case such as you described where the call no longer exists.
This scenario, and others, were discussed in an Apple Developer Forums thread
The specific advice for your case is:
While you must report an incoming call immediately, you are still free to decide the call has failed and tell the system later, asynchronously. To do this, call reportCallWithUUID:endedAtDate:reason:. This will tear down the incoming call UI even if the user has not answered the call.
If the user is particularly fast at tapping the accept call button, or if the network conditions are poor or there is otherwise a lot of latency, then you should simply wait until the necessary handshakes are complete before calling fulfill on the CXAnswerCallAction. To the user, it simply appears that the call is taking some time to connect, which is a common experience even with standard phone calls.
Note that the system takes a few seconds for the incoming call UI to animate in, during which the app has the opportunity to complete this handshake, so this will only have a user-visible impact if it takes a significant time for the handshake to complete.
So, what you need to do is report the call, then when you determine that the call is no longer valid (which shouldn't take long at all), immediately end the call.

How to close Callkit UI when call is not connected

I'm using Twilio Programmable Voice SDK. I'm facing an issue where call doesn't connect but CallKit UI starts. When I send app into background I can see the CAllKit UI running with green notification bar at the top.
There seems to be some issue with Twilio which twilio support hasn't been able to figure out and can't provide a solution.
As a workaround I want to close CallKit UI after a time interval when call doesn't connect.
I know how to kill CallKit UI when a call is connected but this doesn't apply in my case as call isn't connected at all.
My question is how do I kill CallKit UI when call isn't connected?
My issue is exactly similar to what is reported here How to close call kit when call doesn't connect but call kit ui is running in the background
Please read it again.
Call is not connected but CallKit UI is started and I want to close it. Note that when a call is not connected you will not get uuid hence you can't call disconnect.
Looking at the ViewController code, it seems like the UUID should be stored in one of this two members:
var callInvite: TVOCallInvite?
var call: TVOCall?
In the case of an incoming call that has not been already answered the UUID is contained in callInvite, otherwise (i.e. outgoing call or answered incoming call) in the call object.

How do I know that an audio interruption ended without receiving AVAudioSessionInterruptionTypeEnded?

I'm using AVAudioSession in my VOIP app (using also CallKit).
I understand that the session can get interrupted by a number of things, for example by a second incoming call.
Apple states towards the bottom of this page:
https://developer.apple.com/library/content/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/HandlingAudioInterruptions/HandlingAudioInterruptions.html#//apple_ref/doc/uid/TP40007875-CH4-SW5
"Note: There is no guarantee that a begin interruption will have a
corresponding end interruption. Your app needs to be aware of a switch
to a foreground running state or the user pressing a Play button. In
either case, determine whether your app should reactivate its audio
session."
On the mentioned page there is an example for a special case, when the user ignores the incoming call and in that case AVAudioSessionInterruptionTypeEnded is being sent.
But what should I do to know when the interruption has ended in every other case (in which cases I will never receive an AVAudioSessionInterruptionTypeEnded)? (E.g. When the user answers the 2nd call and puts me on hold and later he ends the 2nd call?)
Thanks!
I remember when you use CallKit, no app using audio like music will interrupt your app except for those other voip apps or native calls.
In that case, your call will be ended/held according to your response on the call kit ui (If your call do not support held, you will not be shown a thid button accept&hold)----Then, you can get your callback from CallKit delegate methods.
The Interruption api just works when CallKit is not used and CallKit app have a higher priority on audio session than those not using it.

How to resume (or launch) my app after a phone call ends in iOS (my app did *not* initiate the phone call)?

I have seen several ways to "make sure that my app is shown again after a phone call which my app has initiated has ended" however that isn't what I want -> what I am looking for is a way to, say my app is currently running in the background doing network communications and someone calls me, I would like my app to either be able to "detect when the phone call has ended and resume my network communications" and/or "launch/resume my app back into the foreground when the phone call has ended". Is there any way to accomplish something like this and how?
This is unsupported within iOS.
From the docs:
http://developer.apple.com/iphone/library/documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html
http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Reference/CTCallCenter/Reference/Reference.html#//apple_ref/doc/uid/TP40009604
If your application is active when a call event takes place, the system dispatches the event to your handler immediately. However, call events can also take place while your application is suspended. While it is suspended, your application does not receive call events. When your application resumes the active state, it receives a single call event for each call that changed state—no matter how many state changes the call experienced while your application was suspended. The single call event sent to your handler, upon your application returning to the active state, describes the call’s state at that time.
The best you can do is detect phone calls while your app is open.
applicationWillResignActive is called when the app is about move from active to inactive state. So if you get a call, this method is called before your app is backgrounded.
Use this method to pause any ongoing tasks and save any settings you need.
applicationDidBecomeActive is called when you app becomes active again.
Use this method to resume any tasks that were suspended. Example would be resuming your network communications

Resources