Getting Started with iOS libSoftphone

This section describes the steps to create an iOS application that can place and receive calls using libSoftphone SDK.

Adding SoftphoneSwift Dependency

To add a package dependency to the Xcode project:

  1. Open your Xcode project.

  2. Select the Package Dependencies tab.

  3. Select the + button.

  4. In the Enter Package URL field, add the URL of the libSoftphone Swift package

  5. Select the Add Package button.

After adding the dependency, Xcode automatically includes the Softphone dependencies.

Initializing the SDK

Use the initialize method to initialize SoftphoneBridge. This method takes XML string as a parameter. This string represents an XML structure containing the license key and the configuration of the SDK.

 1let license = """
 2    <root>
 3        <saas>
 4            <identifier>your license key</identifier>
 5        </saas>
 6    </root>
 7    """
 9// This method is used for initializing an instance of SDK


Replace your license key between the <identifier> XML tags with a valid license key obtained in the Acrobits licensing portal. This key is required for initializing the SDK. See step 1 in the Quick Start Guide.

Reporting Application States

libSoftphone SDK must have accurate information about the current state of the application to handle SIP registration, push calls, and overall SDK functionality properly. To report the application state changes to the SDK, call the update method of the SoftphoneBridge.instance().state() instance. This method takes the InstanceStateType enum as a parameter. This enum contains all possible application states.

