VoIPGRID / VialerSIPLib

An Objective-c wrapper for PJSIP
GNU General Public License v3.0
133 stars 69 forks source link

IOS 13 voIP restriction #197

Open mudassirzulfiqar opened 5 years ago

mudassirzulfiqar commented 5 years ago

Because of new ios 13 voip restrictions func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) completion should be called with in the same loop for - (void)reportIncomingCall:(VSLCall *)call. Any idea how this new restriction will be implemented with this library.

ismaiI1 commented 5 years ago

@mudassirzulfiqar Did you get VoIP push notification in background? I couldn't.. When app in foreground didReceiveIncomingPushWith is called, but in background it's not called..

mudassirzulfiqar commented 5 years ago

@invisible66 Right after posting this, I also find this weird thing that didReceiveIncomingPushWith is not called when the app is is background. But I think I figured this out why, but let me investigate this more.

Florianlec commented 5 years ago

@mudassirzulfiqar Same behavior for me here, for some reasons I do receive calls in foreground and didReceiveIncomingPushWith is getting called, but not in background. I'm also on it.

Florianlec commented 5 years ago

Interesting post from Apple staff about that : https://forums.developer.apple.com/thread/117939

mudassirzulfiqar commented 5 years ago

I have figured out the issue, as it is stated in the official forums by Apple that not calling completion will result ban your application after 3 to 5 attempts I guess. So I think when the app get banned in 2 to 3 attempts then it stops receiving voip.

Use case: I reinstalled my application and put my application into the background and didReceiveIncomingPushWith gets called. But because i'm not using completion closure on the right time, probably again Im not going to receive voip next time. And this always work fine when app is in foreground.

ismaiI1 commented 5 years ago

Interesting post from Apple staff about that : https://forums.developer.apple.com/thread/117939

I didn't understand anything from this post..

ismaiI1 commented 5 years ago

I have figured out the issue, as it is stated in the official forums by Apple that not calling completion will result ban your application after 3 to 5 attempts I guess. So I think when the app get banned in 2 to 3 attempts then it stops receiving voip.

Use case: I reinstalled my application and put my application into the background and didReceiveIncomingPushWith gets called. But because i'm not using completion closure on the right time, probably again Im not going to receive voip next time. And this always work fine when app is in foreground.

Perfect. Thank you, you save my day :) This means, we have to call reportNewIncomingCallWithUUID in didReceiveIncomingPushWith.

Florianlec commented 5 years ago

@invisible66 that sounds good indeed, but what if the account is not registered to SIP ?

ismaiI1 commented 5 years ago

so, we have to end call using reportCallWithUUID:endedAtDate:reason: as Apple staff says.

mudassirzulfiqar commented 5 years ago

@invisible66 that sounds good indeed, but what if the account is not registered to SIP ?

Im also stuck on achieving this behaviour, in our application, we always push new account information in payload to register the sip calls, and obviously for this we have to call so many library methods. So Im currently unable to call this completion() closure.

I checked multiple apps like Slack, Skype, Messenger. They all are using old way to initiating the sip calls using notification technique. Only WhatsApp is managing this callkit thing, but I also faced some issues on receiving whatsapp call from my friend. (Did some testing.)

pshitikov commented 5 years ago

This problem is relevant to me. Any suggestions on how to resolve this issue?

ismaiI1 commented 5 years ago

This problem is relevant to me. Any suggestions on how to resolve this issue?

I am looking for any solution.. If you find something, can you share it with us please? :)

mudassirzulfiqar commented 5 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

ismaiI1 commented 5 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

We post call to Callkit in didReceiveIncomingPushWith. After registration, we update call information in reportNewIncomingCall's completion. you have to set call's UUID before call information update.

This is a bad solution, but it's better than clicking notification and opening the app.

mudassirzulfiqar commented 5 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

We post call to Callkit in didReceiveIncomingPushWith. After registration, we update call information in reportNewIncomingCall's completion. you have to set call's UUID before call information update.

This is a bad solution, but it's better than clicking notification and opening the app.

