phpswiftvoipcallkit

CXAnswerCallAction not running after answering call


I have implemented VOIP calls in my application and I am trying to show a screen when the user answers a call.

VoipNotificationManager.swift

// Handle incoming pushes
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    let callManager = CallManager()
    let id = UUID()

    callManager.reportIncomingCall(id: id, handle: "Assistant")
}

CallManager.swift

// MARK: Incoming calls
func reportIncomingCall(id: UUID, handle: String) {
    let update          = CXCallUpdate()
    update.remoteHandle = CXHandle(type: .generic, value: handle)
    update.hasVideo     = true
    
    provider.reportNewIncomingCall(with: id, update: update) { error in
        if let error = error?.localizedDescription {
            print("Report incoming call error: \(error)")
        } else {
            print("Call reported")
        }
    }
}


// Runs the user answers a call
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
    print("Call answered")
    
    action.fulfill()

    // Show view
}

When I run the PHP script (check last code snippet for the PHP code), I receive a call but when I answer the call, the CXAnswerCallAction function doesn't run.

But the CXAnswerCallAction function runs when I run the app and click on a button which replicates an incoming call like so (this method doesn't involve a PHP script):

// Call button
Button {
    let callManager = CallManager()
    let id = UUID()
    callManager.reportIncomingCall(id: id, handle: "Assistant")
            
} label: {
    Text("Call")
}

Also, here's the PHP code I run to receive a call:

if ( defined("CURL_VERSION_HTTP2") && (curl_version()["features"] & CURL_VERSION_HTTP2) !== 0) {
    $ch = curl_init();
    $body ['aps'] = array (
                           "alert" => array (
                                             "status" => 1,
                                             "title"  => "Assistant",
                                             "body"   => "Incoming Video Call",
                                             ),
                           "badge" => 1,
                           "sound"  => "default",
                           "voip" => true
                           );
    $curlconfig = array(
                        CURLOPT_URL => "https://api.development.push.apple.com/3/device/token",
                        CURLOPT_RETURNTRANSFER =>true,
                        CURLOPT_POSTFIELDS => json_encode($body),
                        CURLOPT_SSLCERT =>"App.pem",
                        CURLOPT_SSLCERTPASSWD => "Pass",
                        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
                        CURLOPT_VERBOSE => true
                        );
    curl_setopt_array($ch, $curlconfig);
    $res = curl_exec($ch);
    if ($res === FALSE) {
        echo('Curl failed: ' . curl_error($ch));
    }
    curl_close($ch);
} else {
    echo "No HTTP/2 support on client.";
}

I don't think there are any issues with the script as it runs with no issue and when I run it, the device receives a call.


Solution

  • Looks like your CallManager will be getting released as soon as pushRegistry returns (since it's initialised as a local variable inside pushRegistry) so by the time the call is answered there will be no CXProviderDelegate.

    You should initialise one instance of CallManager early in your app lifecycle and use this instance throughout the app.

    For example, you might make CallManager a singleton and use CallManager.shared in your VoipNotificationManager.swift and elsewhere:

    class CallManager: CXProviderDelegate {
        
        static let shared = CallManager()
    
        // private init to prevent other instances
        private init() {
            // probably create CXProvider and set CXProviderDelegate here
        } 
    
        ...