Skip to main content

Workflows

Initialization

In order to use the Cloudonix Mobile SDK in your application, it must first be initialized with the license key (which you receive from Cloudonix, either a trial or a production license key). The application would load the license key into the Cloudonix Mobile SDK to start the SDK initialization process. This process will verify the license, configure the SDK for the device by utilizing Cloudonix on-line device configuration service and will eventually issue the licensing completion event to the application. If the licensing process failed - for example if the license key is corrupt or has expired - then the SDK will not be operational.

Following that, the application should follow these steps:

  1. Register to receive unsolicited events from the Cloudonix Mobile SDK, so that the SDK can notify the application of important events such as receiving an incoming call or the remote side hanging up an active call. This is done using the addListener() API with an object that implements the CloudonixSDKClientListener protocol.
  2. Set up the SDK configuration parameters such as allowed codecs and transports, using the setConfig() API.
  3. Set up the SIP account details, that will be used for making and receiving calls, using the setConfiguration() API.
  4. Wait for the onSipStarted event to be received by the CloudonixSDKClientListener protocol.

This initialization process can written in Swift as such:

func initCloudonixSDK() {
// load the licnse key from a resource
guard let url = Bundle.main.url(
forResource: "cloudonix_license_key",
withExtension: ".lic") else {
return
}

guard let data = try? Data(contentsOf: url) else {
return
}

var licenseKey = String(data: data, encoding: .utf8)
CloudonixSDKClient.sharedInstance().initialize(withKey: licenseKey) {
(success, error) in
if success {
// `self` should implement `CloudonixSDKClientListener`
CloudonixSDKClient.sharedInstance().add(self)
CloudonixSDKClient.sharedInstance().setConfig("USER_AGENT", value: "MyApp/1.0")
let regData = CloudonixRegistrationData()

regData.serverUrl = "sip.cloudonix.io"
regData.port = 5060
regData.transportType = TRANSPORT_TYPE_TLS
regData.domain = "example.com"
regData.username = "rowdy"
regData.password = "rawhide"
regData.displayName = "Rowdy Rawhide"

CloudonixSDKClient.sharedInstance().setConfiguration(regData)
} else {
return
}
}
}

Registration Modes Setup

The Cloudonix Mobile SDK supports both classic SIP accounts using periodic REGISTER messages to maintain a “connection” to the server, as well as Cloudonix Registration-Free mode.

Registration Mode

In a classic SIP registration use case, the application should:

  1. Make sure to set up a CloudonixRegistrationData object contains the correct SIP account details (including SIP domain name and transport details) and send it to the CloudonixSDKClient using the setConfiguration() call during initialization.
  2. Once the application's CloudnixSDKClientListener protocol receives the onSipStarted() event - call registerAccount() to start the registration process.

After calling registerAccount() the Cloudonix Mobile SDK will fire the onRegisterState() event whenever the registration state changes. The application can also call isRegistered() to check the registration status. If the application does not need to receive calls, it is possible to not call registerAccount() - this will have the effect that the SDK will consume less resources (resources that would have been used to maintain the registration status of the account), but in such a case it is recommended to also set the CloudonixRegistrationData.workflow field to WORKFLOW_TYPE_REGISTRATION_LESS to allow the SDK to optimize of this use case.

Regardless if the application has called registerAccount() or not, after the SIP stack was started, the application may call one of the dial() methods to start a call using the configured SIP account details configured.

Example Registration

func onSipStarted() {
CloudonixSDKClient.sharedInstance().registerAccount()
}

func onRegisterState(_ result: CloudonixRegistrationState_e, expiry: Int32) {
switch result {
case REGISTRATION_SUCCESS:
print("registered")
case REGISTRATION_ERROR_CREDENTIALS:
print("auth error")
case REGISTRATION_UNREGISTERED:
print("No longer registered")
}
}

Registration-Free mode

In a Registration-Free use case, there is no need for the application to perform SIP registration as call reception is handled by the application backend using push notifications, and there is also no need to set user authorization credentials as the application will be authorizing each call separately using a Cloudonix one-time session token.

During initialization, make sure that the CloudonixRegistrationData object contains the correct SIP account details (including SIP domain name and transport details, though username and password should not be set) and send it to the CloudonixSDKClient using the setConfiguration().

At any point after the CloudonixSDKClientListener receives the onSipStarted() event, the application can dial or receive calls, using the dialRegistrationFree() method.

Dialing Workflows

Dialing In Registration Mode

After the application completes setting up the SDK and configuring the SIP account details, the application may use the dial() command to start a SIP session.

The dial command will start the calling process and will cause the Cloudonix SDK to issue onCallState() events for each stage in the calling process.