My question is how can you post a call without even registering the sip account, and without even receiving the call? What information do you send in the voip? Can you please share thanks

ismaiI1 commented 5 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

We post call to Callkit in didReceiveIncomingPushWith. After registration, we update call information in reportNewIncomingCall's completion. you have to set call's UUID before call information update. This is a bad solution, but it's better than clicking notification and opening the app.

My question is how can you post a call without even registering the sip account, and without even receiving the call? What information do you send in the voip? Can you please share thanks

I did as described on this page. https://developer.apple.com/documentation/pushkit/responding_to_voip_notifications_from_pushkit?language=objc

www0488 commented 5 years ago

I have figured out the issue, as it is stated in the official forums by Apple that not calling completion will result ban your application after 3 to 5 attempts I guess. So I think when the app get banned in 2 to 3 attempts then it stops receiving voip.

Use case: I reinstalled my application and put my application into the background and didReceiveIncomingPushWith gets called. But because i'm not using completion closure on the right time, probably again Im not going to receive voip next time. And this always work fine when app is in foreground.

I tested to reinstall the app, but I still cannot get any response from the "didReceiveRemoteNotification" method and this drives me crazy.

I even tried to restart the device but it does not work.

Is there anyone who have the same issue and know how to solve it?

muhammadalkhalaf commented 4 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

We post call to Callkit in didReceiveIncomingPushWith. After registration, we update call information in reportNewIncomingCall's completion. you have to set call's UUID before call information update.

This is a bad solution, but it's better than clicking notification and opening the app.

Can you explain this solution please ?

ismaiI1 commented 4 years ago

We have reverted back to old implementation, which is clicking the notification and opening the app.

We post call to Callkit in didReceiveIncomingPushWith. After registration, we update call information in reportNewIncomingCall's completion. you have to set call's UUID before call information update. This is a bad solution, but it's better than clicking notification and opening the app.

Can you explain this solution please ?

I hope, you can understand my bad English :)

Muhammad-AhmadRafique commented 4 years ago

Hi All, Can anyone help me out to resolve this iOS 13 weird thing with this library. ? When I receive Voip push, I open a dummy CallKit UI, and when actual call come, I call this function:- let reason = CXCallEndedReason.init(rawValue: CXCallEndedReason.failed.rawValue) provider.reportCall(with: uuid, endedAt: nil, reason: reason!)

and it tears down the dummy CallKit UI, but it show very bad behaviour of the UI, as WhatsApp and other apps don't show this behaviour.

Any suggestion how to resolve this issue. I am stuck at this point for almost 3 weeks, somebody please help me.

Thanks,

mudassirzulfiqar commented 4 years ago

@Muhammad-AhmadRafique Send call information in voip to iOS app. But due to iOS 13 you need to immediately present incoming call UI to the screen. Otherwise your AppDelegate will get crashed. While you prompt the callerId information for example in your voip payload you send useful data like “caller id , caller name”. You register the PJSIP using this vialer library. And after registering user account you can immediately update the call manager with the ongoing call.

Please read below links for solutions:

https://forums.developer.apple.com/thread/117939 https://github.com/VoIPGRID/VialerSIPLib/issues/207#issuecomment-593379174

Muhammad-AhmadRafique commented 4 years ago

@mudassirzulfiqar thanks for the reply. But basically the issue is this, voip comes first and a fake call UI opens, and after that, actual call comes and another UI opens, which comes from CallkitProviderdelegate -> reportIncomingCall.

How can I handle both of the screens simultaneously, Currently when actual call comes, I ended the dummy call UI forcefully, but this is not a good approach.

I have also read the above thread, but with this library, I don't know how to update that dummy UI when push comes? please help me to resolve this.

Thanks again for your help.

Regards, Mohammad Ahmad

mudassirzulfiqar commented 4 years ago

@Muhammad-AhmadRafique This library totally supports this new ios 13 voip limitation. The links which I shared above has the complete knowledge about handling this scenario, Why you are opening two UI?

below is the code you are looking for: https://github.com/VoIPGRID/VialerSIPLib/issues/207#issuecomment-593379174

