SDK setup

The following sections describe installation and setup of the Voice SDK:


To use the Voice SDK you need:

  • Xcode (v. 11.3.1)
  • Swift
  • iOS (13.3.1)
  • Supported architectures (arm64, and x86_64)

Create an iOS project

To get started, create an iOS project according to the following steps:

  1. Open Xcode and click Create a new Xcode project
  2. Select Single View App as the template and click Next
  3. Choose the folder where to store the project and click Create
  4. Go to the TARGETS > Project Name > General > Signing menu and select Automatically manage signing
  5. Click Enable Automatic on the displayed pop-up window


Integrate the Voice SDK

To integrate the Voice SDK:

  1. Download the latest version of the Wavecell Voice SDK for iOS You can download the Voice SDK here???.
  2. Unzip the downloaded Voice SDK package. You should have the following contents from the extracted .zip file:


The Voice SDK package includes:

  • Wavecell.framework
  • Wavecell.framework.dSYM
  • Voice iOS SDK Documentation
  1. Copy the Wavecell.framework bundle to the Frameworks folder as shown:


  1. Go to the menu at TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content:


  1. Drag the Wavecell.framework bundle from the Frameworks folder into the Frameworks, Libraries, and Embedded Content section.


Enable VoIP capabilities

To enable VoIP capabilities:

  1. Go to TARGETS > Project Name > Signing & Capabilities and then add Background Modes.


You can also enable Audio, AirPlay Voice over IP and other attributes while in this directory.

  1. Go to the TARGETS > Project Name > Signing & Capabilities and add Push Notifications.


  1. Go to TARGETS > Project Name > Info and add your privacy description for microphone usage.


The NSMicrophoneUsageDescription property describes the reason your app needs to access the phone microphone. When the system prompts the user to allow access, this string is displayed as part of the alert. Therefore, it cannot be left empty.

Disable bitcode

Bitcode is an Apple technology that enables app recompilation in order to reduce storage size. The Wavecell framework is built without bitcode which may cause access issues on a bitcode enabled system.

To disable bitcode, go to TARGETS > Project Name > Build Settings and set Enable Bitcode to No.


Build and run

After you have completed the preceding integration tasks, you can verify if your app can invoke functions from the Wavecell.framework by doing the following:

  1. Modify the AppDelegate.swift file by adding the following lines:

    import Wavecell print("\(Wavecell.shared.version())")

  2. Build (Cmd+B) and Run (Cmd+R) the app project

  3. If successful your Xcode console displays the following type of message:


15:05:33.291 [WAVECELL.SDK] [INFO] [Wavecell.swift:version():285]


Push notification setup

The Wavecell backend solution includes the notification server. The notification server establishes secure connection with APNS in order to send push notifications to your application.

There are two types of secure connections:

The Wavecell backend supports both types of secure connections.


For the certificate-based type of connection, generate the VoIP Service Certificate with your Apple developer account:

  1. When the certificate is ready, click Download and save it to your local drive (voip_services.cer file).

  2. Open the voip_services.cer file with the Keychain Access app on your computer. Select the** login** option if you are asked which keychain to add the certificate to.

  3. In the Keychain Access app, select the Certificates option in the bottom section of the left sidebar. You will now need to find the certificate you have created.

  4. Export your Certificate as a .p12 file.

  5. Convert the .p12 file to a .pem file using the Terminal openssl command.

  6. Register the Certificate (apns-voip-services.pem file) with your Wavecell developer account.


For a token-base connection you will need to generate a key using your Apple developer account with Apple Push Notification Service enabled.

Once the key is ready click** Download** and save it to your local drive (AuthKey_<Key ID>.p8 file). Then register the Key ID and Key (.p8 file) with your Wavecell developer account.

Using the Voice SDK

The Voice SDK interface uses the Wavecell facade object. The facade object is the starting point for all communications between the client and the Voice SDK.


The SDK interface uses the Wavecell facade object, the starting point of all communications between the client and the Voice SDK.


The Voice SDK is designed to fit the concept of account based applications in which the application has a login (auto-login) and logout actions.


The client initializes the Voice SDK once and then may have multiple activation/deactivation cycles following user login or logout.