Example Dial in Registration Mode

func dial(_ phoneNumber: String) {
if (!CloudonixSDKClient.sharedInstance().isRegistered())
return
CloudonixSDKClient.sharedInstance().dial(phoneNumber)
}

func onCallState(_ callId: String!, callState: CloudonixCallState_e, contactUrl: String!) {
switch callState {
case CallState_Starting:
print("Starting call", callId, "to number:", contactUrl)
case CallState_Connecting:
print("Connecting call", callId, "to number:", contactUrl)
case CallState_Calling:
print("Calling call", callId, "to number:", contactUrl)
case CallState_Ringing:
print("Ringing call", callId, "to number:", contactUrl)
case CallState_Confirmed:
print("Connected call", callId, "to number:", contactUrl)
case CallState_Disconnected,
CallState_DisconnectedDueToBusy,
CallState_DisconnectedMediaChanged
CallState_DisconnectedDueToNetworkChange,
CallState_DisconnectedDueToNoMedia,
CallState_DisconnectedDueToTimeout:
print("Hangedup call", callId, "to number:", contactUrl)
default:
break
}
}

Dialing in Registration-Free Mode

After the application completes setting up the SDK and configuring the SIP account details (usually just the SIP server address and domain name), the application may start a Registration-Free dial by obtaining a session token from application backend (please refer to the Cloudonix Registration-Free Dialing specification for more details) and then use the dialRegistrationFree(number, token) method to start a call.

It is also possible to set up the SIP stack only right before making a call (or receiving a call). This is useful in case the application manages multiple subscriber accounts and knows which account to use for a call only at the last second. In such a case it is important to wait for the onSipStarted() event before issuing the dial call, for example:

Example Dial in Registration-Free

var sessionToken = ""
var msisdn = ""

func makeCall(_ phoneNumber: String, token: String, regData: CloudonixRegistrationData) {
sessionToken = token
msisdn = phoneNumber
CloudonixSDKClient.sharedInstance().add(self)
CloudonixSDKClient.sharedInstance().setConfiguration(regData)
}

func onSipStarted() {
CloudonixSDKClient.sharedInstance().dialRegistrationFree(msisdn, session: sessionToken)
}

Incoming Calls

Call Reception in Registration Mode

When a call is received, the onCallState() event will be invoked with the CallState set to CALL_STATE_INCOMING. When the application handles the event, it can call either answer(callId) or reject(callId) as required. See Call Maintenance below for additional explanation of the onCallState() event.

Eg.

func onCallState(_ callId: String!, callState: CloudonixCallState_e,
contactUrl: String!) {
if callState == CallState_Incoming {
CloudonixSDKClient.sharedInstance().answer(callId)
}
}

Call Reception in Registration-Free Mode

When a push notification for an incoming call is received, containing a Registration-Free call token, the application should make sure that onSipStarted() has already been received, and then use the dialRegistrationFree(msisdn, token) call to accept the call.

Please note that the phone number provided in the first parameter can be of any value (the token is the only value that determines the success of receiving the call), but its value must never be set to null.

Call Maintenance

During the life of a call, from beginning to end, the Cloudonix Mobile SDK will call the client’s onCallState() event handle multiple times passing the call identifier (“key”), the update call “state” and additional details about the call. The event listener should examine the call state and perform actions to reflect the current state of the call to the user, as needed.

Normally a client is expected to handle at least the following events:

  • CALL_STATE_INCOMING - The client should display a UI to indicate that the call is incoming and later use the Cloudonix Mobile SDK’s answer() method to pick up the incoming SIP call
  • CALL_STATE_CONFIRMED - The client should display a UI to indicate the call is in progress and offer additional UI to the user to perform call operations (such as hanging up).
  • CALL_STATE_DISCONNECTED (and all its variations) - The client should recover and reset all resources used to handle the call and remove any “in call” UI. See the “Call States” reference table, at the end of this document, for a complete list of possible call states and what they mean.

Sending DTMF

It is common for users to want to send DTMF signals to the remote end, to signal that the user has pressed on a standard numeric keypad during the call. The client can use the Cloudonix Mobile SDK’s DTMF() method. The method call receives the call ID of the call on which to send DTMF signals, and a character representing the DTMF signal to send.

Eg.

func sendDTMF(code: Int) {
CloudonixSDKClient.sharedInstance().dtmf(currentCallId, digit: Int8(code))
}

Application Shutdown

It is important to note that when the application is moved to the background, the SDK will still maintain context to allow the application to receive calls. If the application needs to shut down completely and not receive any calls, it should call shutdown(), after which the SDK is completely shut down and in order to start it again it needs to be reinitialized.