Opened 8 years ago

Closed 7 years ago

Last modified 3 years ago

#1941 closed enhancement (fixed)

Review iOS 10 integration to PJSIP

Reported by: nanang Owned by: bennylp
Priority: normal Milestone: release-2.6
Component: common Version: trunk
Keywords: Cc:
Backport to 1.x milestone: Backported: no

Description (last modified by nanang)

iOS 10 is coming with new features such as CallKit, framework changes such as in AVFoundation, and also API deprecations. This ticket will review and apply any integrations needed in PJSIP library.

PushKit guide

What your application needs to do:

  1. Set up PushKit according to Apple's doc.
  2. Upon startup, request for push tokens.
  3. Send REGISTER to SIP server with the push token info, the info may be added as a specific header, Contact header params, or Contact URI params, to tell the SIP server about the PN (Push Notification) info (server URI, tokens, etc). You can use pjsua_acc_config.reg_hdr_list, pjsua_acc_config.contact_uri_params, or pjsua_acc_config.reg_contact_params (the later is available in ticket #1965).
    Note: RFC 8599: Push Notifications in the Session Initiation Protocol (SIP) suggests to put it in Contact URI params, for example:
    Contact: <sip:alice@alicemobile.example.com;
         pn-type=acme;pn-methods="INVITE";
         pn-uri="https://pn.acme.example.com/ZTY4ZDJlMzODE1NmUgKi0K">
    
  4. After a successful registration, SIP client can go background and will be woken up by the OS upon receiving push notification.

Note: starting from iOS 13, there's a new requirement:
Apps receving VoIP pushes must post an incoming call (via CallKit or IncomingCallNotifications) in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.'
In order to make it work with the normal SIP flow which may require you to wait for some time to receive the INVITE message, please look at Apple's recommendation in its developer forum.

Configure your SIP server:

  1. Parse the PN info in registration.
  2. Upon receiving an incoming SIP INVITE, SIP server should contact PN server as specified via PN URI and tokens.
  3. After some interval (assuming the SIP client has been woken up), it then can send/forward the SIP INVITE message to the SIP client.

CallKit support

CallKit framework allows apps to use the native phone UI to receive incoming calls and make outgoing calls. In order to achieve this, CallKit requires the call audio to start only when audio session has been activated, thus it's recommended that when using PJSIP, you open the sound device only when necessary. It can be done by:

  1. Starting PJSIP with no sound device (by calling pjsua_set_no_snd_dev() after startup).
  2. Close the sound device when unused, also with the same API (pjsua_set_no_snd_dev()).
  3. Upon audio session activation, open the sound device with the API pjsua_set_snd_dev().

Below is an example on how to integrate CallKit with PJSIP, with the delegate functions taken from Speakerbox sample app provided by Apple.

To make outgoing call:

    func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
        /* 1. We must not start call audio here, and can only do so
         *    once the audio session has been activated by the system
         *    after having its priority elevated. So, make sure that the sound
         *    device is closed at this point.
         */

        /* 2. Provide your own implementation to configure
         *    the audio session here.
         */
        configureAudioSession()

        /* 3. Make call with pjsua_call_make_call().
         *    Then use pjsua's on_call_state() callback to report significant
         *    events in the call's lifecycle, by calling iOS API
         *    CXProvider.reportOutgoingCall(with: startedConnectingAt:) and
         *    CXProvider.reportOutgoingCall(with: ConnectedAt:)
         */
         
        /* 4. If step (3) above returns PJ_SUCCESS, call action.fulfill(),
         *    otherwise call action.fail().
         */
    }

To handle incoming call:

    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        /* 1. We must not start call audio here, and can only do so
         *    once the audio session has been activated by the system
         *    after having its priority elevated. So, make sure that the sound
         *    device is closed at this point.
         */

        /* 2. Provide your own implementation to configure
         *    the audio session here.
         */
        configureAudioSession()

        /* 3. Answer the call with pjsua_call_answer().
         */

        /* 4. If step (3) above returns PJ_SUCCESS, call action.fulfill(),
         *    otherwise call action.fail().
         */
    }

To start sound device:

    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
        /* Start call audio media, now that the audio session has been
         * activated after having its priority boosted.
         *
         * Call pjsua API pjsua_set_snd_dev() here.
         */
    }

API/Symbol Deprecations

  1. "kCFStreamNetworkServiceTypeVoIP is deprecated (first deprecated in iOS 9.0 - use PushKit for VoIP control purposes."
    See the PushKit guide above.
    If you want to disable the use of kCFStreamNetworkServiceTypeVoIP, set PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT to 0.
  1. AVFoundation API deprecation:
    "warning: 'devices' is deprecated: first deprecated in iOS 10.0 - Use AVCaptureDeviceDiscoverySession instead."
    Done in r5454.

Reference:

Change History (9)

comment:1 Changed 7 years ago by ming

In 5453:

Re #1941: Add support to specify min iOS versions in configure-iphone and update the default for ipjsua sample app

comment:2 Changed 7 years ago by ming

In 5454:

Re #1941: Support for AVCaptureDeviceDiscoverySession to replace the deprecated [AVCaptureDevice devices] in iOS 10.

comment:3 Changed 7 years ago by ming

  • Description modified (diff)

comment:4 Changed 7 years ago by ming

  • Description modified (diff)

comment:5 Changed 7 years ago by ming

  • Description modified (diff)

comment:6 Changed 7 years ago by ming

  • Resolution set to fixed
  • Status changed from new to closed

In 5463:

Fixed #1941: Disable the setup of audio session in coreaudio_dev. This will allow application to have better control towards its audio session management, which will help to ensure a smoother integration with CallKit? features.

comment:7 Changed 7 years ago by ming

In 5498:

Re #1941: re #5454, modify declaration of NSArray to support older compiler version

Should be r5454.

Last edited 7 years ago by ming (previous) (diff)

comment:8 Changed 4 years ago by ming

  • Description modified (diff)
  • Update the RFC number
  • Add iOS 13 requirement.
Last edited 4 years ago by ming (previous) (diff)

comment:9 Changed 3 years ago by nanang

  • Description modified (diff)
Note: See TracTickets for help on using tickets.