Muhammad-AhmadRafique commented 4 years ago

@mudassirzulfiqar Thanks again for your help. I have updated my code when voip push received, as per the link. But one more thing I want to ask, when actual call comes through asterisk, do I need to update my appDelegate.reportIncomingCall() method in CallkitProviderDelegate.m file ? And if it must be updated, then what code should I write in that method. ?

or otherwise, it will work fine , I have to only change in voip push method, which you suggested earlier ?

Regards,

mudassirzulfiqar commented 4 years ago

I did not understand the question, but let me tell you the flow

This is described above in the link as well.

I did not understand this

when actual call comes through asterisk, do I need to update my appDelegate.reportIncomingCall() method in CallkitProviderDelegate.m file ?

Muhammad-AhmadRafique commented 4 years ago

ok, let me tell you the flow of my app, maybe you understand in a better way and guide me what I am doing wrong.

In my app, I am doing following steps, and it was working fine unless iOS 13:- STEP 1 First user calls a rest api, which sends voip pushes to other iPhone device and other user uses this voip push method body to only register to Sip server, STEP 2 This rest api keeps on checking either other user is connected to Sip or not, if it is not connected, it keeps on sending push after every 4 second if the other user does not connect to the Sip server within these 4 seconds. STEP 3 if after 4 seconds, other user becomes online, then this api returns response to the first user that other user becomes online, STEP 4 And then first user makes a call through asterisk server to other user.

The following steps were working fine, till iOS 12.

But for iOS 13, what limitations I am facing right now:- For STEP 1 I must have to open a fake dummy UI when voip push receives which was not the case previously. For STEP 2 If other user does not connect to sip client for any network problem in 4 seconds, another push comes and another call UI opens (as per iOS limitation, we have to open dummy Call UI for each voip push received) For STEP 4 now first user gets response that other user becomes online and it calls other user through asterisk server,

So in other user iPhone device, 1 or more Call UIs open already due to voip pushes and now actual call UI opens , so there are multiple UIs are open in other user's device.

Thats why I am asking you what am I doing wrong. ? please guide me.

Now I am asking you following question ?

I am stucked at this, please help me. If you need any assistance regarding my above flow, please tell me, I will explain in more detail.

Once again thank you so much for your cooperation and help.

Kind Regards, Ahmad

mudassirzulfiqar commented 4 years ago

Your first four steps which you described does not seem to me the proper implementation, The voip notifications were meant to be for Incoming Calls only. Because of this abusive behaviour which you also described that it pings the device after some interval, Apple now forcefully want you to show the UI.

It is not only you who suffered from all these thing, many big voip applications had forcefully changed their backend implementation along with the front-end

If you read the some other third party voip call providers for example Twilio. You will find out that they also had to adopt the new ios 13 behaviour and their sample ios application for voip does the same flow which Im describing to you.

About your second four steps, you have to change the whole implementation to adopt this ios 13 thing. Im not very expert in backend but still I see that your approach for pinging a device is not correct. Which makes you open multiple UI, its totally not a valid approach. No one does that.

There is no need to keep checking the device by sending voip notifications, I think you can play with asterisk and query the connection from backend for receiving client rather then the client applications. You should not care about is the device connected or not it the backend thing. How can one person be offline?, if logically the client device is offline then dont send voip. And with this new implementation the ios code has to show the UI, so there is no case when the person is offline.

Should asterisk server itself call voip push script ? because for now, I am calling rest api to do it. ( is it good approach to call rest api to send voip push ) ? I think rest api is okay for that, you can hit the api and present outgoing call screen, meanwhile the receiver will receive the sip information and register itself or try to make connection.

Muhammad-AhmadRafique commented 4 years ago

Thanks for the response, Yes, I have heard about many apps related to VOIP calling, and these apps already changed their implementation for iOS 13.

You asked when an iPhone device is offline to asterisk. ?

For this :- I think you can play with asterisk and query the connection from backend for receiving client rather then the client applications.

For this:- You should not care about is the device connected or not it the backend thing You mean, asterisk server must know that device is connected or not ? if device is connected, so make calls directly or otherwise send voip push to connect first and then make calls ?