The following code snippet illustrates the functions that handle different application state transitions using the update method:

 1func applicationDidBecomeActive(_ application: UIApplication) {
 2    let bg = UIApplication.shared.applicationState == .background
 3    SoftphoneBridge.instance().state().update(bg ? InstanceState_Background : InstanceState_Active)
 6func applicationWillResignActive(_ application: UIApplication) {
 7    SoftphoneBridge.instance().state().update(InstanceState_Inactive)
10func applicationDidEnterBackground(_ application: UIApplication) {
11    SoftphoneBridge.instance().state().update(InstanceState_Background)
14func applicationWillEnterForeground(_ application: UIApplication) {
15    SoftphoneBridge.instance().state().update(InstanceState_Active)

Managing SIP Account

Set up a SIP account before you can place calls. SIP accounts are specified in XML format.

To view all the recognized XML nodes and values that can be used to configure SIP accounts, go to the Account XML documentation at

Creating a SIP Account

There are two ways to create a SIP account:

  • Include the following code to create an account with a basic configuration containing the username, password, and host:

     1let xml = XmlTree(name: "account")
     2xml?.setAttribute(name: "id", value: "sip")
     3xml?.setNodeValue(value: "Sip Account", name: "title")
     4xml?.setNodeValue(value: "1125", name: "username")
     5xml?.setNodeValue(value: "misscom", name: "password")
     6xml?.setNodeValue(value: "", name: "host")
     7xml?.setNodeValue(value: "udp", name: "transport")
  • If you have a XML string for an account, parse the XML string using the XmlTree class, and then pass it to the saveAccount method.

     1let sipAccount = """
     2    <account id=\"sip\">
     3        <title>Sip Account</title>
     4        <username>1125</username>
     5        <password>misscom</password>
     6        <host></host>
     7        <transport>udp</transport>
     8    </account>
    11let xml = XmlTree.parse(sipAccount)

Note the following:

  • The id attribute must be specified to identify an account. If not, a unique one is generated for that account upon calling the saveAccount method.

  • Calling SoftphoneBridge.instance().registration().saveAccount() with an XML that has the same id as an existing account replaces the existing account with the new values.

  • If you save a new account with an id that matches the ID of an existing account but different account configuration, the new account (re)registers asynchronously.

  • The account settings are stored on disk, so you do not have to recreate the account when the application restarts.

Deleting an Account

Call the deleteAccount method of the SoftphoneBridge.instance().registration() instance to delete accounts. This method takes account ID as a parameter.


Observing Events from SDK

You can implement your own Softphone Delegates to receive notifications about important events that occur within the SDK.

  • To set up the delegates for the SDK, create the SoftphoneObserverProxyBridge instance and configure it to act as the delegate for the softphone instance. Set an observer immediately after the SDK initialization.

    The following example code snippet demonstrates the setup:

    1let softphoneObserverProxy = SoftphoneObserverProxyBridge()
    2softphoneObserverProxy.delegate = self;
  • You can implement the SoftphoneDelegateBridge protocol and all the methods of this protocol in your class. Some of these methods are optional. The following code snippet gives examples of implementing the SoftphoneDelegateBridge protocol:

     1// This delegate will be called when the registration state changes
     2func onRegistrationStateChanged(state: RegistratorStateType, accountId: String!) {
     6// This delegate will be called when a new event arrives (i.e. incoming call/message)
     7func onNewEvent(_ event: SoftphoneEvent!) {
    11// This delegate will be called when the state of the call changes
    12func onCallStateChanged(state: CallStateType, call: SoftphoneCallEvent!) {
    16// This delegate will be called when the network change is detected
    17func onNetworkChangeDetected(_ network: NetworkType) {
    21// This delegate will be called when the hold state of a call is changed
    22func onHoldStateChanged(states: CallHoldStates!, call: SoftphoneCallEvent!) {
  • Set up Softphone_Cx_Delegate so that you can manage the interaction with iOS CallKit:

    • To modify CXCallUpdate before it is reported to the system.

    • To modify CXProviderConfiguration created by the SDK or to create a new one.

    The following code snippet illustrates setting up the delegate for the Softphone_Cx instance.

    1Softphone_Cx.instance().delegate = self

Handle missed call events

The SDK offers the following APIs that make displaying a missed call count in your UI straightforward:

  • Use SoftphoneBridge.instance().notifications().getMissedCallCount() to retrieve the current missed call badge count.

  • Use SoftphoneBridge.instance().notifications().resetMissedCallCount() to clear the missed call badge count, for example after the user reviewed the (missed) call history.

  • In order to observe missed call badge count changes, override the function onBadgeCountChanged() from the SoftphoneDelegateBridge

To get notified about missed calls from all possible sources, including push, override the func onMissedCalls(_ callEvents: [Any]!) function from your implementation of SoftphoneDelegateBridge. This callback is the optimal one to fire missed call notifications from.

Placing a Call

Use the SDK to enable the application to make calls.

To place calls:

  1. Create SoftphoneCallEvent with a specified accountId and uri.

  2. Associate the SoftphoneCallEvent object with a specific stream.

  3. Send the call event using the post method provided by the SoftphoneBridge.instance().events() instance.

    The method returns the status of the post as the EventsPostResult enum.

The following snippet code illustrates the process of initiating a call:

 1func call(number: String) {
 2    if number.isEmpty {
 3        return;
 4    }
 6    let call = SoftphoneCallEvent.create(withAccountId: "sip", uri: number)
 7    let stream = SoftphoneEventStream.load(SoftphoneStreamQuery.legacyCallHistoryStreamKey())
 9    call?.setStream(stream)
10    call?.transients.set("voiceCall", forKey: "dialAction")
12    let result = SoftphoneBridge.instance().events().post(call)
14    if result != PostResult_Success {
15        print("Failed to post call event")
16    }

Managing Preferences

The SDK provides the app-specific preferences function to manage the Preferences menu items in the application setting. To do so, use the SoftphoneBridge.instance().settings().getPreferences() instance, which provides access to both read-write and read-only properties related to preferences.

Reading Preferences

You can read various properties and check the state of a preference, such as SIP logging, acoustic echo suppression, and pressing keypad volume.

For example, to check if SIP traffic logging is enabled, use the following codes:

1if SoftphoneBridge.instance().settings().getPreferences().trafficLogging {
2    print("SIP traffic logging is enabled")

Changing Preferences

You can modify various properties and change the value of a preference.

For example, the following code snippet demonstrates that setting the trafficLogging property as true to enable SIP traffic logging:

1SoftphoneBridge.instance().settings().getPreferences().trafficLogging = true

Enabling Logging

Enable logging to capture important events and activities that occur within the SDK.

  • By default, the logger is disabled. To enable logging, set the trafficLogging preference to true, as shown in the following code snippet:

    1SoftphoneBridge.instance().getPreferences().trafficLogging = true
  • To disable logging, set the trafficLogging preference to false.

  • To direct the SDK logging into the iOS Console, define your own NSLogSerializer with a custom prefix (<your prefix>), as shown in the following code snippet:

    1let serializer = NSLogSerializer(prefix: "<your prefix>")
  • To retrieve logs at any point, use the following code snippet:

    1let log = SoftphoneBridge.instance().log().get()

Setting up for Push Notifications

Ensure you already set up the VoIP push notifications in both your project and server prior to enabling push notifications. If the setup is not completed yet, go to the iOS Push notifications section for detailed instructions.

The push notifications function is disabled by default in libSoftphone SDK. Modify the provisioning XML file to enable and use this function with the application.


Ensure that your application correctly reports its current state to the SDK. This is crucial for the push notifications to work properly. See Reporting Application States for the setup.

  1. To set the SDK registration with the push servers, add the following snippet to the prefKeys node in the provisioning XML file.

     2    <saas>
     3        <identifier>saas-identifier</identifier>
     4    </saas>
     6    <prefKeys>
     7        <prop name="sipisDisabled" default="0"/>
     8        <prop name="pushNotificationsEnabled" default="1"/>
     9    </prefKeys>

    This snippet is passed to the SoftphoneBridge.initialize method to enable push notifications when libSoftphone SDK initializes.

  2. Enable push notifications so that the application can receive calls. To do so, call the setRegistrationId method on the SoftphoneBridge.instance().notifications().push() instance. This method is used to pass the token data and the usage information to the SDK, as illustrated in the following code snippet:

    1func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
    2    SoftphoneBridge.instance().notifications().push().setRegistrationId(pushCredentials.token, usage: PushTokenUsage_IncomingCall)

Handling Push Notifications for Incoming Calls

After setting up the push notifications functions, pass the push notification payload to the SDK so that the SDK can handle push notifications for incoming calls. To do so, call the handle method on SoftphoneBridge.instance().notifications().push() instance, as illustrated in the following code snippet:

1func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
2    let xml = Dictionary<AnyHashable, Any>.xmlFromDictionary(payload.dictionaryPayload)
3    SoftphoneBridge.instance().notifications().push().handle(xml, usage: PushTokenUsage_IncomingCall, completion: nil)