Getting issue on accepting video call from VOIP when app is in terminated state

Getting issue on accepting video call from VOIP notification when app is in terminated state/ Force Quit.
When i accept the call from VOIP notification, the video call is getting failed for the first time,
when i call again its getting accepted.

Hi @Android_MR_Firebase , thanks for the report.
I’m guessing that there might be an error with authenticating the user when the first push notification is received. Can you make sure that the user is authenticated before call.accept() is called? It would also help if you could provide the code snippet where you handle the received push notification.

Thanks :slight_smile:

Hi @mininny

i followed this link

i am calling the call.accept() here :

func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        guard let call = SendBirdCall.getCall(forUUID: action.callUUID),
              SendBirdCall.currentUser != nil else {
            action.fail()
            return
        }
        
        let callOptions = CallOptions(isAudioEnabled: true, isVideoEnabled: call.isVideoCall, useFrontCamera: true)
        let acceptParams = AcceptParams(callOptions: callOptions)
        call.accept(with: acceptParams)
        UIApplication.shared.showCallController(with: call)
        action.fulfill()
    }

Here is the code for handling received VOIP push notification:

import UIKit
import CallKit
import PushKit
import SendBirdCalls


extension AppDelegate: PKPushRegistryDelegate {
    func voipRegistration() {
        self.voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
        self.voipRegistry?.delegate = self
        self.voipRegistry?.desiredPushTypes = [.voIP]
    }
    
    func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
        
        tokenVoip = pushCredentials.token
        UserDefaults.standard.voipPushToken = pushCredentials.token

    }
    
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
        
        SendBirdCall.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type, completionHandler: nil)
    }
    
   
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        SendBirdCall.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type) { uuid in
            guard uuid != nil else {
                let update = CXCallUpdate()
                update.remoteHandle = CXHandle(type: .generic, value: "invalid")
                let randomUUID = UUID()
                
                CXCallManager.shared.reportIncomingCall(with: randomUUID, update: update) { _ in
                    CXCallManager.shared.endCall(for: randomUUID, endedAt: Date(), reason: .acceptFailed)
                }
                completion()
                return
            }
            completion()
        }
    }
}

Here is the didStartRinging function :

func didStartRinging(_ call: DirectCall) {

        call.delegate = self
        
        guard let uuid = call.callUUID else { return }
        guard CXCallManager.shared.shouldProcessCall(for: uuid) else { return }    
      
        print(call.caller)

        let name = call.caller?.nickname ?? "Unknown"

        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .generic, value: name)
        update.hasVideo = call.isVideoCall
        update.localizedCallerName = name
        
        if SendBirdCall.currentUser == nil {

            CXCallManager.shared.reportIncomingCall(with: uuid, update: update) { _ in
 //               CXCallManager.shared.endCall(for: uuid, endedAt: Date(), reason: .acceptFailed)
            }
  //          call.end()
        } 
		else if SendBirdCall.getOngoingCallCount() > 1 {

            CXCallManager.shared.reportIncomingCall(with: uuid, update: update) { _ in

               	CXCallManager.shared.endCall(for: uuid, endedAt: Date(), reason: .declined)

            }
            call.end()
        } 
		else {
            
            CXCallManager.shared.reportIncomingCall(with: uuid, update: update)
        }
    }

Hi @mininny Sharing another video of issue, when app is forced quit or terminated, and device is locked.

Hi @mininny
Any update on this will be appreciated.
The project is held up and we cant go live with this issue coming up.

Hi @Android_MR_Firebase, sorry for the delayed response. It seems like you are not authenticating the user before calling DirectCall.accept(). Can you please refer to the following code? quickstart-calls-directcall-ios/CXCallManager.swift at 650d93bd6e5cdf73c63ea7e3c2412c2734d4635d · sendbird/quickstart-calls-directcall-ios · GitHub

What you should do is call SendBirdCall.authenticate in provider(_ provider: CXProvider, perform action: CXAnswerCallAction) before calling call.accept(with: AcceptParams)

Please let me know if this resolves your issue after trying this. :slight_smile:

Hi @mininny

i tried the above, but still its not working,

the authenticateIfneeded is not available in the version of SendBird i am using (installed via Cocoapods),
now, i am authenticating the user as shared in code snippet, Please let me know if i am doing it right, or i have to use the SendBirdCall.currentUser!.userId at the place of userId in AuthenticateParams as

let authenticateParams = AuthenticateParams(userId: SendBirdCall.currentUser!.userId)

func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        guard let call = SendBirdCall.getCall(forUUID: action.callUUID),
              SendBirdCall.currentUser != nil else {
            action.fail()
            return
        }

        let userId = self.appDelegate.dictInfo["idToAuth"]
        
        let authenticateParams = AuthenticateParams(userId: userId)
        SendBirdCall.authenticate(with: authenticateParams) { (user, error) in
            guard let user = user, error == nil else { return }

            print("Successfully Authenticated: \(user.userId)")
        }
        
        let callOptions = CallOptions(isAudioEnabled: true, isVideoEnabled: call.isVideoCall, useFrontCamera: true)
        let acceptParams = AcceptParams(callOptions: callOptions)
        call.accept(with: acceptParams)
        UIApplication.shared.showCallController(with: call)
        action.fulfill()
    }