FCSDK Developer Guide
FCSDK Developer Guide
Updated: 2022-08-31
Contact Information
Related Documentation
Before doing anything, the FCSDK enabled application needs to create a session on the server;
the server exposes a session creation REST API for the purpose. Although it would be possible
in principle to dispense with the Web Application, and expose that API directly to the
applications, such an approach has serious drawbacks:
The Web Application ID is a unique text string which identifies the Web Application to the Web
Gateway, and confirms that the Web Application is allowed to create sessions. The Web
Application ID must correspond with one on the list of acceptable Web Application IDs configured
on the Web Gateway (see FCSDK Administration Guide).
There is no authorization of users - an application which can create a session can create a
session with any or all permissions, whereas you may want some users to have more
access to FCSDK facilities than others.
The recommended approach is to create a Web Application which users can log in to with a user
name and credentials, and which will return the session token to authenticated users. The Web
Application will:
While the Fusion Client SDK defines the way in which both the Web Application and client
communicate with the Web Gateway, it does not restrict how the Web Application communicates
with the client.
How the Web Application authenticates the user is entirely in control of the application itself. The
sample application provided with FCSDK uses a particularly simple scheme, in which an XML file
which is deployed to the server contains the users and their capabilities (look at this in
conjunction with the sample code):
1. The sample application’s login servlet receives an HTTP request containing a user name
and password, either as part of a JSON body, or as parameters to the request
(LoginServlet.handleLoginFromWebpage and BaseLoginServlet.getUserLoginSessionID).
It’s easy to see how this could be adapted to a scheme where the information about each user
was held in a secure database, or on an LDAP server.
After it has authenticated the user, the Web Application sends a POST request to the Web
Gateway. The request describes the requested capabilities for the session, such as:
As the message contains the Web Application ID, CBA recommends that this transaction is
performed over HTTPS for security.
The content type of the POST message should be application/json, and the body must be
formatted as a JSON string:
{
"timeout":1,
"webAppId":"WEBAPPCSDK-A8C1D",
"allowedOrigins":["example.com"],
"urlSchemeDetails":
{
"secure":true,
"host":"wg.example.com",
"port":"8443"
},
"voice":
{
"username":"jbloggs",
"displayName":"Joseph",
"domain":"example.com",
"inboundCallingEnabled":true,
"allowedOutboundDestination":"sip:[email protected]",
"auth":
{
"username":"1234",
"password":"123456",
"realm":"example.com"
}
},
"aed":
{
"accessibleSessionIdRegex":".*",
"maxMessageAndUploadSize":"5000",
"dataAllowance":"5000"
},
Member Description
abcdef;encoding=hex
abcdefghijk;encoding=blah;paramname=paramvalue
"abcdefghijk";encoding=blah
To be a valid JSON string for creating a session, the JSON must obey the following rules:
Examples
See the following examples of POST messages for examples of how to start sessions with
specific capabilities:
For voice and video calling, using all the default settings:
{
"webAppId":"WEBAPPCSDK-A8C1D",
"voice":
{
"username":"jbloggs",
"displayName":"Joseph",
"domain":"example.com"
}
}
For voice and video calling, specifying URL scheme details and an allowed origin:
AED Only
{
"webAppId":"WEBAPPCSDK-A8C1D",
"aed":
{
"accessibleSessionIdRegex":".*",
"maxMessageAndUploadSize":"5000",
"dataAllowance":"5000"
}
}
You might use this technique to put some sensitive data in the User-to-User header which the
consumer application does not know (or at least, does not transmit). When the consumer
application requests a session token, the Web Application puts the sensitive data, known only to
itself, in the uuiData element of the JSON which it sends to the session token servlet. The Web
Gateway associates that data with the session it creates. When the consumer application makes
a call to a SIP device using that session, the Web gateway populates the User-to-User header of
the INVITE which it sends to the SIP device with the sensitive data. How the SIP device uses the
data is a matter for the device itself, but it could be an authentication token which allows it to set
up the call.
If the data which needs to be sent to the SIP device is not sensitive, the consumer application
can send it to the Web Application, and the Web Application can copy it to the uuiData element of
the JSON it uses to create the session token.
JSON Response
When it has created the session, the Web Gateway responds with a JSON string containing
configuration data for the client, which includes a session ID for the new session; the Web
Application must pass this token to the client application. If the JSON submitted to the Web
Gateway contains properties with names that are unknown to the Gateway, the response
contains an unknownProperties object with those properties; it is omitted if there are no unknown
properties:
{
"sessionid" : "<very long string..>",
"unknownProperties" : ["<propname1>","<propname2>",...]
}
The Web Application should end the session on the Web Gateway when it knows that it is no
longer needed. The sample application included with FCSDK does this in response to an explicit
To end the session, the Web Application needs to send an HTTP DELETE request containing the
session ID to the Web Gateway at one of the following URLs:
The response for the DELETE operation will be 204 No Content. This is conventional in
REST services, as nothing is returned in the response.
This tears down any calls the user has active and invalidates the session.
You can also enhance any existing browser-based applications with these features.
Fusion Client SDK provides you with a network infrastructure and JavaScript API which make
use of technologies such as WebRTC to integrate seamlessly with your existing SIP
infrastructure. The JavaScript API is delivered with its own reference javadocs available at
<installation_directory>/Core_SDK/JavaScript_SDK/jsdoc.
For more detailed discussion of the Fusion Client SDK solution, refer to FCSDK Overview
Guide.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
In your development environment, start a new project and create the page to use to deliver your
client application. The Fusion Client SDK JavaScript SDK files were installed when you
installed the Web Gateway, so will be automatically available to any client application which
accesses the Web Gateway itself. Each page which uses the JavaScript API will need to include
the following script tags:
csdk-sdk.js implements voice and video calling and AED; if you only want to
implement a subset of this functionality, you can include only the script for
the functionality you require:
If you are using a subset of functionality, ensure that you include csdk-common.js after the
modules you require. If you are using only AED, and want to avoid prompting the user for access
to their microphone and camera, ensure that you do not include csdk-phone.js (either directly or
indirectly).
When the JavaScript runs, it creates an object called UC in the global namespace.
To set up all the functionality to which the user has access, you must obtain a session ID from
your Web Application (see the Creating the Web Application section), and initialize the UC object
by calling the start method on the UC object with it.
To confirm that UC has initialized correctly, you can use the onInitialised method. To determine
whether UC has failed to initialize, you should implement onInitialisedFailed.
UC.onInitialised = function() {
//Register listeners on UC
UC.phone.onIncomingCall = function(call) {
// perform tasks associated with incoming call
};
};
Once the UC object has initialized, the application can use its phone and aed objects to make
and receive calls, or to access any other FCSDK functionality. Note that the above code assigns
the phone.onIncomingCall function only in the onInitialised callback; this is typical - the phone
and aed objects can only be used inside the onInitialised callback, or after it has been received.
STUN servers are not necessary if the Gateway is not behind a firewall, so that Network
Address Translation is not needed; in this case the stunServers array can be empty. You can
provide your own STUN server instead of the public Google one above; and you can provide
more than one in the array, in which case FCSDK tries them in sequence until it finds a
working one.
Your Web Application may fail to return a session ID (for instance, if it cannot authenticate
the user). In these situations the user should be logged out and needs to log in again to start
a new session (see the Creating the Session section).
pluginInfoCallback is called with an argument (pluginInfo), which is a JavaScript object with the
following members:
Member Values
status
zero length stringIf pluginRequired is false
latestAvailable
string in form x.y.zWhere x, y, and z are integers. This is the
latest version of the plugin available on the server.
pluginUrl
zero length stringIf pluginRequired is false
The user may not have permission to install plugins. In this case, it is the responsibility of their IT
administrator to install the correct plugin, and the application should inform the user of the
problem.
Stopping A Session
An explicit method has been added to end an existing session by disconnecting the existing
websocket and nulling it against future reconnection attempts.
UC.stopSession();
This will likely need to be called in conjunction with the server-side call to the Gateway to delete
the current session token, in order to completely tear down an existing call and session, if
required.
All of the functions required to develop applications for browser-based voice and video are
supported by the UC.phone object. This is an instance of the Phone class.
If you want to add a preview window (a window which displays the video which is being sent to
the other endpoint) before a call is established, you can call the UC.phone.setPreviewElement
function. An appropriate time to do this is in the UC.onInitialised callback:
UC.onInitialised = function() {
UC.phone.setPreviewElement(document.getElementById('local'));
};
var call;
call = UC.phone.createCall(numberToDial);
call.onInCall = function() {
call.setPreviewElement(document.getElementById('local'));
}
With mobile javascript, either running inside a supported mobile web browser or webView in a
native application, there are additional methods and functionality provided specifically for a
mobile web app. Namely, these are to provide a mirrored preview video from a user-facing
device camera and to handle switching between “enviromental” and “user” cameras available on
most mobile devices.
When the UC object has been initialised, the mobile web developer will need to set the default
facing mode to either “user” (which selects an optimal front facing camera) or “environment”
which selects an available outward facing back camera. They can do this via this method:
UC.phone.setFacingVideo("user")
or
UC.phone.setFacingVideo("user")
Further, this method can be called with an existing call object as a second argument to allow the
user to switch facing modes during a call; i.e. to switch from a front to back camera. For
example, with the first ongoing call:
UC.phone.setFacingVideo("user", UC.phone.getCalls()[0])
When developing a mobile web application for video calling it can be expected the local preview
video be mirrored if the user is using their front facing camera. To support this, the developer can
make use of the Mirror Mode setting on the UC Phone object.
This setting has three modes; “On”, “Off” and “Auto”. e.g.
UC.phone.setMirrorMode("On")
“On” will always mirror the preview video element - developers can use this in conjunction with
setting “Off” to programatically manage mirroring in accordance with their camera selection. “On”
mode will work with desktop as well as mobile.
“Auto” needs to be called after the UC phone has been initialised with the “user” facing mode.
The mirroring will then automatically follow the switch between camera facing constraints (e.g.
“user” and “environment”)
For some use cases, it may be useful to throw away access to the user’s media devices after a
call has ended or been ended, for device security reasons. There is a flag that can be set for this
purpose, which accepts a Boolean as it’s only parameter. For example:
UC.phone.setRetainMediaAfterCall(false);
This needs to be set via the Phone object before a call is created or answered.
Making a Call
The phone object provides a createCall method, to which your client application should provide
the number to contact. This returns a new Call object, on which you can set callbacks and call
the dial method, which initiates a call to the destination specified for the call. The dial method
takes two string parameters:
The default for both parameters is enabled, which provides backward compatibility and
convenience, as the application need only call dial to establish 2 way communication on both
voice and video (considered the normal case).
call.dial() must only be called after the application has initialized the SDK and received the
UC.onInitialised callback (see the Initializing the SDK section).
var call;
//A method to call from the UI to make a call
function makeCall(numberToDial) {
//Create a call object from the framework and save it somewhere
call = UC.phone.createCall(numberToDial);
call.onInCall = function() {
// Show video stream(s) in elements
call.setPreviewElement(previewVideoElement);
call.setVideoElement(remoteVideoElement);
};
We recommend that the application should override the following error methods to inform the
user of call status, in the event that any issues occur when making a call:
onBusy
onCallFailed
onDialFailed
onGetUserMediaError
onNotFound
onTimeout
As shown above, to end the call the client should call the Call object’s end method.
Receiving a Call
Overriding onIncomingCall allows FCSDK to notify the client application when it receives a call.
The notification has a Call object as a parameter; the Call object contains details of the call in
progress and some key methods which should be overridden.
In a simple application, showing some user feedback when this object is called enables a user to
receive a call.
var call;
// Define what to do on incoming call
UC.phone.onIncomingCall = function(newCall) {
var response = confirm("Call from: " + newCall.getRemoteAddress() +
" - Would you like to answer?");
if (response === true) {
// What to do when the remote party ends the call
newCall.onEnded = function() {
alert("Call Ended");
};
To answer the call, your client application should call the Call object’s answer method.
The default for both parameters is enabled, which provides backward compatibility and
convenience, as the application need only call answer to establish 2 way communication on both
voice and video (considered the normal case).
To reject the call, your client application should call the Call object’s end method.
In order to send local media to the Web Gateway, the application must call
setLocalMediaEnabled. The setLocalMediaEnabled() method supports two boolean parameters:
The setLocalMediaEnabled() method also supports a single parameter JavaScript object which
contains both the audio and video capabilities. This object contains two boolean parameters,
audio and video, which can be set separately:
Adding a Stream
To enable the client you develop to play any audio and video provided by the framework, you
must call Call.setVideoElement, passing in the element that is be used to display the video and
the ID of the stream to be displayed:
call.onInCall = function() {
call.setVideoElement(document.getElementById('remote'), 'streamid');
}
The stream ID is optional, and defaults to ‘main’ if not provided. The application should only need
to specify it if the framework is providing more than one video stream; in that case, the
application should know what those stream IDs are, and may give the user some way to switch
between them.
In IE, the element which displays the video (whether remote or local) needs to have a minimum
size; in IE the default height is 0, and it does not expand to accommodate the video stream when
that starts. You can correct this with a CSS entry:
You need to set the elements that are immediate children of the remote and local elements
(assuming that remote and local are the elements which you will pass to setVideoElement and
setPreviewEement); FCSDK will add a child to the remote and local elements, with the same
Ending a Call
If the user ends the call, the client application should call the Call object’s end method.
In order to detect that the remote party has ended the call, the client application needs to
override the Call object’s onEnded callback method.
During a call, the application can mute and unmute the local audio and video streams separately.
Muting the stream stops that stream being sent to the remote party. The remote party’s stream
continues to play locally, however.
If the user puts a call on hold, the client application should call the call object’s hold method.
To resume a call that currently on hold, the client application should call the call object’s resume
method.
call.sendDtmf("#123*", true);
The first parameter is a string representing the tones to send. Valid values for the tones are
those characters conventionally used to represent the standard DTMF tones:
0123456789ABCD#*. A comma character inserts a two-second pause into a sequence of tones.
Alternatively, to send a single tone, the application can pass in a number from 0 to 9.
The second parameter should be true if you want the tones to also be played back locally, so
that they are audible to the user.
Applications developed with Fusion Client SDK JavaScript SDK support multiple simultaneous
calls:
To make additional calls while another call is in progress, the client application would use
the UC.phone.createCall(numberToDial) method (see the Making a Call section).
The Fusion Client SDK JavaScript SDK supports configuring the captured, and therefore sent,
video resolution for video calls. The application can select one of a set of video resolutions, and
apply it to the capture device. It can also configure the frame rate for capture. When it specifies a
resolution and frame rate, FCSDK makes every effort to match those values where hardware
allows.
The new resolution and frame rate only take effect for subsequent calls, and do not affect calls
that are in progress.
The application can get a list of possible resolutions from the Phone object using the
videoresolutions array:
When you set the resolution, the device’s camera may not support that resolution. In that case
the browser provides a different resolution, but exactly what resolution will depend on the
browser being used.
The application can set the captured video resolution using the
setPreferredVideoCaptureResolution(resolution) method of the Phone object. The value supplied
must be one of the video resolutions presented in the videoresolutions array (see the
Enumerating Possible Resolutions section):
There may be circumstances when you want to set a specific video resolution not listed above.
You can do this by specifying a JavaScript object which contains the width and height in pixels:
UC.phone.setPreferredVideoCaptureResolution({width:400,height:200});
The device must be able to support the resolution that you specify; if not, the browser provides a
default resolution. Currently, for example, Google Chrome defaults to a resolution of 640x480 if
the requested resolution is not available.
The application can set the captured video frame rate using the
setPreferredVideoFrameRate(rate) method of the Phone object.
UC.phone.setPreferredVideoFrameRate(30);
Often, a user has more than one input device attached. This is commonly the case with audio
input devices (microphones), and is becoming increasingly common with video input devices
(front and back cameras on tablets, for example). An application can set its preferred audio and
video devices using the functions:
UC.phone.setPreferredAudioInputId(id);
and
UC.phone.setPreferredVideoInputId(id);
before a call starts. The id parameter is a string which uniquely identifies the input device; it may
also be ‘default’, which allows the browser to choose the input device itself. To find the ID of a
particular device, you must list all the input devices, and use the ID of one of them; see the
Getting the Input Devices section.
You can set the preferred audio or video ID to a value which does not correspond to an input
device.
If you call Call.dial (see the Making a Call section) while the preferred media ID is invalid in
this way, FCSDK calls onGetUserMediaError, followed by onCallFailed.
If you call Call.answer on a received call (see the Receiving a Call section) while the
preferred media ID is invalid, FCSDK also calls onGetUserMediaError, followed by
onCallFailed.
If you make or receive a call as audio-only or video-only using the input parameters
withAudio and withVideo of dial and answer, the preferred input ID of the inactive media may
be invalid without affecting the call.
The application can get the current preferred audio and video input devices using:
and
var id = UC.phone.getPreferredVideoInputId();
Initially, the browser prefers the default device, and the ID returned by these functions is ‘default’;
after local media has been established, the functions return the actual ID of the currently
preferred device.
UC.phone.setOnGetMediaDevices(function(devices) {
});
The devices object contains two arrays, videoinputs and audioinputs, either of which may be
empty (if there are no local media devices of that type); each element of each array is an object
which contains a label and an id:
{
"videoinputs" : [
{
"label" : "Microsoft® LifeCam HD-3000 (045e:0779)",
"id" : "c5cfe4b705510e08e43346e262e81bc26bb1207e5ca0f12e0d45750099740c37"
},
],
"audioinputs" : [
{
"label" : "Default",
"id" : "default"
},
{
"label" : "Built-in Microphone",
"id" : "77c7f2e78a889bd84a83e0df6cf76699338dde84246d342469891e91e3711cb4"
},
The label element is a moderately informative description of the device; id is the value to be used
as a parameter for the setPreferredAudioId and setPreferredVideoId functions. The callback
function will be called more than once because the device labels change after local media
becomes established. Before that, the labels are uninformative, such as Mic 1 and Cam 2.
When a problem occurs obtaining the user media (microphone or camera) the Fusion Client
SDK provides three call backs on the Call object:
getUserMediaError is called when there is a terminal user media problem which has
resulted in the call ending (for instance, if the user has denied permission to both the
microphone and camera).
FCSDK will only call the onOutboundAudioFailure and onOutboundVideoFailure methods if the
relevant media type was requested when making the call; the timing of these method callbacks
will vary depending on the browser.
During call setup, the call transitions through several states, from the initial setup to being
connected with media available (or failure). You can implement callbacks to get notifications of
the transitions to some of these states, in order to provide feedback to the user or to take some
other action.
The following table gives the available callbacks, on Phone and Call objects:
Callback Meaning
All of the functions required to develop applications for browser-based Application Event
Distribution (AED) are on the UC.aed object. The application can subscribe to a topic, and can
send data (consisting of key-value pairs) or messages (simple text) to that topic, and have all
other subscribers to that topic see the data and messages.
Creating a Topic
UC.aed.createTopic(topic);
where topic is a unique string identifier for the topic. This method call returns a Topic object.
Subscribing to a Topic
After it has created the topic, the client application subscribes to it by calling:
This method call triggers one of the following events on the client:
onConnectSuccess (data[])
onConnectFailed
The onConnectSuccess callback includes an array of data objects representing all the existing
data (as key-value pairs) on the topic. Each object in the data array has the following members:
Member Description
A number indicating the data’s version relative to other values that have been
version
sent. Later versions have higher values.
Whether the data for this key was deleted. If this is true, value may be null or
deleted
undefined.
The key and value elements of the data object must be strings.
Once it receives the onConnectSuccess callback, the application may receive onTopicUpdate
notifications. onTopicUpdate is fired each time anyone connected to the topic updates the topic’s
data or sends a message to it. The callback passes a JSON topic object which contains details
of the new data update or message in the following format:
{
"type": "topic",
"name": "Pension",
"data": [
{"key":"dataKey", "value":"dataValue", "version":"0"},
{...},
{...},
...
],
"message": "This my message!",
"timeout": 120
}
The following code sample shows the code required to subscribe to a topic:
UC.onInitialised = function() {
// create a topic
var topic = UC.aed.createTopic('topic');
topic.onConnectSuccess = function(data) {
for (var i = 0; i < data.length; i++) {
// Process each data object
}
}
topic.onConnectFailed = function(message) {
alert(message);
}
topic.onTopicUpdate = function(key, data, version, deleted) {
// Store or display new data received
}
topic.connect();
};
The application can compare the version of a data object with the version of a stored version of
the same data to ensure that an older version does not replace a newer one.
topic.disconnect(delete);
The delete argument is an optional boolean. If true, the topic is removed from the server
(disconnecting all users from the topic); if false, only the current user will be disconnected from
the topic.
If delete is true, this method call triggers one of the following events on the client:
onDeleteTopicSuccess
onDeleteTopicFailed
topic.submitData(key, value);
Both key and value should be strings. This method call triggers one of the following events on
the client:
onSubmitDataSuccess
onSubmitDataFailed
All clients which are subscribed to the topic receive an onTopicUpdate event.
The following code sample shows the steps required to create a topic and publish data to it:
UC.onInitialised = function() {
var topic = UC.aed.createTopic('topic');
topic.onConnectSuccess = function(data) {
// Submit new data when connected to topic
topic.submitData('key_one', 'value');
}
topic.onConnectFailed = function(message) {
alert(message);
}
topic.onSubmitDataSuccess = function(key, value, version) {
// Log success
}
topic.onSubmitDataFailed = function(key, value, message) {
// Notify user of failure
}
topic.onTopicUpdate = function(key, value, version, deleted) {
// Display new data to user
}
topic.connect();
};
topic.deleteData(topic, data_key);
This method call triggers one of the following events on the client which called deleteData:
onDeleteSuccess
onNotFound.
If successful, all clients subscribed to the topic to receive an onTopicUpdate event (with the
deleted parameter set to true).
topic.sendMessage(msg);
This method call triggers one of the following events on the client:
onSendMessageSuccess
onSendMessageFailed
The following code sample shows the code required to send a message to all the clients
subscribing to the topic:
UC.onInitialised = function() {
topic.onConnectSuccess = function(data) {
// Send message as soon as topic is connected
topic.sendMessage(message_text);
}
topic.onSendMessageSuccess = function(message) {
// Log success
}
topic.onSendMessageFailed = function(message, errorMessage) {
When dialing into a multi-party conference on a conference server which supports Binary Floor
Control Protocol (BFCP), BFCP operations are available from the bfcp element of the Call
object. The application can request and release the floor, and can receive various callbacks that
provide information about the state of the conference. Other operations (including all BFCP Chair
operations) are not supported.
Clearly, requesting the floor is not something which an application should do automatically, but it
could do it in response to a user action which indicates that the user wants to request the floor.
A client requests the floor of the conference by calling call.bfcp.requestFloor(). Requesting the
floor does not mean that the floor is automatically granted, so the client application must wait
until it receives the onFloorRequestAccepted callback to indicate that it has been granted the
floor. To do this, it must first set the call.bfcp.onFloorRequestAccepted element to a function
which is called when the client receives the floor.
Once the floor request has been accepted, the client can stream video to the conference. Note
that floor requests are not necessarily granted immediately, or even very quickly - in a
conference with several participants, others may have requested the floor first, and the client
may be put in a queue. The client must be prepared to receive onFloorRequestAccepted at any
time after it has made the floor request.
A floor request can fail, in which case the client receives one of the callbacks:
Indicates that no floor control is available for this call (either because the conference is not under
the control of a BFCP conference server, or because the client is not allowed to make BFCP
requests).
onNoContentStreamAvailable
Indicates that the request was made before the client had any content stream to send to the
conference. In order to avoid this, a real client application would wait until it received a callback
indicating that a media stream was available before allowing the user to request the floor.
onFloorControlEnded
The client may also call releaseFloor to cancel a floor request which has not yet been granted. In
this case, the client receives an onFloorControlEnded callback instead of
onFloorRequestAccepted. However, since the floor control server may have already granted the
floor to the client when it receives the releaseFloor message canceling the floor request, the
client may receive the onFloorRequestedAccepted callback as well.
The conference server may take the floor away from the client at any time after it has granted it
the floor (for example, to give the floor to another conference participant, or to close the
conference). If this happens, the client receives an onFloorControlEnded callback. This is the
client’s opportunity to adjust its internal state and its user interface to indicate that it is no longer
streaming media to the conference.
The onFloorTaken callback may contain information about the user who has been granted the
floor, in the form of a UserInfo object containing a name and a uri. The client can update its user
interface to indicate who has the conference floor, but should not rely on this information being
available, and should check that the UserInfo parameter is not undefined.
If another user releases the floor, or is removed from the floor by the conference server, the
client receives an onFloorReleased callback. This is an opportunity for the client to update its UI
to indicate that the floor is not taken by any user. If the conference server removes one
participant from the floor and immediately grants the floor to another participant (other than the
client), then the client may receive only the onFloorTaken callback for the new floor owner, or it
may receive both onFloorReleased followed immediately by onFloorTaken. The client should
therefore not rely on receiving this callback, and should be ready to transition directly from one
participant having the floor to another participant having it, without necessarily going through an
intermediate state in which no one has the floor.
call.bfcp.onFloorRequestAccepted = function() {
// Update UI to show client has the floor
// Stream video-only, then
// Stop streaming video, then
call.bfcp.releaseFloor();
};
call.bfcp.onBFCPUnavailable = function() {
alert("No floor control possible");
};
call.bfcp.onNoContentStreamAvailable = function() {
alert("Tried to request floor before content ready");
};
call.bfcp.onFloorReleased = function() {
// Remove floor information from the UI
};
call.bfcp.onFloorControlEnded = function() {
// Update UI to show client no longer has the floor
};
call.bfcp.requestFloor();
The above skeleton program releases the floor as soon as it is granted it. A real program would
use the onFloorRequestAccepted callback to start streaming content, and would call
releaseFloor in response to a user command to do so.
In the case of a multi-node cluster, when failover occurs, and control of an existing call moves
from one node in the cluster to another, floor control requests and messages may be lost;
because of that, the floor control state on the client is resynchronized with that known to the
server, after a call has moved from one node to another. When this happens, the client may
receive an unexpected onFloorControlEnded or onFloorRequestAccepted notification. Clients do
not normally deal with this explicitly (their normal processing of these messages should be
enough), but developers should be aware that these messages may be received.
To end the session, the client application needs to call in to the Web Application, which can
terminate the session as described in the Ending the Session section.
As Fusion Client SDK is network-based, it is essential that the client application is aware of any
loss of network connection. When a network connection is lost, the server uses SIP timers to
determine how long to keep the session alive before reallocating the relevant resources. Any
application you develop should make use of the available callbacks in the Fusion Client SDK
API, and any other available technologies, to handle network failure scenarios.
If the connection to the network is re-established within 20 seconds, FCSDK attempts to re-
establish the connection to the Gateway.
During this process it will make fifteen attempts at the following intervals: 0.5s, 1s, 2s, 4s, 4s, 4s,
4s, 5s, 5s, 5s, 5s, 5s, 5s, 6s, 6s. A call to the onConnectionRetry(attempt, delayUntilNextRetry)
method of the UC object precedes each of these attempts.
When all reconnection attempts are exhausted, the UC object receives the onConnectivityLost
callback, and the retries stop.
If any of the reconnection attempts are successful, the UC object receives the
onConnectionReestablished callback, and retries stop.
FCSDK loses connection to the Gateway without losing its network connection
In this case, FCSDK attempts to automatically re-establish its connection to the Gateway.
During this process it will make fifteen attempts at the following intervals: 0.5s, 1s, 2s, 4s, 4s, 4s,
4s, 5s, 5s, 5s, 5s, 5s, 5s, 6s, 6s. A call to the onConnectionRetry(attempt, delayUntilNextRetry)
method of the UC object precedes each of these attempts.
When all reconnection attempts are exhausted, the UC object receives the onConnectivityLost
callback, and the retries stop.
If any of the reconnection attempts are successful, the UC object receives the
onConnectionReestablished callback, and retries stop.
In either case, if the application receives onConnectivityLost, it means that FCSDK is unable to
re-establish a connection to the Gateway, and the application itself must take some action; at the
very least it must inform the user that they are no longer connected.
The application can implement the onCallQualityChanged callback function on theCall object to
receive callbacks on the quality of the network during a call:
call.onConnectionQualityChanged = function(connectionQuality) {
// Show indication of quality
}
The connectionQuality parameter is a number between 0 and 100, where 100 represents a
perfect connection. The application might choose to show a bar in the UI, the length of the bar
indicating the quality of the connection.
The SDK starts collecting metrics as soon as it receives the remote media stream. It does this
every 5s, so the first quality callback fires roughly 5s after this remote media stream callback has
fired.
The callback then fires whenever a different quality value is calculated; so if the quality is perfect
then there will be an initial quality callback with a value of 100 (after 5s), and then no further
callback until the quality degrades.
Fusion Client SDK provides you with an iOS SDK and a network infrastructure which integrate
seamlessly with your existing SIP infrastructure.
Developing iOS applications using Fusion Client SDK requires Xcode 12 or later.
Information about the minimum version of iOS supported can be found in the Release Notes.
The Fusion Client SDK for iOS is made up of the following classes:
ACBClientAED
The iOS SDK reference documentation, including a full list of available methods and their
associated callbacks, is delivered in the docs.zip file. Open index.html to view the API
documentation.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
1. Open Xcode and choose to create a Single View Application, giving your project an
appropriate name. The following code samples use the example name
iOSFusionSDKSample.
2. Click the Build Phases tab, and expand the Link Binary with Libraries section by clicking on
the title.
4. Select the following iOS native dependencies from the iOS folder:
CoreVideo.framework
CoreMedia.framework
QuartzCore.framework
AudioToolbox.framework
AVFoundation.framework
UIKit.framework
Foundation.framework
CoreGraphics.framework
CFNetwork.framework
Security.framework
libicucore.dylib.
VideoToolbox.framework
Metal.framework
The dependencies you selected are now displayed in the Link Binary with Libraries section.
2. Expand the Link Binary with Libraries section by clicking on the title.
3. Click the + button. When the file explorer displays, click Add Other.
To ensure that your project compiles, you need to configure its Other Linker Flags setting:
2. Enter an appropriate term in the search field to find the Other Linker Flags setting, for
example Linker. Click Search. Other Linker Flags display in the Linking section.
-ObjC -lc++
Some users have found problems with build failing due to text relocation issues. To solve this,
also add the –read_only_relocs suppress flag to the above Other Linker Flags.
4. Position Independent Executables are incompatible with some codecs in the Fusion
Client SDK for iOS. In the Linking section, set Generate Position Dependent Executable
to Yes.
We can fetch FCSDK-iOS from GitHub and use it in our project by doing the following:
1. In your Xcode Project, select File > Swift Packages > Add Package
Dependency.
2. Follow the prompts using this url for LASDK-
https://github.com/cbajapan/acb-client-sdk.git
3. Choose which version you would like to checkout (i.e. 3.3.22)
Or you can clone the Package and use it locally using git clone . This is more work and not
recommended
To set up a project using the Swift Package we want to depend on the Swift Package at the root
level of your project.
1. Open your Xcode project and drag the unzipped Swift Package into the root level of your
project, typically you can do this directly under the project as shown in the image bellow
2. We want to make sure that the Swift Package has the little arrow next to the package in the
directory window. If yours does not look like this, close the Xcode project and re-open it.
This is a known Xcode bug.
Simulator Support
We now offer simulator support with FCSDK-iOS. It is simple to set up. The Simulator does not
support the use of the camera, therefore we need to give it a video to stream to your real device.
1. Create a short placeholder video (about 5 seconds long) and name it Simulator.mp4 .
2. Drag and Drop the .mp4 into the root level of your application like the picture shows bellow.
It is now set up. Now when you make calls with the simulator, you will see the video from your
real device and the mp4 will stream from the simulator.
If you are interested in building a Static Library instead of a Framework the process is the
same
The nature of Frameworks and Static Libraries cause us to use them in a very specific way.
Apple will not allow Embedded Frameworks to be released on the App Store in iOS. So that
means if you try and embed these 2 frameworks into your framework, it will inevitably fail. What
you want to do when it comes to depending on a framework within your framework is to link the
child framework to the parent framework, but DO NOT EMBED THEM. This will result in the
External Symbols being linked, but not the internal symbols. So, if you try to place the framework
you created in your application, you will get several errors saying that there are symbols missing.
How can this be resolved? You need to import those same 2 frameworks you depend on in your
framework into the Application you are building.
This seems like a lot of work, so we have done most of it for you with our Swift Package.
All you need to do is import the Swift Package into your framework as described above.
However, in order to use the Framework you are developing in an iOS application there are a
couple of steps you will need to follow.
1. Do as described above and import your framework that depends on FCSDK-iOS along with
FCSDK-iOS into the iOS application. OR
2. Let Swift Package Manager handle all of that for you.
You will want to create a Swift Package in order to distribute your XCFramework.
1. Open Terminal
2. Create a directory - you can name it something like my-framework-kit with mkdir
MY_DIRECTORY
import PackageDescription
I will describe what this file does - What we are mostly interested in is the Package
1. Name
2. Products
3. Dependencies
4. Target
Name is not very important, but typically this is the name of the directory you made
Products consists of the Libraries name; we also need to specify this Library as a Static
Library, and we want to tell it about our Target that we define in Packages final property.
Dependencies are any code that you want to bring in from a url that is an internal or external
resource, so basically, other Swift Packages. Here we are depending on FCSDK-iOS
Creating an XCFramework
Note
You need to make sure that in your project in the Xcode Build Settings these 2 settings are set
accordingly SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
#!/bin/zsh
xcodebuild archive \
-project YourProject.xcodeproj \
-scheme YourProjectTarget \
-archivePath target/xcodebuild/device.xcarchive \
-destination "generic/platform=iOS" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
#Time to create an XCFramework with device and simulator for a Static Library
xcodebuild -create-xcframework \
-library build/device.xcarchive/Products/usr/local/lib/libYourFramework.a \
-headers build/device.xcarchive/Products/usr/local/include \
-library build/simulator.xcarchive/Products/usr/local/lib/libYourFramework.a \
-headers build/simulator.xcarchive/Products/usr/local/include \
-output build/YourFramework.xcframework
If you want to create an XCFramework from a Framework instead replace the above code with
something like this
xcodebuild -create-xcframework \
-framework
build/device.xcarchive/Products/Library/Frameworks/YourFramework.framework \
-framework
build/simulator.xcarchive/Products/Library/Frameworks/YourFramework.framework \
-output build/YourFramework.xcframework
Then you can just run the shell script in it’s directory sh build.sh You should have an
XCFramework inside of the build folder indicated in -output
Importing ACBClientSDK
Note
@import ACBClientSDK;
The application accesses the API initially via a single object, ACBUC. To set up all the
functionality to which the user has access, the application needs to obtain a session ID from the
Web Application (see the Creating the Web Application section), and initialize the ACBUC object
using it. Once it has received the Session ID, the client application must call the
ucWithConfiguration method on the ACBUC:
(void) initialize
{
NSString* sessionId = [self getSessionId];
ACBUC* uc = [ACBUC ucWithConfiguration:sessionId delegate:self];
[uc startSession];
}
(void) ucDidStartSession:(ACBUC *)uc
{
}
The delegate (in this case self) must implement the ACBUCDelegate protocol. Once the session
has started, FCSDK will call the delegate method ucDidStartSession, and the application can
make use of the ACBUC object. (If the session does not start, FCSDK will call one of the
delegate’s error methods.)
There is an alternative version of ucWithConfiguration for use if STUN is needed, which takes as
an additional parameter, an NSArray* of STUN servers, each member an NSString in the form
stun:stun.1.google.com:19302.
STUN servers are not necessary if the Gateway is not behind a firewall, so that Network Address
Translation is not needed. You can provide your own STUN server instead of the public Google
one above; and you can provide more than one in the array, in which case they will be tried in
sequence until FCSDK finds a working one.
Once the application has initialized the ACBUC object, it can retrieve the ACBClientPhone
object. It can then use the phone object to make or receive calls, for which it returns
ACBClientCall objects. Each one of those objects has a delegate for notifications of errors and
other events.
As of iOS 8.2, the iOS simulator does not support video and audio input, so in order to fully test
your application with audio and video, you will have to deploy it to a real device.
On iOS 7.0 and higher, your application needs to ask the end user for permission to use the
microphone and camera before they can make or receive calls. Because the microphone and
camera permissions in iOS function at an application-level and not per call, you need to consider
the most appropriate time to ask the end user for their permission. iOS remembers the answer
they provide until your application is uninstalled or the permissions are reset in the iOS Settings.
The end user can also change the microphone and camera permissions for your application in
iOS Settings.
The iOS SDK provides a helper method to request access to the microphone and camera:
ACBClientPhone requestMicrophoneAndCameraPermission. This method delegates to the iOS
permission APIs, and you should typically call it before making or receiving calls. The first time
you call this method, it displays an individual alert for each requested permission. Subsequent
calls do not display an alert unless you have reset your privacy settings in iOS Settings.
When subsequently making or receiving a call, the iOS SDK checks whether the user has given
the necessary permissions. For example, if you make an audio-only outgoing call, the end user
only needs to have granted permission to use the microphone; if you want to receive an
incoming audio and video call, the end user needs to have granted permission to use the
microphone and camera.
Making a Call
In the following example, the application makes a call (using createCallToAddress on the
ACBClientPhone object) as soon as the session has started (see the Initializing the ACBUC
Object section):
You can change the values of the withAudio and withVideo parameters to make an audio-only or
video-only call. Valid values are:
ACBMediaDirectionNone
ACBMediaDirectionSendOnly
ACBMediaDirectionReceiveOnly
ACBMediaDirectionSendAndReceive
Receiving a Call
You can change the values of the parameters to answer the call as audio-only or video-only.
Valid values are:
ACBMediaDirectionNone
ACBMediaDirectionSendOnly
ACBMediaDirectionReceiveOnly
ACBMediaDirectionSendAndReceive
The older form, answerWithAudio:video:, which took two boolean values, is now deprecated.
The audio and video options specified in the answer affect both sides of the call; that is, if
the remote party placed a video call and the local application answers as audio only, then
neither party sends or receives video.
If your application plays its own ringing tone, please note that the iOS SDK makes calls to
the AVAudioSession sharedInstance object when establishing a call. For this reason, we
recommend waiting until you receive a call status of ACBClientCallStatusRinging (from
ACBClientCallDelegate didChangeStatus) before calling AVAudioSession sharedInstance
methods.
If you require the application to continue receiving calls when in background or suspended
mode, you need to add the following values to the Required background modes key in the
application’s plist file:
In order to show video during a call, the application can set the videoView on the ACBClientCall
object, and the previewView on the ACBClientPhone object. Each property is a UIView object.
The videoView is used to render the remote party’s video stream and is mandatory for a two-way
video call. The previewView is an optional addition that renders the local party’s video stream as
it is being captured; this is the same stream that the remote party receives.
Initializing the videoView and previewView is optional and can be done at any time. If there are
calls in progress when the application sets the properties, the changes take effect when the next
video call is made.
When there is no video stream being sent or received, the videoView and previewView do not
render any frames; video is only displayed when streaming.
Ending a Call
If the user ends the call, the client application should call the ACBClientCall object’s end method.
To receive notification that the remote party has terminated the call, the application must monitor
the state of the call (see the Monitoring the State of a Call section) for the
ACBClientCallStatusEnded state.
During a call the application can mute or unmute the local audio and video streams. Muting the
stream stops that stream being sent to the remote party; the user still receives any stream that
the remote party sends.
To mute either stream, use one, or both, of the enableLocalAudio and enableLocalVideo
methods of the call:
(void) muteButtonPressed:(UIButton*)button
{
[self.call enableLocalAudio:NO];
[self.call enableLocalVideo:NO];
}
Each method takes a single boolean parameter. To restore media, call enableLocalVideo or
enableLocalAudio with the parameter YES.
During a call the application can put a call on hold (for example, in order to make or receive
another call). Placing the call on hold pauses both the stream sent by the user and the stream
sent by the remote party; only the party who placed the call on hold can resume it.
(void) holdButtonPressed:(UIButton*)button
{
[call hold];
}
(void) resumeButtonPressed:(UIButton*)button
{
[call resume];
}
DTMF Tones
Once a call is established, an application can send DTMF tones on that call by calling the
playDTMFCode method of the ACBClientCall object:
The comma indicates that there should be a two second pause between the 3 and the * tone.
The second parameter is a boolean which indicates whether the application should play the
tone back locally so that the user can hear it.
Applications developed with Fusion Client SDK for iOS do not support multiple simultaneous
calls.
The Fusion Client SDK supports configuring the captured, and therefore sent, video resolution
for video calls. The application can select one of a set of video resolutions, and apply it to the
capture device. It can also configure the frame rate for capture. When it specifies a resolution
and frame rate, FCSDK makes every effort to match those values where hardware allows.
The application can get a list of possible resolutions from the ACBClientPhone object using the
recommendedCaptureSettings method:
The array returned by this method contains an ACBVideoCaptureSetting object for each
recommended setting. Each ACBVideoCaptureSetting specifies a resolution and a
recommended frame rate for that resolution.
iPhone 5s
iPad Mini 2
640x480 30
iPad Mini 3
All other
iOS12-
1280x720 30
compatible
devices
If you set the resolution of frame rate to values higher than these, then the provided resolution or
frame rate is the minimum of the requested value and the maximum value for the particular
device.
The application can set the captured video resolution using the preferredCaptureResolution
property of the ACBClientPhoneobject. The value supplied must be one of the resolutions
presented in recommendedCaptureSettings, as described the Enumerating the Possible
Resolutions section
uc.phone.preferredCaptureResolution = ACBVideoCaptureResolution352x288;
The video capture resolution only applies for the next call made with the phone object, and it
does not affect calls currently in progress.
The application can set the captured video frame rate using the preferredCaptureFrameRate
property of the ACBClientPhoneobject:
uc.phone.preferredCaptureFrameRate = chosenSetting.frameRate;
uc.phone.preferredCaptureFrameRate = 20;
The video capture frame rate only applies for the next call made with the phone object, and it
does not affect calls currently in progress.
Dial Failures
FCSDK does not call the ACBClientCallDelegate failure methods (didReceiveDialFailure and so
on) for failures caused by a timeout. This results in the client seeing the Trying to call… dialog,
despite the call being inactive. To avoid this, handle these timeout errors using the status
delegate methods; examples can be found in the Monitoring the State of a Call section and in
particular to the callback:
By default, during video calls, FCSDK uses the front camera. The application can change this by
calling the setCamera method of ACBClientPhone.
AVCaptureDevicePositionBack
AVCaptureDevicePositionFront.
The camera setting persists between calls; if the back camera is enabled during a video call, the
next video call will also use that camera.
The method can be called at any time; if there are no active video calls, the value takes effect
when a video call is next in progress.
When the user presses the Home button, presses the Sleep/Wake button, or the system
launches another application, the foreground application transitions to the inactive state and then
to the background state. If you are currently streaming video from your application, this is
suspended when the application goes into background mode, and automatically resumes when
the application returns to the foreground. Audio continues to be streamed when an application
goes into background mode.
If you mute the video when in background mode, you must unmute in order to resume capture
and streaming.
Each state change fires the call:didChangeStatus: delegate method. As the outgoing call
progresses toward being fully established, the application receives a number of calls to
didChangeStatus, containing one of the ACBClientCallStatus enumeration values each time.
The application can adjust the UI by switching on the value of the status parameter, to give the
user suitable feedback, for example by playing a local audio file for ringing or alerting:
The application initially accesses the API via a single object, ACBUC, from which other objects
can be retrieved. ACBUC has an attribute named aed, which is the starting point for all
Application Event Distribution operations.
2. Access the aed attribute to create or connect to an ACBTopic, supplying the delegate from
the previous step.
4. Disconnect from the topic when you no longer want to receive AED notifications.
The name of the topic is an NSString, and the expiryTime parameter is a time in minutes. A topic
created with an expiry time will be automatically removed from the server after the topic has
been inactive for that time. When created without an expiry time, the topic exists indefinitely, and
the application must delete it explicitly (see the Disconnecting from a Topic section). The
delegate is an object conforming to the ACBTopicDelegate protocol.
Either of these creates a client-side representation of a topic and automatically connects to it. If
the topic already exists on the server, it connects to that topic; if the topic does not already exist,
it creates it.
didConnectWithData
After connecting to the topic, the delegate will receive a didConnectWithData callback. (In the
case of failure, it will receive a didNotConnectWithMessage callback with a message parameter
(an NSString).) The didConnectWithData callback has a single data parameter containing all the
data currently associated with the topic.
The data parameter is an NSDictionary which contains a value with the key data, which is an
NSArray of NSDictionary objects, each of which contains a single data item with members called
key and value. The application can iterate through the data items to display them to the newly
connected user:
(void)topic:(ACBTopic*)topic didConnectWithData:(NSDictionary*)data
{
//topic data is an array containing all our key/value pairs
NSArray *topicData = [data objectForKey:@"data"];
if([topicData count] > 0)
{
//we can show our users the data in the topic as follows
for(int i = 0; i < [topicData count] ; i++)
{
NSString* keyField = [[topicData objectAtIndex:i] valueForKey:@"key"];
NSString* valueField = [[topicData objectAtIndex:i]
valueForKey:@"value"];
// Display key and value
}
You can either disconnect from the topic without destroying it:
[topic disconnectWithDeleteFlag:FALSE];
or delete the topic from the server, which will also disconnect any other subscribers:
[topic disconnectWithDeleteFlag:TRUE];
When you delete the topic by calling disconnectWithDeleteFlag:TRUE, you will receive a
didDeleteWithMessage callback, followed by a topicDidDelete callback.
topicDidDelete
All clients connected to the topic receive a topicDidDelete callback when the topic is deleted from
the server, either as a result of any client deleting it, or as a result of the topic expiring on the
server (see the Creating and Connecting to a Topic section for details of topic expiry). Once a
topic has been deleted, the client should not call any of that topic’s methods (which will fail in any
case), and should consider itself unsubscribed from that topic. If a topic with the same name is
subsequently created, it is a new topic, and the client will not be automatically subscribed to it.
Having submitted the data, the delegate receives either a didSubmitWithKey or (in the case of
failure) a didNotSubmitWithKey callback. Both callbacks contain the key and value which were
submitted (successfully or unsuccessfully). The didNotSubmitWithKey callback also contains a
message parameter giving more details of the failure The didSubmitWithKey callback also
In the case of a successful submission, the delegate also receives a didUpdateWithKey callback.
didUpdateWithKey
A client receives a didUpdateWithKey callback when any client connected to the topic makes a
change to a data item on that topic. The callback contains the key, value, and version
parameters detailed previously (value contains the new value), and an additional deleted
parameter, which will be TRUE if the data item has been deleted from the server (see the
Deleting Data from a Topic section).
The client can delete the data item from the topic by calling:
[topic deleteDataWithKey:@"key_one"];
All clients subscribed to the topic will also receive a didUpdateWithKey callback, with the deleted
parameter set to TRUE.
didReceiveMessage
Threading
The application must make all method invocations on the SDK, even to access read-only
properties, from the same thread. This can be any thread, and not necessarily the main thread of
the application. Internally, the SDK may use other threads to increase responsiveness, but any
delegate callbacks will occur on the same thread that is used to initialize the SDK.
Self-Signed Certificates
If you are connecting to a server that uses a self-signed certificate, you need to add that
certificate, and the associated CA root certificate, to the keychain on your client.
You can obtain the server certificate and CA root certificate through the FAS Administration
screens. The FAS Administration Guide explains how to view and export certificates. You need
to extract the HTTPS Identity Certificate (server certificate) and the Trust Certificate (CA root
certificate) that has signed your server certificate.
Once you have exported and downloaded the two certificates, you need to copy them to your
client. Please follow the user documentation for your device to install the certificates.
You should then view the installed server certificate through the appropriate tool (iOS Settings-
>General->Profiles or OSX Keychain) and confirm that the server certificate is trusted. If it is,
then your application should connect to the server.
Alternatively, you can use the acceptAnyCertificate method of the ACBUC object before calling
startSession, although this should only be used during development:
Since iOS 9, you also need to add a setting to your application’s plist file to allow connection to a
server using self-signed certificates. Set Allow Arbitrary Loads under App Transport Security
Settings to YES.
Apple require that apps submitted to the Apple store support IPv6-only networks, and you should
test this during development; see:
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/Netwo
rkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingforth
eIPv6Transition.html
Neither Media Broker nor FAS support IPv6 directly; however, you can configure Media Broker to
give an IPv6 public address to the client, and then you can access both FAS and Media Broker
through a NAT64 router. Apple laptops support providing a NAT64 Wi-Fi hotspot, as long as you
are able to connect to your network through another interface such as an Ethernet cable - for
details on enabling this, see the Test for IPv6 DNS64/NAT64 Compatibility Regularly section in
the above link.
To configure Media Broker to give IPv6 addresses to the client, edit the Media Broker’s settings:
2. For each of the current public addresses click add, then enter an IPv6 equivalent in the
public address.
If using an Apple laptop hotspot, then the IPv6 address equivalent starts with
64::ff9b::
and is followed by the hexadecimal version of the IPv4 address. For example c0a8:131d is the
equivalent of 192.168.19.29
Apple sometimes require testing an app in full during submission, in which case a public NAT64
is required - contact support for details on how to implement this.
Bluetooth Support
The user can set the active audio device (speaker and microphone) for an iOS device, and
FCSDK calls will use this setting by default. However, this behavior may not be appropriate while
an FCSDK application is running; and in particular, the default behavior does not allow the call to
switch to an alternative device if the active device fails (a particular problem with Bluetooth
devices). The application can override the default behavior using the ACBAudioDeviceManager
class; a single instance of this class is available on the ACBClientPhone object which controls
the call. While this is in use, the application can:
Define which audio output on the phone should handle the audio
Define a default audio output on the phone, which will handle the audio if the preferred
device is interrupted.
Determine which of the phone’s audio outputs currently handles the audio
This class has been added specifically to support the use of Bluetooth headsets, and we expect
this to be its main use; accordingly, the examples assume that this is how it is being used.
However, an application could also use this class to manage the audio output to the
speakerphone, the internal speaker, and an external headphone set, and to explicitly exclude the
use of Bluetooth headsets with the calls made by the application.
[uc.phone.audioDeviceManager start];
An appropriate place to do this is during initialization of the object which is to control the call.
In order to return to the iOS device’s default behavior without ending the call, the application can
call stop:
[uc.phone.audioDeviceManager stop];
While the audio device manager is active the application must not call the setCategory method
of the call’s AVAudioSession object. Doing so can cause unexpected behavior.
The application can set the preferred device for the call:
[uc.phone.audioDeviceManager setAudioDevice:
(ACBAudioDevice*) ACBAudioDeviceBluetooth];
The argument to the method must be one of the members of the ACBAudioDevice enumeration:
ACBAudioDeviceSpeakerphone
Audio goes to the loudspeaker in the phone, and is audible to others in the vicinity. Audio input is
from the phone’s internal microphone.
ACBAudioDeviceWiredHeadset
Audio goes to a device attached to the jack in the phone. If this device has a microphone, that is
used for audio input.
ACBAudioEarpiece
Audio goes to the internal speaker, and is received from the internal microphone. The user will
have to hold the phone to their ear during the call.
ACBAudioDeviceBluetooth
The application has no preference, and accepts the default behavior of the iOS device.
If the preferred device is available when the application calls setAudioDevice, the call starts
using that device; otherwise, there is no immediate change, but if it later becomes available (the
Bluetooth device is switched on or is otherwise recognized), then the audio switches to this
device.
The application can set a fallback device in case the preferred device is unavailable:
[uc.phone.audioDeviceManager setDefaultDevice:
(ACBAudioDevice*) ACBAudioDeviceEarpiece];
The argument is one of the values from the ACBAudioDevice enumeration (see the Setting the
Preferred Device section).
Setting the default device establishes a fallback option in case the preferred device is temporarily
unavailable. A common use would be:
[uc.phone.audioDeviceManager setAudioDevice:
(ACBAudioDevice*) ACBAudioDeviceBluetooth];
[uc.phone.audioDeviceManager setDefaultDevice:
(ACBAudioDevice*) ACBAudioDeviceEarpiece];
which would establish the Bluetooth headset as the preferred device, with the normal phone
internal speaker and microphone as a fallback. With these settings in operation:
1. The call starts, but no Bluetooth headset is available. The call is sent to the internal speaker
and microphone.
2. The Bluetooth headset is switched on. The phone switches the audio to the headset, and
the user can put the phone down and continue the call.
3. The headset fails (perhaps the battery becomes too low). The application switches the call
back to the internal speaker and microphone.
If the default device is also unavailable, the audio will be sent to whatever has been set as the
active device on the phone (that is, it will fallback to the iOS default behavior).
The resulting array contains members of the ACBAudioDevice enumeration, taken from the
available inputs known to the AVAudioSession.
It can also find which device is currently set as the preferred audio device:
This will work whether the preferred device has been set explicitly (using setAudioDevice) or not.
As the iOS SDK is network-based, it is essential that the client application is aware of any loss of
connection. Fusion Client SDK does not dictate how you implement network monitoring;
however, the sample application uses the SystemConfiguration framework.
Depending on the nature of the issues with the network, the client application should react
differently.
If any of the reconnection attempts are successful, the ACBUCDelegate receives the
ucDidReestablishConnection callback.
The retry intervals, and the number of retries attempted by the SDK are subject to change in
future releases. Do not rely on the exact values given above.
If the issues with the network are caused by a temporary loss of connectivity (for example, when
moving between two Wi-Fi networks, or from a Wi-Fi network to a cellular data connection), the
client application should not log out from the session and log back in (as described in the
Reacting to Network Loss section), as all session state will be lost.
To avoid this, the client application should register with iOS to receive notification of changes in
network reachability. When iOS notifies the client application that the network has changed, the
application should pass these details to the ACBUC instance.
When the client application starts, it should check for network reachability. When the network is
reachable, the application calls ACBUC setNetworkReachable:YES; until this call is made, the
application does not attempt to create a session.
If the network reachability drops after a session has been established, the client application
needs to call ACBUC setNetworkReachable:NO.
If the network reachability changes from a cellular data connection to a Wi-Fi network, or vice
versa, the client application should call ACBUC setNetworkReachable:NO followed by ACBUC
setNetworkReachable:YES to disconnect from the first network and re-register on the second.
The inboundQuality parameter is a number between 0 and 100, where 100 indicates perfect
quality. The application might choose to show a bar in the UI, the length of the bar indicating the
quality of the connection.
The SDK starts collecting metrics as soon as it receives the remote media stream. It does this
every 5s, so the first quality callback fires roughly 5s after this remote media stream callback has
fired.
The callback then fires whenever a different quality value is calculated; so if the quality is perfect
then there will be an initial quality callback with a value of 100 (after 5s), and then no further
callback until the quality degrades.
This method has been implemented in the sample app (iOSFusionSDKSample), and logs a
console message ‘Received SSRC information for AUDIO XXX and VIDEO YYY’. (In
PhoneViewController.m of the sample). There’s also a few lines of the code commented out in
PhoneViewController.m following this call to logging; uncommenting them and building/testing
the sample will pop up an alert showing the audio and video SSRC(s) when they become
available.
This will be triggered when a provisional response is received as part of call establishment. The
reason parameter equates to the SIP reason phrase.
ACBClientCallProvisionalResponseRinging ;
ACBClientCallProvisionalResponseBeingForwarded ;
ACBClientCallProvisionalResponseQueued ;
ACBClientCallProvisionalResponseSessionProgress
The method has been implemented in the sample app (iOSFusionSDKSample); on receiving a
provisional response, an alert will pop up with details of the provisional.
Fusion Client SDK provides you with an Android SDK and a network infrastructure which
integrate seamlessly with your existing SIP infrastructure.
To develop Android applications using Fusion Client SDK, your system will need to conform to
the system requirements listed at http://developer.android.com/sdk/index.html.
Information about the minimum supported version of Android can be found in the Release
Notes.
The Android API reference documentation, including a full list of available methods and their
associated callbacks, is delivered in the docs directory. Open index.html to view the API
documentation.
The structure of an Android application revolves around different Activity objects, and the sample
code included with the FCSDK Android SDK shows a typical structure. In the sample code, there
is a LoginActivity, which gets the session token from the server (see the Creating the Session
section); a Main Activity, which creates the UC object and connects to the session (see the
Creating the UC Object section); and an InCallActivity, which makes and receives calls, and
works with those calls while they are in progress. AED operations (see the Adding Application
Event Distribution section) are centralized in the AEDFragment and AEDTopicManager classes.
We recommend that Android applications which make use of the FCSDK should separate their
operations similarly; however, for simplicity this separation is not shown in the code snippets in
the following section - see the sample code.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
2. Add the android-sdk-release.aar file to your project. This is found in the sample application’s
libs directory or in the android-sdk zip file.
legacy-support-v4.jar
The legacy-support-v4.jar is required if you want to write applications that use newer Android
features but also support older devices which do not support those features by default.
4. In order to allow your project to access the required features on Android devices, include the
following permissions in your AndroidManifest.xml file:
android.permission.INTERNET
android.permission.RECORD_AUDIO
android.permission.CAMERA
android.permission.MODIFY_AUDIO_SETTINGS
To set up all the functionality which the user has access to, the client application must obtain a
session ID from the Web Application (see the Creating the Web Application section), and create
a UC object using it. You create a UC object from a single object, UCFactory:
In addition to the session token, createUc takes an android.content.Context object, and an object
which implements the UCListener interface. When the session starts, the listener receives an
onSessionStarted callback.
If the application saves the session token in the instance state as soon as it receives it from the
Web Application, it can create or re-create the UC object as necessary in the onCreate method
There is an alternative version of createUc, which takes a list of STUN servers in addition:
STUN servers are not necessary if the Gateway is not behind a firewall, so that Network Address
Translation is not needed. You can provide your own STUN server instead of the public Google
one above. You can provide more than one in the array, in which case FCSDK tries them in
sequence until it finds a working one.
Some Android devices are not able to properly handle a request to renegotiate the session in the
middle of a call. To avoid this issue you can switch off the local support for renegotiation prior to
calling startSession by using the following call
uc.setSupportsRenegotiation(false);
The result will be that the server will handle the renegotiation using the information supplied by
the device at the start of the call.
Once the application has created the UC object, it can use it to obtain an instance of the Phone
and AED objects.
The application uses the Phone object to make or receive calls, represented by Call objects.
Objects in the API implement the listener pattern which enables an application to be informed of
the outcome of operations and other events.
The application can use the AED object to create AED Topics (see the Adding Application Event
Distribution section).
Making a Call
Call call;
public void onSessionStarted()
{
Phone phone = uc.getPhone();
phone.addListener(this);
call = phone.createCall(callee, audio, video, listener);
}
The callee parameter is a String containing the address to make the call to.
You can use the values of the audio and video parameters to make an audio-only or video-only
call. Valid values are members of the MediaDirection enumeration:
NONE
SEND_ONLY
RECEIVE_ONLY
SEND_AND_RECEIVE
The listener parameter is an object implementing the CallListener interface, which receives
notifications of events of interest on the call (such as when it is completely set up).
(The above code makes a call as soon as the session has started. More typically, the application
starts a new Activity to gather the callee’s number in response to the session starting, and
another new Activity to make the call, once the callee’s number is known. See the sample code
included in the Android SDK for a more realistic architecture.)
The older form in which audio and video were boolean parameters is now deprecated.
Receiving a Call
FCSDK invokes the PhoneListener onIncomingCall method when it receives an incoming call,
passing a Call object as a parameter. The application can answer the incoming call by calling its
answer method:
You can use the values of the audio and video parameters to answer the call as audio-only or
video-only. Valid values are members of the MediaDirection enumeration:
NONE
SEND_ONLY
RECEIVE_ONLY
SEND_AND_RECEIVE
The audio and video options specified in the answer will affect both sides of the call; that is, if the
remote party placed a video call and the local application answers as video only, then neither
party will send or receive audio. Adding a CallListener before answering the call allows the
application to receive a notification when the call is completely set up, so that it can render video
and audio streams.
The older form in which audio and video were boolean parameters is now deprecated.
The application creates a VideoSurface using the createVideoSurface method of the Phone
object, passing in the android.content.Context, the required dimensions (an
android.graphics.Point object), and an object implementing VideoSurfaceListener. Initializing the
The video view renders the remote party’s video stream and is mandatory for a two-way video
call. The preview view renders the local party’s video stream as it is being captured; this is the
same stream that the remote party will receive.
If there are calls in progress when these properties are set, the changes will take effect
immediately and endure for future calls. If there are no active video calls, the change will take
effect when a video call is next in progress.
When there is no video stream being sent or received, the video view and preview view render a
full frame of green. Video appears only when there is video being streamed.
The application can set the camera to use as the local video source on the Phone object. See
the Switching between the Front and Back Cameras section.
Ending a Call
If the user ends the call, the client application should call the Call object’s end method.
CallListener.onRemoteMediaStream will also be called at the end of a call (with argument null),
as well as at the beginning of the call.
During a call, the application can mute and unmute the local audio and video streams separately.
Muting the stream stops that stream being sent to the remote party. The remote party’s stream
continues to play locally, however.
To mute either stream, use the enableLocalAudio and enableLocalVideo methods of the Phone
object.
void onMuteButtonPressed()
{
phone.enableLocalAudio(false);
phone.enableLocalVideo(false);
}
To restore media, call the same method with the parameter set to true.
This will affect all calls and persists to subsequent calls. When a call starts, the streams will be
muted as per the current Phone setting.
If you need to allow other applications to make use of the camera during your call, you will have
to make sure that the camera is released from your application, otherwise you will not be able to
use the camera again after you regain the application focus.
In order to release the camera, use the method Phone.releaseCamera() on your Phone object
after muting the video as described above. When you want to resume using the camera, it is
sufficient to re-enable the local video in the usual way, again as described above.
Sample code:
void onUnmuteVideoRequest()
{
phone.enableLocalVideo(true);
}
The application can put a call on hold (for example, in order to make or receive another call).
Placing the call on hold pauses the stream sent by the user and the stream sent by the remote
party; only the party who placed the call on hold can resume it.
void holdButtonPressed()
{
call.hold();
}
void resumeButtonPressed()
{
call.resume()
}
An application can send DTMF tones on the call by calling the playDTMFCode method on the
Call object.
The first parameter to this call is a String, which can be either a single tone, (for example, 6), or a
sequence of tones (for example, #123*456). Valid values for the tones are those characters
conventionally used to represent the standard DTMF tones: 0123456789ABCD#*. A comma
character inserts a two-second pause into a sequence of tones.
The second parameter should be true if you want the tones to be played back locally, so that the
user of the application can hear them.
Applications developed with Fusion Client SDK for Android do not support multiple
simultaneous calls:
The Fusion Client SDK Android SDK supports configuring the captured, and therefore sent,
video resolution for video calls. The application can select one of a set of video resolutions, and
apply it to the capture device. It can also configure the frame rate for capture. When it specifies a
resolution and frame rate, FCSDK makes every effort to match those values where hardware
allows.
The application can get a list of possible resolutions from the Phone object via the
getRecommendedCaptureSettings() method:
List<PhoneVideoCaptureSetting> recommendedSettings =
phone.getRecommendedCaptureSettings();
The List returned by this method contains a PhoneVideoCaptureSetting object for each
recommended setting. Each PhoneVideoCaptureSetting provides a resolution (from its
getResolution method) and a recommended frame rate (from its getFramerate method) for that
resolution.
The application can set the captured video resolution using the setPreferredCaptureResolution
method of the Phone object. The single parameter is one of the PhoneVideoCaptureResolution
enumeration:
phone.setPreferredCaptureResolution(PhoneVideoCaptureResolution.RESOLUTION_640x480
Alternatively, you can get it from a PhoneVideoCaptureSetting value (see the Enumerating the
Possible Resolutions section):
phone.setPreferredCaptureResolution(setting.getResolution());
The video capture resolution will only apply to the next call made with the Phone object; it does
not affect calls currently in progress.
The application can set the captured video frame rate using the setPreferredCaptureFrameRate
method of the Phone object. It takes a single integer parameter:
phone.setPreferredCaptureFrameRate(20);
The video capture frame rate only applies to the next call made with the Phone object; it does
not affect calls currently in progress.
The camera setting persists between calls; that is, if you enable the rear-facing camera during a
video call, the next video call will also use that camera.
The method can be called at any time; if there are no active video calls, the value will take effect
when a video call is next in progress.
The FCSDK android sample app checks to see how many cameras there are on the device. If
there is only 1 camera, it uses it, whether it is front-facing or back-facing. If there is more than 1
camera, it uses the first front-facing camera it can find. If there is more than 1 camera on the
device, the sample app adds a Camera Selection menu to the Options Menu to allow the user
to select between the front-facing and back-facing camera.
When the user presses the Home button, presses the power button, or the system launches
another application, the foreground application transitions to the inactive state and then to the
background state. If you are currently streaming video from your application, this continues when
the application goes into background mode.
During call setup, the call transitions through several states, from the initial setup to being
connected with media available (or failure). You can monitor these states by setting the
CallListener and implementing the onStatusChanged method.
You can also call the getCallStatus method on the Call object to get the status of the call.
UNINITIALIZED The Call object has been created, but not initialized
The UC object also provides access to the AED object, which is the starting point for all
Application Event Distribution (AED) operations.
4. Call methods on the Topic object (apart from disconnect) to change data on the topic or
send messages to other subscribers to the topic.
If it succeeds, the TopicListener receives the onTopicConnected notification. In the notification, itl
receives a Topic object representing the topic, and a Map containing the data items (in the form
of key-value pairs) which are currently associated with the topic. The application can add data,
disconnect, send messages, and so on, by calling methods on the Topic object.
You should give each topic you create a unique name. If the topic already exists on the server,
you will simply be connected to it.
Topic Expiry
There is another version of createTopic which takes an expiry time in addition to the topic name
and the listener. This allows you to set an expiry time for the topic (in minutes); if the topic is
inactive for that amount of time, the server automatically deletes it. A topic created without an
expiry time remains on the server indefinitely, until explicitly deleted by a subscriber (see the
Unsubscribing from a Topic section).
onTopicConnected
After connecting to the topic, the listener receives an onTopicConnected callback. (In the case of
failure, it will receive an onTopicNotConnected callback, containing the topic and an error
message.) The onTopicConnected callback has two parameters, the Topic object, and a Map
which contains an object (under the key data), which represents all the data currently associated
with the topic. This object is a List of LinkedHashMap objects, each of which contains the data
item’s key and value. The application can iterate through the data items to display them to the
newly connected user:
topic.disconnect(true);
If you choose to merely unsubscribe from the topic without deleting it (by calling
topic.disconnect(false)), then you will not see any notifications that the unsubscribe has been
successful. Nor will other subscribers receive any notification that you have unsubscribed.
onTopicDeletedRemotely
All clients connected to the topic receive a onTopicDeletedRemotely callback when the topic is
deleted from the server, whether as a result of any client deleting it, or of the topic expiring on the
server (see the Topic Expiry section for details of topic expiry). Once a topic has been deleted,
the client should not call any of that topic’s methods (which will fail in any case), and should
consider itself unsubscribed from that topic. If a topic with the same name is subsequently
created, it is a new topic, and the client will not be automatically subscribed to it.
topic.submitData("foo", "bar");
When you submit data to the topic, users connected to the topic receive an onTopicUpdate
notification, containing the data which you have submitted.
onTopicUpdated
A client receives a onTopicUpdated callback when any client connected to the topic makes a
change to a data item on that topic. The callback contains the key, value, and version
parameters detailed previously (value contains the new value), and an additional deleted
parameter, which will be true if the data item was deleted from the server (see the Deleting Data
from a Topic section).
The client application can delete data from the topic by calling the deleteData method, passing in
the key under which the data is stored on the topic.
topic.deleteData("foo");
The application can send a message to a topic using the sendAedMessage method.
topic.sendAedMessage("Hello World!");
If the message is sent successfully, you receive an onTopicSent notification; otherwise, you
receive onTopicNotSent. Other users connected to the topic receive an onMessageReceived
notification.
onMessageReceived
The TopicListener will receive an onMessageReceived callback whenever any client connected
to the topic (including itself) sends a message to the topic. It contains the topic parameter, and
the message parameter containing the text of the sent message.
Self-Signed Certificates
If you are connecting to a server that uses a self-signed certificate, you have two options:
2. Add the server certificate and the associated CA root certificate to the Credential Storage on
your client.
You can obtain the server certificate and CA root certificate through the FAS Administration
screens. The FAS Administration Guide explains how to view and export certificates. You need
to obtain the HTTPS Identity Certificate (server certificate) and the Trust Certificate (CA root
certificate) that has signed your server certificate.
You should then view the installed server certificate through the appropriate tool (Android
Settings->Security->Credential Storage) and confirm that the server certificate is trusted. If it
is, then your application should be able to connect to the server.
Bluetooth Support
An FCSDK application can support Bluetooth devices using the AudioDeviceManager class; a
single instance of this class is available on the Phone object which controls the call. While this is
in use, FCSDK will:
Automatically send audio output to a Bluetooth headset when one becomes available.
Send audio output to a wired headset if one is available and there is no Bluetooth device
connected.
Send audio output to another audio device if neither a headset nor a Bluetooth device is
available.
Receive notifications when devices become, or cease to be, available (such as when a
wired headset is plugged in or unplugged, or when a Bluetooth device goes in or out of
range), in order to change the above behavior. See the Using the Listener section.
Define which audio output on the phone should handle the audio if neither a Bluetooth
device nor a headset is available.
Define a default audio output on the phone, which will handle the audio if neither a Bluetooth
device nor a headset is available, and the application has not selected a specific audio
device.
Determine which of the phone’s audio outputs currently handles the audio
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 100
AudioManager methods directly, take care that doing so does not interfere with the workings of
the AudioDeviceManager.
The Phone object starts the AudioDeviceManager automatically, so that the application can use
the AudioDeviceManager methods as soon as the Phone object is available:
AudioDeviceManager adm;
public void onSessionStarted()
{
adm = uc.getPhone().getAudioDeviceManager();
adm.addListener(this);
}
The application can call these methods to set the audio devices which the phone should use for
calls made or received by the application. Calls which are not handled by the FCSDK application
are unaffected, and use the phone’s default behavior.
The listener interface (this in the above example) should be a class which implements
AudioDeviceManagerListener, which has a single method, getDeviceListChanged. The
AudioDeviceManager will call getDeviceListChanged when it becomes aware of a change to the
list of available devices, or to the selected device. It will make the check for available devices
(and possibly change the selected device, if the preferred device has become available) when a
wireless headset is plugged in, or a Bluetooth headset becomes available; the application can
also trigger the check by calling updateAudioDeviceState. See the Using the Listener section.
There may be occasions when the application does not wish to use AudioDeviceManager. In
order to return to the Android device’s default behavior, the application can call stop:
phone.getAudioDeviceManager().stop();
To switch back to using the AudioDeviceManager, the application can call start:
phone.getAudioDeviceManager().start();
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 101
AudioDeviceManager sends output to available devices in the following order:
1. Bluetooth device
2. Wired headset
3. The device selected by the application (see the Setting the Audio Device section)
4. The default device (see the Setting the Default Device section)
When the set of available devices changes (for instance, if a wired headset is unplugged, or a
paired Bluetooth device comes into range), FCSDK will start to send audio to the first available
device in the above list. Thus, the audio will switch to a Bluetooth device as soon as one
becomes available; and if a wired headset is plugged in (when a Bluetooth device is not
connected), it will switch to that.
This (Bluetooth takes precedence over headset, which takes precedence over the speaker or
earpiece) is the most likely requirement; but the application can override this behavior by setting
the preferred device in the AudioDeviceManagerListener.onDeviceListChanged method:
AudioDeviceManager adm;
The above code sends a call’s audio to the wired headset, even when a Bluetooth device is
connected.
The list of available devices which AudioDeviceManager passes to onDeviceListChanged will not
necessarily contain all the devices which exist on the phone; see the Listing Available Devices
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 102
section.
phone.getAudioDeviceManager().setAudioDevice(AudioDevice.BLUETOOTH);
The argument to the method must be one of the members of the AudioDevice enumeration:
NONE
The application has no preference, and will accept the default behavior of the phone.
SPEAKER_PHONE
Audio is sent to the loudspeaker in the phone, and is audible to others in the vicinity. Audio input
is from the phone’s internal microphone.
WIRED_HEADSET
Audio goes to a device attached to the jack in the phone. If this device has a microphone, that is
used for audio input.
EARPIECE
Audio is sent to the internal speaker, and received from the internal microphone. The user will
have to hold the phone to their ear during the call.
BLUETOOTH
The phone will not necessarily use the device which the application tries to set. When it sets the
audio device, AudioDeviceManager checks to see whether the selected device is in the list of
available devices, and if it is not, chooses either another device or the default device set by the
application (see the Setting the Default Device section). It does this without throwing an
exception.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 103
phone.getAudioDeviceManager().setDefaultAudioDevice(AudioDevice.EARPIECE);
The argument is one of the values from the AudioDevice enumeration (see the Setting the Audio
Device Section).
Setting the default device establishes a fallback option in case neither a Bluetooth device nor a
wired headset is available. As such, the application can only set it to either EARPIECE or
SPEAKER_PHONE, and if an earpiece is not available (a tablet will not have an earpiece, for
instance), AudioDeviceManager will only allow it to set it to SPEAKER_PHONE. The default
value (if the application never calls setDefaultAudioDevice) is SPEAKER_PHONE.
The application can get a list of available audio devices by calling the getAudioDevices method:
The resulting set contains members of the AudioDevice enumeration, taken from the connected
devices known to the phone. The list of available devices will not necessarily contain all the
devices which exist on the phone. In particular, if it includes WIRED_HEADSET, it will not include
EARPIECE or SPEAKER_PHONE, because it considers these to be mutually exclusive. For a
phone, the list of available devices may be:
BLUETOOTH, WIRED_HEADSET
BLUETOOTH, SPEAKER_PHONE
WIRED_HEADSET
SPEAKER_PHONE
SPEAKER_PHONE, EARPIECE
The application can also find which device is currently being used as the audio device:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 104
AudioDevice device = phone.getAudioDeviceManager().getSelectedAudioDevice();
This will work whether the preferred device has been set explicitly (using setAudioDevice) or not.
As Fusion Client SDK is network-based, it is essential that the client application is made aware
of any loss of network connection. When it loses a network connection, the server uses SIP
timers to determine how long to keep the session alive before reallocating the relevant
resources. Any application you develop should make use of the available callbacks in the Fusion
Client SDK API, and any other available technologies, to handle network failure scenarios.
To receive callbacks relating to network issues, the application must implement the UCListener
interface.
In the event of network connection problems, the SDK automatically tries to re-establish the
connection. It will make seven attempts at the following intervals: 0.5s, 1s, 2s, 4s, 4s, 4s, 4s. A
call to onConnectionRetry on the UCListener precedes each of these attempts. The callback
supplies the attempt number and the delay in seconds before the next attempt in its two
parameters.
When all reconnection attempts are exhausted, the UCListener receives the onConnectivityLost
callback, and the retries stop. At this point the client application should assume that the session
is now invalid. The client application should then log out of the server and reconnect via the web
app to get a new session, as described in the Creating the Session section.
The retry intervals, and the number of retries attempted by the SDK are subject to change in
future releases. Do not rely on the exact values quoted above.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 105
client application should not log out from the session and log back in (as described in the
Reacting to Network Loss section), as all session state will be lost.
To avoid this, the client application should register with the OS to be told of network reachability
changes, using the ConnectivityManager class. When the OS notifies the application that the
network has changed, it should pass these details on to the UC instance by calling the
setNetworkReachable method.
When the application starts, it should check for reachability. When the network is reachable, call
UC.setNetworkReachable(true). Until this call is made, FCSDK will not try to make a session
connection to the server.
If the network reachability drops after a session has been established, the client application
needs to call UC.setNetworkReachable(false).
If network reachability changes from a cellular data connection to Wi-Fi or vice versa, call
UC.setNetworkReachable(false) followed by UC.setNetworkReachable(true) to disconnect from
the first network and re-register on the second.
The inboundQuality parameter is a number between 0 and 100, where 100 indicates perfect
quality. The application might choose to show a bar in the UI, the length of the bar indicating the
quality of the connection.
The SDK starts collecting metrics as soon as it receives the remote media stream. It does this
every 5s, so the first quality callback fires roughly 5s after this remote media stream callback has
fired.
The callback then fires whenever a different quality value is calculated; so if the quality is perfect
then there will be an initial quality callback with a value of 100 (after 5s), and then no further
callback until the quality degrades.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 106
Creating an OSX Client Application
Fusion Client SDK enables you to develop OSX applications offering users the following
methods of communication:
Voice calling
Fusion Client SDK provides you with an OSX SDK and a network infrastructure which integrate
seamlessly with your existing SIP infrastructure.
To develop OSX applications using Fusion Client SDK requires Xcode 4.5 or later.
The Fusion Client SDK for OSX is made up of the following classes:
The OSX SDK reference documentation, including a full list of available methods and their
associated callbacks, is delivered in the docs.zip file. Open index.html to view the API
documentation.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
To set up a project including the Fusion Client SDK, first create a new project and add OSX
native frameworks to it:
1. Open Xcode and choose to create a Cocoa Application, giving your project an appropriate
name. The following code samples use the example name ‘WebrtcClientOSX’.
2. Click the Build Phases tab, and expand the Link Binary with Libraries section by clicking on
the title.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 107
3. Click the + button to display the file explorer.
4. Select the following OSX native dependencies from the OSX folder:
Cocoa.framework
QuartzCore.framework
The dependencies you selected are now displayed in the Link Binary with Libraries section.
2. Expand the Link Binary with Libraries section by clicking on the title.
3. Click the + button. When the file explorer displays, click Add Other.
The application accesses the API initially via a single object, ACBUC. To set up all the
functionality to which the user has access, the application needs to obtain a session ID from the
Web Application (see the Creating the Web Application section), and initialize the ACBUC object
using it. Once it has received the Session ID, the client application must call the
ucWithCofiguration method on the ACBUC:
(void) initialize
{
NSString* sessionId = [self getSessionId];
ACBUC* uc = [ACBUC ucWithConfiguration:sessionId delegate:self];
[uc startSession];
}
The delegate (in this case self) must implement the ACBUCDelegate protocol. Once the session
has started, FCSDK calls the delegate method ucDidStartSession, and the application can make
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 108
use of the ACBUC object. (If the session does not start, one of the delegate’s error methods is
called.)
Adding Voice
Once the application has initialized the ACBUC object, it can retrieve the ACBClientPhone
object. It can then use the phone object to make or receive calls, for which it returns
ACBClientCall objects. Each one of those objects has a delegate for notifications of errors and
other events.
Making a Call
In the following example, the application makes a call (using createCallToAddress on the
ACBClientPhone object) as soon as the session has started (see the Initializing the ACBUC
Object section):
You can change the values of the withAudio parameter to make the call one way; the withVideo
parameter should always be ACBMediaDirectionNone. Valid values are:
ACBMediaDirectionNone
ACBMediaDirectionSendOnly
ACBMediaDirectionReceiveOnly
ACBMediaDirectionSendAndReceive
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 109
Receiving a Call
You can change the values of the parameters to answer the call with a specific direction for
audio. Valid values are:
ACBMediaDirectionNone
ACBMediaDirectionSendOnly
ACBMediaDirectionReceiveOnly
ACBMediaDirectionSendAndReceive
The older form, which took two boolean values, is now deprecated.
The options specified in the answer affect both sides of the call; that is, if the remote party
placed an audio and video call, and the local application answers as audio only (as an OSX
application must), then neither party sends or receives video.
If your application plays its own ringing tone, please note that the OSX SDK makes calls to
the AVAudioSession sharedInstance object when establishing a call. For this reason, we
recommend waiting until you receive a call status of ACBClientCallStatusRinging (from
ACBClientCallDelegate didChangeStatus) before calling AVAudioSession sharedInstance
methods.
Video is not supported in this release of the OSX Fusion Client SDK, so only
ACBMediaDirectionNone is valid for the video direction.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 110
Video is not supported in this release of the OSX Fusion Client SDK.
To mute the audio stream use the enableLocalAudio method of the call:
(void) incomingCallReceived:(ACBClientCall*)call
{
self.call = call;
[call answerWithAudio:YES video:NO];
}
(void) muteButtonPressed:(UIButton*)button
{
[self.call enableLocalAudio:NO];
}
During a call the application can put a call on hold (for example, in order to make or receive
another call). Placing the call on hold pauses both the stream sent by the user and the stream
sent by the remote party; only the party who placed the call on hold can resume it.
(void) holdButtonPressed:(UIButton*)button
{
[call hold];
}
(void) resumeButtonPressed:(UIButton*)button
{
[call resume];
}
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 111
DTMF Tones
Once a call is established, an application can send DTMF tones on that call by calling the
playDTMFCode method of the ACBClientCall object:
The first parameter can either be a single tone, (for example, 6), or a sequence of tones (for
example, #123,*456). Valid values for the tones are those characters conventionally used to
represent the standard DTMF tones: 0123456789ABCD#*.
The comma indicates that there should be a two second pause between the 3 and the * tone.
The second parameter is a boolean which indicates whether the application should play the
tone back locally so that the user can hear it.
Each state change fires the call:didChangeStatus: delegate method. As the outgoing call
progresses toward being fully established, the application receives a number of calls to
didChangeStatus, containing one of the ACBClientCallStatus enumeration values each time.
The application can adjust the UI by switching on the value of the status parameter, to give the
user suitable feedback, for example by playing a local audio file for ringing or alerting:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 112
(void) call: (ACBClientCall*)call didChangeStatus:(ACBClientCallStatus) status
{
switch (status)
{
case ACBClientCallStatusRinging:
[self playRingtone];
break;
case ACBClientCallStatusInCall:
[self stopRinging];
break;
case ACBClientCallStatusEnded:
case ACBClientCallStatusBusy:
case ACBClientCallStatusError:
case ACBClientCallStatusNotFound:
case ACBClientCallStatusTimedOut:
[self updateUIForEndedCall];
break;
default:
break;
}
}
ACBCallStatusError An error has occurred on the call. such the media broker
reaching its full capacity, the network terminating the
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 113
request, or there being no media.
Threading
The application must make all method invocations on the SDK, even to access read-only
properties, from the same thread. This can be any thread, and not necessarily the main thread of
the application. Internally, the SDK may use other threads to increase responsiveness, but any
delegate callbacks will occur on the same thread that is used to initialize the SDK.
Self-Signed Certificates
If you are connecting to a server that uses a self-signed certificate, you need to add that
certificate, and the associated CA root certificate, to the keychain on your client.
You can obtain the server certificate and CA root certificate through the FAS Administration
screens. The FAS Administration Guide explains how to view and export certificates. You need
to extract the HTTPS Identity Certificate (server certificate) and the Trust Certificate (CA root
certificate) that has signed your server certificate.
Once you have exported and downloaded the two certificates, you need to copy them to your
client. Please follow the user documentation for your device to install the certificates.
You should then view the installed server certificate through the appropriate tool (iOS Settings-
>General->Profiles or OSX Keychain) and confirm that the server certificate is trusted. If it is,
then your application should connect to the server.
Alternatively, you can use the acceptAnyCertificate method of the ACBUC object before calling
startSession, although this should only be used during development:
Since iOS 9, you also need to add a setting to your application’s plist file to allow connection to a
server using self-signed certificates. Set Allow Arbitrary Loads under App Transport Security
Settings to YES.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 114
Responding to Network Issues
As the OSX SDK is network-based, it is essential that the client application is aware of any loss
of connection. Fusion Client SDK does not dictate how you implement network monitoring;
however, the sample application uses the SystemConfiguration framework.
Depending on the nature of the issues with the network, the client application should react
differently.
When all reconnection attempts are exhausted, the ACBUCDelegate receives the
ucDidLoseConnection callback, and the retries stop. At this point the client application should
assume that the session is invalid. The client application should then log out of the server and
reconnect via the web app to get a new session, as described in the Creating the Session
section.
If any of the reconnection attempts are successful, the ACBUCDelegate receives the
ucDidReestablishConnection callback.
The retry intervals, and the number of retries attempted by the SDK are subject to change in
future releases. Do not rely on the exact values given above.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 115
To avoid this, the client application should register with iOS to receive notification of changes in
network reachability. When iOS notifies the client application that the network has changed, the
application should pass these details to the ACBUC instance.
When the client application starts, it should check for network reachability. When the network is
reachable, the application calls ACBUC setNetworkReachable:YES; until this call is made, the
application does not attempt to create a session.
If the network reachability drops after a session has been established, the client application
needs to call ACBUC setNetworkReachable:NO.
If the network reachability changes from a cellular data connection to a Wi-Fi network, or vice
versa, the client application should call ACBUC setNetworkReachable:NO followed by ACBUC
setNetworkReachable:YES to disconnect from the first network and re-register on the second.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 116
Creating a Windows Client Application
Fusion Client SDK enables you to develop Windows applications that offer users the ability to
make voice and video calls.
Fusion Client SDK provides you with a Windows SDK and a network infrastructure which
integrate seamlessly with your existing SIP infrastructure.
The Fusion Client SDK for Windows is made up of the following main classes:
AED, Topic, and TopicListener, for working with Application Event Distribution
The listener classes are interface classes that define pure virtual functions that the application is
expected to implement in order to receive the notifications defined by that interface.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
To set up a project including the Fusion Client SDK, you first need to create a new project and
add SDK native libraries and headers:
1. Extract the Client SDK archive to a directory that will be referred to by your new project, as
described in the following steps,
3. Select your preferred project template, name etc then click OK to create the project,
4. In the Solution Explorer view, right-click the project name and choose Properties from the
menu,
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 117
5. Select All Configurations from the Configuration: combo box,
The application initially accesses the API via a single object, UC. To set up all the functionality to
which the user has access, the application needs to obtain a session ID from the Web
Application (see the Creating the Web Application section), and initialize the UC object using it.
Once it has received the Session ID, the client application must create the UC object, then call
its StartSession method:
The first line in this sample creates the UC object using the session ID string obtained from the
Gateway. It also registers this as the UCListener object, which implies that this must be an
instance of a class that extends the UCListener interface class. Of course, you may wish to have
a different object act as the UCListener.
The second parameter is a list of STUN servers in the form of a JSON string. STUN servers are
not necessary if the Gateway is not behind a firewall, so that Network Address Translation is not
needed; in that case the array can be empty (“[]“). You can provide your own STUN server
instead of the public Google one above; and you can provide more than one in the array, in
which case they will be tried in sequence until FCSDK finds a working one.
In the second line, the UC tries to start the session; the UCListener object receives
asynchronous notification that the session has started or failed:
void MyUCListener::OnSessionStarted()
{
uc->GetPhone()->SetListener(this);
}
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 118
The implementation of OnSessionStarted obtains the Phone class from the UC, and registers
this as the listener. This implies that this must be a class that extends the PhoneListener
interface class. Again, you may use a different class as the phone listener.
The primary purpose of the PhoneListener is to receive notification of incoming calls (see the
Receiving a Call section).
After the application has created the UC object, it can retrieve the Phone object. Once the
application has been notified that the session has started, it can use the Phone object to make or
receive calls; calls are represented by Call objects. Each of the UC, Phone, and Call objects
have corresponding listener interfaces that the application can implement in order to receive
error notifications and other events.
void MyUCListener::OnSessionStarted()
{
uc->GetPhone()->SetPreviewViewName("local");
};
Making a Call
Once you have created the session, you can start making calls. Create a Call object from the
Phone object :
In this example, 1234 is the number to dial, the two MediaDirection parameters indicate that we
want the call to be an audio and video call respectively, and the final parameter registers this as
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 119
the CallListener.
The CreateCall() function returns the newly created call (CallPtr is a typedef for
std::shared_ptr<Call>).
The CreateCall method returns a Call object immediately, but the application should not use it
until the CallListener receives the asynchronous notification that the call creation has succeeded.
You can change the values of the media direction parameters to make the call audio only or
video only. They must be members of the MediaDirection enumeration:
NONE
SEND_ONLY
RECEIVE_ONLY
SEND_AND_RECEIVE
The older form of CreateCall, which took two boolean values, is now deprecated.
Receiving a Call
FCSDK invokes the PhoneListener object that you registered with the Phone object when it
receives an incoming call:
In this example the application auto-answers the call; most applications will notify the user before
invoking either call->Answer() to accept, or call->End() to reject, the call.
The two parameters to the Answer() method indicate whether to answer the call with audio and
video respectively. They are members of the MediaDirection enumeration:
NONE
SEND_ONLY
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 120
RECEIVE_ONLY
SEND_AND_RECEIVE
The older form of Answer, which took two boolean values, is now deprecated.
Displaying Video
Your application can display both video received from the remote peer, and a preview of the
locally captured video that it sends to the remote peer. You display video in your application
using two classes provided by the Windows SDK: VideoView and ImagePipeServer.
The VideoView class is provided by the SDK to paint video image data to a device context (HDC)
provided by your application.
The ImagePipeServer is a base class that your application will need to provide a concrete
implementation of, in order to receive image data and pass it on to the VideoView:
The first line creates a VideoView with a unique name for the remote view. The second line sets
a refresh function for the view; this refresh function is invoked every time there is a new video
frame to render. The application should implement it to invalidate the user interface element that
displays the video. The third line creates an instance of the subclass of ImagePipeServer, giving
it the name and reference of the VideoView. The fourth line tells the Call object the name of the
VideoView to use for displaying the remote video.
When the SDK receives a video frame from the remote peer, it invokes SendImageToView on
your ImagePipeServer subclass. Your implementation of this method must pass the image data
on to the VideoView:
void MyPipeServer::SendImageToView()
{
VideoViewImageData img = GetImageData();
remoteView->SetImageData(img);
RefreshViewFunc func = remoteView->GetRefreshViewFunc();
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 121
func();
}
This code updates the video data and triggers your refresh function. When your user interface
video element redraws, you can simply pass the HDC to the VideoView to paint the new video
frame:
remoteView->Paint(hdc, region);
Muting the local streams stops audio or video from being sent to the remote party (audio and
video received from the remote party is not affected).
The following example shows an application muting both audio and video in response to a mute
button being pressed in the user interface:
void MyUIController::MuteButtonPressed()
{
call->EnableLocalAudio(false);
call->EnableLocalVideo(false);
}
You can also mute the audio and video streams as soon as the call is answered by supplying
RECEIVE_ONLY as the media direction:
Your application can place a call on hold, and subsequently resume the call. When a call is on
hold, no audio or video is played to either end of the call. Only the party that placed the call on
hold can resume it.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 122
void MyUIController::HoldButtonPressed()
{
call->Hold();
}
void MyUIController::ResumeButtonPressed()
{
call->Resume();
}
call->SendDTMF("#123*", true);
This example sends five tones sequentially. To send a single tone just use a single-character
string.
The boolean parameter indicates whether or not you want the tones to also be played back
locally, so that the user of your application can hear them.
Valid values in the string parameter are those conventionally used to denote DTMF tones:
0123456789#*. A comma character inserts a two-second pause into a sequence of tones.
phone-
>SetPreferredCaptureResolution(VideoCaptureResolution::RESOLUTION_1280x720);
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 123
The VideoCaptureResolution enumeration class defines the set of resolutions available to your
application.
phone->SetPreferredCaptureFrameRate(20);
Changes to the video resolution and frame rate apply only to new calls; the resolution of existing
calls are not affected.
During call setup, the call transitions through several states, from the initial setup to being
connected with media available (or failure). You can monitor these states using the
onStatusChanged method of CallListener. Switching on the value of the CallStatus enumeration
allows the application to adjust the UI to give the user suitable feedback, such as by playing a
local audio file for ringing or alerting:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 124
Status Code Meaning
UNINITIALIZED The Call object has been created but not initialized
The dialing operation timed out without a response from the dialed
TIMED_OUT
number
The CallListener interface defines other notification functions that allow your application to detect
call quality changes and dial and call failures (see the Network Quality Callbacks section).
Application Event Distribution functionality is contained in the AED and Topic objects. There is
also a TopicListener object which receives information of changes which have been made to the
topics.
In order to use Application Event Distribution, you must first obtain an AED object from the UC
object:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 125
Initialization of the UC object is exactly the same as for voice and video calling (see the
Initializing the UC and Starting the Session section).
Creating a Topic
Once you have obtained an AED object, you can create a topic.
or
The name is a std::string which uniquely identifies the topic on the server, and the expiry is a
time in minutes. If you create the topic with an expiry time, it will be automatically removed from
the server after it has been inactive for that time. When created without an expiry time (by the
first method), the topic exists indefinitely, and needs to be deleted explicitly (see the
Disconnecting from a Topic section).
The listener is an object which descends from the TopicListener object. It contains a number of
callback methods which inform the application about things which happen on the topic.
Either of these creates a client-side representation of a topic and automatically connects to it. If
the topic already exists on the server, it connects to that topic; if the topic does not already exist,
it creates it.
OnTopicConnected
After creating a topic, the listener should receive an OnTopicConnected callback (in case of
failure, the listener will receive an OnTopicNotConnected callback instead). The parameters to
the callback are a TopicPtr identifying the topic, and a TopicDataPtr. The TopicDataPtr points to a
structure containing all the existing data for the topic (if the topic is newly created, this is empty).
The data on a topic consists of name-value pairs, and you can either look for the value of a data
item that you know will be there:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 126
or call GetStart() to get a TopicDataIterator pointing at the beginning of the data, and so get all
the data values:
acb::TopicData::TopicDataIterator it = data->GetStart();
if (!it.isEnded())
{
do
{
std::string name = it.GetKey();
acb::TopicDataValue value = it.GetValue();
} while (it.Next());
}
A TopicDataValue can contain one of a number types of data object (std::string, bool, int, or
double), and provides methods (GetAsString(), GetAsInt(), etc.) for retrieving the actual value; it
also provides a GetType() method which returns a std::type_info object. Currently, however, it will
always be a std::string.
The client application can also change the value of an existing data item by calling SubmitData.
In this case, the callbacks (OnTopicSubmitted and OnTopicUpdated) include a version parameter
greater than 0.
OnTopicUpdated
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 127
The client receives the OnTopicUpdated callback when any client makes a change to a data item
on a topic (adding, deleting, or changing the value associated with it), and contains information
about the change:
The topic, name, and value parameters are as detailed previously (the value parameter is the
new value); deleted will be true if the data item has been removed from the topic (see the
Deleting Data from a Topic section for details about deleting data). The version parameter is an
integer which increases with every change made to the value of the data item. The client
application can ignore updates for data items if those updates have values earlier than the value
it currently has for the same data item.
The client can delete the name-value pair from the topic by calling
acb::Topic::DeleteData(std::string key). The client receives either an OnDataDeleted followed by
an OnTopicUpdated callback, or an OnDataNotDeleted callback (in the case of failure).
A client application can send a message to a topic, and have that message sent to all current
subscribers to the topic.
If the client successfully sends the message, the listener receives an OnTopicSent followed by
an OnMessageReceived callback, both containing the topic and the message; if it is not
successful, the client will receive an OnTopicNotSent callback containing the topic, the message
which failed, and an error message.
OnMessageReceived
The OnMessageReceived callback is received by all connected clients when any client
connected to the topic (including itself) successfully sends a message to the topic. The
parameters include the topic and the message itself (as a std::string).
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 128
Disconnecting from a Topic
topic->Disconnect();
or delete it altogether:
topic->Disconnect(true);
The optional parameter to the Disconnect method is a boolean which, if true, will cause the topic
to be deleted from the server (the default value is false). The listener will receive either an
OnTopicDeleted followed by an OnTopicDeletedRemotely callback, or an OnTopicNotDeleted
callback. Apart from the topic which has been deleted, OnTopicDeleted includes a message
parameter. The message is not particularly helpful, and is probably best ignored. The
OnTopicNotDeleted callback also includes an error parameter (a std::string) which is more
useful.
OnTopicDeletedRemotely
As Fusion Client SDK is network-based, it is essential that the client application is made aware
of any loss of network connection. When a network connection is lost, the server uses SIP timers
to determine how long to keep the session alive before reallocating the relevant resources. Any
application you develop should make use of the available callbacks in the Fusion Client SDK
API, and any other available technologies, to handle network failure scenarios.
To receive callbacks relating to network issues, the application must use the UCListener class.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 129
In the event of network connection problems, the SDK automatically tries to re-establish the
connection. It will make seven attempts at the following intervals: 0.5s, 1s, 2s, 4s, 4s, 4s, 4s. A
call to OnConnectionRetry on the UCListener precedes each of these attempts. The callback
supplies the attempt number (as a uint8_t) and the delay in seconds before the next attempt (as
a uint16_t) in its two parameters.
When all reconnection attempts are exhausted, the UCListener receives the OnConnectionLost
callback, and the retries stop. At this point the client application should assume that the session
is now invalid. The client application should then log out of the server and reconnect via the web
app to get a new session, as described in the Creating the Session section.
If any of the reconnection attempts are successful, the UCListener receives the
OnConnectionReestablished callback.
Of these three notifications, the application only needs to implement OnConnectionLost(). The
other two are optional.
The retry intervals, and the number of retries attempted by the SDK are subject to change in
future releases. Do not rely on the exact values given above.
The inboundQuality parameter is a number between 0 and 100, where 100 indicates perfect
quality. The application might choose to show a bar in the UI, the length of the bar indicating the
quality of the connection.
The SDK starts collecting metrics as soon as it receives the remote media stream. It does this
every 5s, so the first quality callback fires roughly 5s after this remote media stream callback has
fired.
The callback then fires whenever a different quality value is calculated; so if the quality is perfect
then there will be an initial quality callback with a value of 100 (after 5s), and then no further
callback until the quality degrades.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 130
The CallListener class provides a skeleton implementation (which does nothing) of
OnInboundQualityChanged, so there is no need for the application to implement it.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 131
Creating a Windows .NET Client Application
Fusion Client SDK includes a wrapper for the native Windows library that allows you to develop
Windows applications in languages that use the .NET Framework, such as C# or VB.NET.
The wrapper generally follows the native Windows SDK library, provides similar functionality, and
works with similar objects. It departs from the FCSDK for Windows where doing so works better
with the .NET Framework. Managed versions of the classes provided by the wrapper are
contained within the namespace FCSDKCLR (FCSDK Common Language Runtime) and are
prefixed by CLI_ to indicate that they use the Common Language Infrastructure.
Interfaces are prefixed by ICLI_ in keeping with conventional naming of interfaces used by the
.NET framework.
Setting up a Project
Before setting up a project for a client application, make sure you have created a Web
Application to authenticate and authorize users, and to create and destroy sessions for them.
See the Creating the Web Application section.
This section provides guidance on setting up a project using Visual Studio 2013 that imports the
CSDK-CLR wrapper library.
1. Create a new .NET project (typically a Visual C# Windows Forms application or a Visual
Basic Windows Forms application).
2. Within Solution Explorer (use the View menu to display it if it is not shown), open the project
node, then open its References node.
4. The SDK contains a file CSDK-CLR.dll. Click on the Browse… button, browse to the file
and click on Add.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 132
The application initially accesses the API through a single object, CLI_UC. To set up all the
functionality to which the user has access, the application needs to obtain a session ID from the
Web Application (see the Creating the Web Application section), and initialize the CLI_UC object
using it. Once it has received the Session ID, the client application must create the CLI_UC
object, then call its StartSession method:
If you use a different object that implements ICLI_UCListener to provide the callbacks, then you
should substitute a reference to that object for this in the call to the CLI_UC constructor.
Note that you must dispose of the CLI_UC object, in common with many of the objects provided
by the CLI wrapper, when it is no longer useful. Do this by calling its Dispose method:
mUC.Dispose();
The object that implements the ICLI_UCListener interface must provide implementations for the
callbacks:
void OnSessionStarted();
void OnSessionNotStarted();
The SDK calls one of these two functions to indicate whether starting the session has succeeded
or failed. The other function callbacks in the interface are self-explanatory (for their use, see the
Responding to Network Issues section):
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 133
void onConnectivityLost();
void OnConnectionReestablished();
Once the application has created the CLI_UC object, it can retrieve the CLI_Phone object from it,
and use it to make or receive calls, which are represented by CLI_Call objects. Each of the
CLI_UC, CLI_Phone and CLI_Call objects have corresponding listener interfaces that the
application can implement in order to receive error notifications and other events.
If you want to add a preview window (a window which displays the video which is being sent to
the other endpoint) before a call is established, you can call the Phone.SetPreviewViewName
method. An appropriate time to do this is in the OnSessionStarted callback:
Making a Call
Once you have created the session, you can start making calls. Create a CLI_Call object from
the CLI_Phone object:
CLI_MediaDirection.SEND_AND_RECEIVE,
CLI_MediaDirection.SEND_AND_RECEIVE, this);
In this example, 1234 is the number to dial, the two CLI_MediaDirection parameters indicate that
we want the call to be an audio and video call respectively, and the final parameter registers this
as the ICLI_CallListener.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 134
There is an alternative version of CreateCall, which does not take the final ICLI_CallListener
parameter. If you use this version, you will need to call SetListener on the resulting CLI_Call
object in order to receive notifications about the call.
The CreateCall function returns the newly created call as a CLI_Call object, but the application
should not use it until the ICLI_CallListener receives an asynchronous notification indicating that
the call creation has succeeded.
You can change the values of the media direction parameters to make the call audio only or
video only. They must be members of the CLI_MediaDirection enumeration:
NONE
SEND_ONLY
RECEIVE_ONLY
SEND_AND_RECEIVE
The older form of CreateCall, which took two boolean values, is now deprecated.
Receiving a Call
FCSDK will invoke the ICLI_PhoneListener object that you registered with the CLI_Phone object
when an incoming call is received:
In this example, the application auto-answers the call; most applications will notify the user
before invoking either call.Answer() to accept, or call.End() to reject, the call.
The two parameters to the Answer method indicate whether to answer the call with audio and
video respectively. They are members of the CLI_MediaDirection enumeration:
NONE
SEND_ONLY
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 135
RECEIVE_ONLY
SEND_AND_RECEIVE
The older form of Answer, which took two boolean values, is now deprecated.
Displaying Video
Your application can display both video received from the remote peer, and a preview of the
locally‑captured video that it sends to the remote peer.
The SDK uses named pipes internally to route frame information from a receiving (producer)
thread to a consuming thread, These activities are separated within the SDK, and you need to
connect them to allow video to be displayed.
The CLI_Phone object has a method, SetPreviewViewName (associated with local video), and
the CLI_Call object has a method, SetVideoViewName (associated with remote video). Each
method takes a string which is used to create the name of the pipe. File naming conventions
should be followed when assigning this name. This prepares the sources of the pipes.
In order to display the video, you need to extend CLI_ImageDataPipe. The constructor of
CLI_ImageDataPipe takes a string whose name needs to match the name provided to
SetPreviewViewName or SetVideoViewName. You must override the method SendImageToView,
which returns void and takes no arguments. FCSDK calls it whenever it receives a new frame
from the pipe and makes it available for painting. The overridden method must obtain the frame
and render it.
To obtain the frame, call the method GetImageData, which returns a CLI_VideoViewImageData
object that contains the image data. You can render the frame onto a CLI_VideoView object. The
CLI_VideoView has a method, SetImageData, that takes the CLI_VideoViewImageData object
that came from GetImageData as its argument; it associates the image data with the
CLIVideoView object. It also has a method, Paint, which renders the associated frame data - the
window’s onPaint method should call it, passing in its PaintEventArgs object.
When each frame is ready to display, the CLI_VideoView calls an ICLI_ViewRefresher object’s
RefreshViewFunc. You can associate an ICLI_ViewRefresher with the CLI_VideoView by calling
its SetRefreshViewFunc method. The usual behavior of the RefreshViewFunc method is to
invalidate the region of the client area which renders the video.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 136
Muting the local streams stops audio or video from being sent to the remote party. Audio and
video received from the remote party is not affected.
The following example shows an application muting both audio and video in response to a mute
button being pressed in the user interface:
You can also mute the audio and video streams as soon as the call is answered by supplying
RECEIVE_ONLY as the media direction:
call.Answer(CLI_MediaDirection.RECEIVE_ONLY, CLI_MediaDirection.RECEIVE_ONLY);
Your application can send DTMF tones on a call by using the SendDTMF method provided by
the CLI_Call object. It can be used as follows:
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 137
call.SendDTMF(“#123*”, true);
The example sends five tones sequentially. To send a single tone, use a single-character string.
The boolean parameter indicates whether you want the tones to also be played locally, so that
the user of your application can hear them.
Valid values in the string parameter are those conventionally used to denote DTMF tones:
0123456789#*. A comma character inserts a two-second pause into a sequence of tones.
Applications developed with the Fusion Client SDK for .NET do not support multiple
simultaneous calls.
Your application can configure both the resolution and frame rate of the video it sends to the
remote party in a video call. You can set the video resolution on the CLI_Phone object:
phone.SetPreferredCaptureResolution(CLI_VideoCaptureResolution.RESOLUTION_1280x720
RESOLUTION_AUTO
RESOLUTION_352x288
RESOLUTION_640x480
RESOLUTION_1280x720
phone.SetPreferredCaptureFrameRate(20);
Changes to the video resolution and frame rate apply only to new calls. Calling these APIs while
a call is in progress has no effect.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 138
Monitoring the State of a Call
During call setup, the call transitions through several states, from the initial setup to being
connected with media available (or failure). You can monitor these states using the
ICLI_CallListener object using the method OnStatusChanged(CLI_CallStatus newStatus).
CLI_CallStatus is an enumeration with the following values:
UNINITIALIZED The Call object has been created but not initialized
The dialing operation timed out without a response from the dialed
TIMED_OUT
number
There are also other callback functions that allow your application to detect call quality changes
(OnInboundQualityChange which provides a number from 0 to 100 representing the call quality;
100 is best) and dial or call failures (OnDialFailed and OnCallFailed).
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 139
In order to use Application Event Distribution, you must first obtain a CLI_AED object from the
CLI_UC object:
Initialization of the CLI_UC object is exactly the same as for voice and video calling (see the
Initializing the CLI_UC and Starting the Session section).
Creating a Topic
You can create a topic using the CreateTopic API provided by the CLI_AED object:
aed.CreateTopic(name, listener);
or
The name argument is a string that uniquely identifies the topic on the server. If you use the form
of the API that includes an expiry argument, the expiry period is in minutes. If the topic has an
expiry time, it will be removed from the server after it has been inactive for that period of time.
When created without an expiry time (by the first method), the topic exists indefinitely, and the
application must delete it explicitly (see the Disconnecting from a Topic section).
The listener is an object that implements ICLI_TopicListener, the methods of which provide
notification to your application of events that concern the topic.
Either of these creates a client-side representation of a topic and automatically connects to it. If
the topic already exists on the server, it connects to that topic; if the topic does not already exist,
it creates it.
OnTopicConnected
After creating a topic, the listener should receive an OnTopicConnected callback (in case of
failure, the listener receives an OnTopicNotConnected callback instead). The arguments to the
callback are a CLI_Topic identifying the topic and a CLI_TopicData that contains all existing data
for the topic.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 140
The data contained within a topic consists of key-value pairs. If you know the name of a key for
which you want the associated value, you can retrieve it as follows:
You can also iterate through the keys with a simple foreach loop:
The type is returned in string form by using CLI_TopicDataValue.GetType() which returns a string
identifying the type. You can obtain the value using GetAsString(defaultValue), GetAsBool(),
GetAsInt(defaultValue) or GetAsDouble(defaultValue) and if the value does not exist, the default
value is returned (or false in the case of GetAsBool()). You can also call GetAsInt() or
GetAsDouble() in which case the default value returned is 0.
Once the client application has connected to a topic, it can publish data to the topic. Data
consists of key-value pairs.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 141
topic.SubmitData(key, value);
The client application can also change the value of an existing data item by calling SubmitData.
In this case, the callbacks (OnTopicSubmitted and OnTopicUpdated) include a version parameter
greater than 0.
OnTopicUpdated
The client receives the OnTopicUpdated callback whenever any client makes a change to a data
item on a topic (adding, deleting or changing the associated value) and contains information
about the change:
The topic, name, and value parameters are as detailed previously. The version parameter
enables clients to know, when they receive this callback, whether it refers to data they have just
submitted (if it does, the version parameters are equal). For a newly-created data item, the
version is 0, and it is incremented upon every change.
A client application can send a message to a topic and have that message sent to all current
subscribers to the topic.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 142
topic.SendMessage(“message”);
If it successfully sends the message, the listener receives an OnTopicSent callback followed by
an OnMessageReceived callback, both containing the topic and the message. If it is not
successful, the client receives an OnTopicNotSent callback containing the topic, the message
which failed, and an error message.
OnMessageReceived
The OnMessageReceived callback is received by all connected clients when any client
connected to the topic (including itself) successfully sends a message to the topic. The
arguments include the topic and the message itself (as a string).
topic.Disconnect();
or delete it altogether:
topic.Disconnect(true);
If the Disconnect method is called with the boolean argument set to true, the topic is deleted
from the server. Calling Disconnect without an argument is equivalent to calling
Disconnect(false), and in either case the topic is not deleted.
If the application attempts to delete the topic from the server, the listener receives an
OnTopicDeleted callback followed by either an OnTopicDeletedRemotely callback if successful,
or an OnTopicNotDeleted callback otherwise. OnTopicDeleted includes a message string as one
of its arguments, which is not likely to be useful. OnTopicNotDeleted includes a message string
that provides information about the error.
OnTopicDeletedRemotely
OnTopicDeletedRemotely is received by all clients connected to the topic when it is deleted from
the server, either as a result of any client calling Disconnect(true), or because it expires. It
passes the CLI_Topic which has been deleted. Once a topic has been deleted, the client should
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 143
not call any of the topic methods and should consider itself unsubscribed from that topic. If a
topic with the same name is subsequently created, it is a new topic, and the client is not
automatically subscribed to it.
As Fusion Client SDK is network-based, it is essential that the client application is made aware
of any loss of network connection. When a network connection is lost, the server uses SIP timers
to determine how long to keep the session alive before reallocating the relevant resources. Any
application you develop should make use of the available callbacks in the Fusion Client SDK
API, and any other available technologies, to handle network failure scenarios.
To receive callbacks relating to network issues, the application must implement the
ICLI_UCListener interface.
In the event of network connection problems, the SDK automatically tries to re-establish the
connection. It will make seven attempts at the following intervals: 0.5s, 1s, 2s, 4s, 4s, 4s, 4s. A
call to OnConnectionRetry on the ICLI_UCListener precedes each of these attempts. The
callback supplies the attempt number (as a System::Byte) and the delay in seconds before the
next attempt (as a System::UInt16) in its two parameters.
When all reconnection attempts are exhausted, the ICLI_UCListener receives the
OnConnectionLost callback, and the retries stop. At this point the client application should
assume that the session is now invalid. The client application should then log out of the server
and reconnect via the web app to get a new session, as described in the Creating the Session
section.
If any of the reconnection attempts are successful, the ICLI_UCListener receives the
OnConnectionReestablished callback.
The retry intervals, and the number of retries attempted by the SDK are subject to change in
future releases. Do not rely on the exact values quoted above.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 144
public void OnInboundQualityChange(int inboundQuality)
{
// Show indication of quality
}
The inboundQuality parameter is a number between 0 and 100, where 100 indicates perfect
quality. The application might choose to show a bar in the UI, the length of the bar indicating the
quality of the connection.
The SDK starts collecting metrics as soon as it receives the remote media stream. It does this
every 5s, so the first quality callback fires roughly 5s after this remote media stream callback has
fired.
The callback then fires whenever a different quality value is calculated; so if the quality is perfect
then there will be an initial quality callback with a value of 100 (after 5s), and then no further
callback until the quality degrades.
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 145
Appendix: Error Codes
Some of the APIs give access to an error code from the Gateway. These are:
Code Meaning
The Offer, Answer, or Offer Request is not for a new session and does not
NOMATCH
correspond to an existing session
NOTFOUND The outbound request failed because the callee could not be found
© 2023 CBA | All Rights Reserved | Unauthorized use prohibited. Page 146