Trigger an incoming VoIP call using CallKit and Twilio-Video API

4k views Asked by At

By using one of the sample video calling app provided by Twilio (VideoCallKitQuickStart), I am trying to trigger an incoming call by sending a VoIP notification to the App. But the App doesn't trigger an incoming call. I also tried keeping the App opened while sending a VoIP notification and the App crashes, by throwing the below exception

NSInvalidArgumentException: Attempt to insert non-property list object 'PKPushPayload: 0x16e44af0' for key payload

Could someone, please help me or point me in the right direction on how to trigger an incoming call in the App, when a VoIP notification is received.

Below is my code in the ViewController.swift file

 func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
        // Process the received push

        self.reportIncomingCall(uuid: UUID(), roomName: "testRoom", completion: nil)
    } 

func reportIncomingCall(uuid: UUID, roomName: String?, completion: ((NSError?) -> Void)? = nil) {

    let callHandle = CXHandle(type: .generic, value: roomName ?? "")
    let callUpdate = CXCallUpdate()
    callUpdate.remoteHandle = callHandle
    callUpdate.supportsDTMF = false
    callUpdate.supportsHolding = true
    callUpdate.supportsGrouping = false
    callUpdate.supportsUngrouping = false
    callUpdate.hasVideo = true

    callKitProvider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in
        if error == nil {
            NSLog("Incoming call successfully reported.")
        } else {
            NSLog("Failed to report incoming call successfully: \(error?.localizedDescription).")
        }
        completion?(error as? NSError)
    }
}
3

There are 3 answers

10
philnash On

Twilio developer evangelist here.

I'm not particularly good with iOS, but taking a quick look at the documentation for the PKPushRegistryDelegate it looks like your pushRegistry function definition isn't right.

It should be

func pushRegistry(_ registry: PKPushRegistry, 
    didReceiveIncomingPushWith payload: PKPushPayload, 
    forType type: PKPushType)

That is, didReceiveIncomingPushWith rather than didReceiveIncomingPushWithPayload.

Alternatively, does it have anything to do with the fact that you're casting forType to String?

1
iDeveloper On

Posting late answer but it may helpful for someone.

Following code I did to handle voice incoming call.

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
    NSLog("pushRegistry:didReceiveIncomingPushWithPayload:forType:")
    print(payload)
    if (type == PKPushType.voIP) {
        TwilioVoice.handleNotification(payload.dictionaryPayload, delegate: self)

        pushKitPushReceivedWithPayload(payload: payload)
    }
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    NSLog("pushRegistry:didReceiveIncomingPushWithPayload:forType:completion:")

    if (type == PKPushType.voIP) {
        TwilioVoice.handleNotification(payload.dictionaryPayload, delegate: self)

        pushKitPushReceivedWithPayload(payload: payload)
    }

    completion()
}

func pushKitPushReceivedWithPayload(payload: PKPushPayload){
    if UIApplication.shared.applicationState != .active{
        let msgType = payload.dictionaryPayload["twi_message_type"] as? String
        if let messageType = msgType{
            if messageType == "twilio.voice.call"{
                fireLocalNotificationForVoiceCall(didStart: true)
            }else if messageType == "twilio.voice.cancel"{
                fireLocalNotificationForVoiceCall(didStart: false)
            }
        }
    }
}

Below are the delegate methods of call kit I have added

extension AppDelegate : TVONotificationDelegate, TVOCallDelegate
{
  func callInviteReceived(_ callInvite: TVOCallInvite) 
  {
   if (callInvite.state == .pending) 
   {
        //code
   } 
   else if (callInvite.state == .canceled) 
   {
        //code
   }
  }
  func handleCallInviteReceived(_ callInvite: TVOCallInvite) 
  {
        //code
  }

  func handleCallInviteCanceled(_ callInvite: TVOCallInvite) 
  {
        //code
  }
}

I have followed this tutorial provided by twilio - https://github.com/twilio/voice-quickstart-swift

Go through this tutorial and it will work.

0
krish On

Swift 3.0

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
    NSLog("pushRegistry:didReceiveIncomingPushWithPayload:forType:")

    if (type == PKPushType.voIP) {
        print(payload.dictionaryPayload)
        VoiceClient.sharedInstance().handleNotification(payload.dictionaryPayload, delegate: self)
    }
}

And please don't make any changes in payload without modifying it in order for the SDK to extract the incoming call info out of the payload so that the SDK can notify the application with incoming calls