To configure the Voice SDK the client assigns the user account configuration (`WavecellConfiguration1) as follows:

    let sdk = Wavecell.shared
        // …
    sdk.configuration = WavecellConfiguration(...)

The resulting configuration creates the following:

    public struct WavecellConfiguration: Hashable
    	public var accountId: String
    	public var userId: String
        	// …
    	public var displayName: String
    	public var phoneNumber: String?
        	// …
    	public var callKit: CallKitOptions

User Account

The accountId and userId can only be changed when SDK is in .inactive state.


Assign your system values for the following fields in the Voice Callkit framework:

public struct CallKitOptions: Hashable

	public var localizedName: String
    	// …
	public var ringtoneSound: String?
    	// …
	public var iconFileName: String?

The callKit property can only be changed when there are no active calls.


The iOS Wavecell client passes the jwtToken to the Voice SDK by setting the authenticationContext property of the Wavecell object as follows:

let context = AuthenticationContext(jwtToken: "Token Value")
    { token in
        // token refresh is requested
 sdk.authenticationContext = context


The Voice SDK uses callbacks to expose (or request) data to the Wavecell client:


The callback type exposes information about parameters (e.g., the type and order).

The callback is an external extension to the Voice SDK functionality. If the callback is set the Voice SDK passes the log message to it:

Wavecell.logMessageCallback =
    { module, message, level, context in
        // print log message to the console

You can set the log message callback on the Wavecell client before Voice SDK initialization.

Contact resolution

The Voice SDK enables setting the callback block for contact resolution.

The block returns the contact details (if available) for a specified contact ID.

The contact details contain the displayName property. The Voice SDK uses the displayName property value as the caller name on an incoming call screen.

The incoming call screen is displayed when the incoming call notification (push) arrives on a device:

Wavecell.contactResolverCallback =
    { context, completion in
         // …
     let contact = ContactInfo(contactId: context.callerId,
                               displayName: context.callerName,
                               avatarUrl: nil, phoneNumber: nil)

The Voice SDK may request the contact details on an incoming call notification. The Wavecell client can adopt the Contact protocol and return the adjusted information in a completion handler as follows:

struct ContactInfo: Contact
    var contactId: String
    var displayName: String?
    var avatarUrl: String?
    var phoneNumber: String?
        // …


To activate Wavecell the client invokes the activate function as follows:

public func activate(completion: @escaping
(_ result: RtcResult<Void>) -> Void)
    { result in switch result
        { case .success:
          case .failure:

Upon a**.success** notification, the Wavecell object transitions to the .active state.

Otherwise, it returns back to the .inactive state as follows:

enum State
      case inactive, activating, active, deactivating

The Wavecell client can use the WavecellStateObserverProtocol protocol and receive notifications on the Wavecell object state change:

public func addObserver(_ observer: AnyObject)
    func handleStateChanged(_ state: WavecellState)
    	// …


You can use the Wavecell client to invoke the deactivate function:

public func deactivate(completion: @escaping
    (_ result: RtcResult<Void>) -> Void)sdk.deactivate
        result in switch result
            case .success:
               case .failure:

Upon completion, the Wavecell object transitions to an .inactive state regardless of the actual result.

Call features

Place a call

When an outgoing call is placed the following function is used:

func placeCall(callType: CallType, to callee: Contact,
           completion: @escaping (RtcResult<VoiceCall>) -> Void)
        let completionBlock: (RtcResult<VoiceCall>) -> Void = { result in switch result
               case .success(let call):
               	// present UI
               default: break
        let parameters = OutgoingCallParameters(callType: .voip, callee: callee)
        sdk.placeCall(with: parameters, completion: completionBlock)

Receive an incoming call

When you configure for incoming calls, the Wavecell client uses the WavecellCallSetObserverProtocol protocol and registers the observer with the Wavecell object:

class MyWavecellClient: WavecellCallSetObserverProtocol
      func handleCallAdded(_ call: VoiceCall)
             if call.direction == .inbound
           // present UI
let client = MyWavecellClient(...)

Call observer protocols

The VoiceCall object is observable. A client can be notified when a particular property of the VoiceCall object is changed.

The object has a list of observers and on certain event calls the corresponding function of the observer object.The Wavecell client may adopt the following protocols:

  • VoiceCallStateObserverProtocol
  • VoiceCallConnectionQualityObserverProtocol
  • VoiceCallMutedStateObserverProtocol

and register the observer with the VoiceCall object:


Mute a call

The VoiceCall object has the muted property which enables call muting as follows:

public protocol VoiceCall: class
    	var muted: CallMutedState { get set }

You can mute and unmute the call by assigning the corresponding value in the Wavecell client:

call.muted = .on // .off

Put a call on hold

Use the following hold function for call holding:

func hold(_ completion:
    ((CallActionCompletionStatus) -> Void)?)
        func resume(_ completion:
            ((CallActionCompletionStatus) -> Void)?)
                status in
                switch status
                    case .done:
                    case .canceled:
                    case .failed:

The execution of the hold (resume) operation implicitly triggers the call state change.

Hang up a call

Use the hangup function to initiate hang up or call conclusion functionality:

func hangup(_ completion: ((CallActionCompletionStatus) -> Void)?)
 call.hangup { status in
    switch status {
    case .done:
    case .canceled:
    case .failed:

On completion the call transitions to the**disconnected** state. Additionally, the Voice SDK removes the call from the calls list.

Push Notifications

The Voice SDK handles PushKit notifications internally.

For debugging purposes, the Voice SDK makes it transparent to the Wavecell client.

The Wavecell object has the pushToken property.

In order to monitor the push notification payload or observe the token change - you can use the WavecellPushNotificationObserverProtocol protocol for the Wavecell client.