mudassirzulfiqar commented 4 years ago

When an app is killed, our asterisk server shows this device becomes offline.

Why do you care if the asterisk server shows device offline? You should not worry about the app is killed, Worry about the endpoint of sip are killed. To solve this you need to write multiple if else to check if sip is connected, if endpoints are connected, if account is already registered, if ...... and execute these statements when there is voip notification.

What do you mean ? I don't understand.

As far as I know you can see the asterisk statuses in the backend.

You mean, asterisk server must know that device is connected or not ? if device is connected, so make calls directly or otherwise send voip push to connect first and then make calls ?

Dont go for multiple solutions, always send the voip, again you have to write a long method with lots of if else to know what to do. For example:

While checking all these statuses, show a call kit UI.

Muhammad-AhmadRafique commented 4 years ago

just connect the call.

How to connect the call ? Calling happens only when other iPhone user make a call, not otherwise.

This is the point, where I am stuck.

Muhammad-AhmadRafique commented 4 years ago

Actual calling happens only when other user make a call through asterisk.

What are you suggesting is that, only voip will do the connection thing and also actual call thing (both must be done through voip),

I don't understand this point. Sorry for not understanding your point.

mudassirzulfiqar commented 4 years ago
Muhammad-AhmadRafique commented 4 years ago

@mudassirzulfiqar let me tell you something. I am only stuck on last point.

(stuck on it)

Because, When first user call the following function, then actual call comes to 2nd user. and first user only call this method, when rest api response comes to the first user.

self.callManager?.startCall(toNumber: self.callingId, for: self.account!, completion: { (call, error) in if let err = error { print(err.localizedDescription) } })

Muhammad-AhmadRafique commented 4 years ago

Without calling startCall:ToNumber function, how actual call comes to 2nd user ?

Because, when voip push received, 2nd user registers to SIP client, and update its callManager with the parameters received from voip push and call reportIncomingCall method, and a CallKit UI opens.

Then first user call this method startCall:ToNumber, and actual call comes to 2nd user, so How can we interlink this actual call with the above one when Voip Push received.

Once again, thanks for your help. Regards,

aabiawan commented 3 years ago

@mudassirzulfiqar kindly make a proper video on it , as it is very important issue rightnow

mudassirzulfiqar commented 3 years ago

@mudassirzulfiqar kindly make a proper video on it , as it is very important issue rightnow

@aabiawan Hi , What exactly you need to know ?

aabiawan commented 3 years ago

Hi, i have implemented agora for calling but thing is when app is in kill stat its not awakening, do i need any api for triggering notifications to other device ? I am using pushkit btw

On Tue, 9 Mar 2021 at 1:21 AM, Mudassir Zulfiqar notifications@github.com wrote:

@mudassirzulfiqar https://github.com/mudassirzulfiqar kindly make a proper video on it , as it is very important issue rightnow

@aabiawan https://github.com/aabiawan Hi , What exactly you need to know ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/VoIPGRID/VialerSIPLib/issues/197#issuecomment-793048372, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALSQVHHZ7MF3U5FMDJFIGC3TCUWS5ANCNFSM4I2Y3ZHQ .

mudassirzulfiqar commented 3 years ago

@aabiawan You need to study Apple VOIP notification

aabiawan commented 3 years ago

just need to know do i need any api for triggering notifications?

On Tue, Mar 9, 2021 at 2:58 AM Mudassir Zulfiqar notifications@github.com wrote:

@aabiawan https://github.com/aabiawan You need to study Apple VOIP notification

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/VoIPGRID/VialerSIPLib/issues/197#issuecomment-793110352, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALSQVHCYYDYVJVULIDOUFJDTCVCADANCNFSM4I2Y3ZHQ .

mudassirzulfiqar commented 3 years ago

@aabiawan There are different ways to implement both incoming calls and dialling.

Official Running application using this framework : https://github.com/VoIPGRID/vialer-ios You can easily see how they are doing it.

This is the middleware repo which handles this voip thingy. https://github.com/VoIPGRID/vialer-middleware