Call Transfers and Call Forwarding

This article describes the call transfer and user initiated call forwarding features of the mobile SDK.

Overview

The SDK supports the following types of call redirection:

  • Blind transfer - the party initiating the transfer (the “Transferor”) sends the call directly to the third party (the “Target”) without waiting to establish a session with the Target first.

  • Attended transfer - party initiating the transfer (the “Transferor”) speaks with the third party (the “Target”) before completing the transfer from the original call party (the “Transferee”).

  • Call forwarding - the party initiating the forwarding sends the call directly to the third party while the original call is still ringing.

There are two ways to perform and manage redirection:

  • Direct usage of libSoftphone APIs - suitable for simple call redirection scenarios or for scenarios where the developer wants to have full control over the redirection process.

  • CallRedirectionManager - a higher level API that simplifies the call redirection management.

The direct APIs

The Swift SoftphoneBridge and Java Instance offer the following methods for call redirection:

transfer

Performs a blind transfer of an Established call to the specified target.

attendedTransfer

Performs an attended transfer of an Established call to another Established call.

forward

Forwards an IncomingTrying, IncomingRinging or IncomingIgnored call to the specified target.

acceptOfferedTransfer

Accepts an offered transfer.

rejectOfferedTransfer

Rejects an offered transfer.

The following callbacks are exposed in Swift SoftphoneObserverProxy and Java Listeners classes are available to monitor the progress of the call redirection:

onTransferResult

Reports the result of blind and attended transfers.

onTransferOffered

Informs about an incoming transfer offer. The offer can be accepted or rejected via acceptOfferedTransfer and rejectOfferedTransfer.

A successful call forward is reported via transition of call into IncomingForwarded state which is reported in onCallStateChanged callback.

Using CallRedirectionManager

The CallRedirectionManager is a higher level API that simplifies the call redirection management. It is designed in order to lead the developer through the call redirection process and to provide a simple way to implement the call redirection UI by providing a set of unified functions, callbacks and unified state. The CallRedirectionManager is a singleton object which is accessible both in Swift and Java.

The CallRedirectionManager instance can be retrieved in Swift as follows:

1let manager = CallRedirectionManager.shared

And in Java:

1CallRedirectionManager callRedirectionManager = SDKServices.get(CallRedirectionManager.class);

CallRedirectionManager state

CallRedirectionManager tracks the redirection state and provides a set of functions to manage the redirection. The redirection state is represented by the RedirectionState enum.

The state set description follows:

  • Inactive - no redirection is in progress

  • SourceAssigned - the redirect source call is assigned, the GUI should direct the user to select the target call by navigating to the dialpad or contact list

  • TargetAssigned - the target call is assigned and attended transfer can be performed, this state

  • only occurs in case of attended transfer

  • InProgress - both redirect source and target have been assigned, in case of transfers, the REFER will be sent, in case of call forwarding a 302 reponse will be sent as response to the INVITE. At this point it is not possible to change the source nor the target. It is not possible to cancel the redirection nor change the redirection type.

  • Succeeded - the redirection succeeded

  • Failed - the redirection failed

  • Cancelled - the redirection was cancelled, e.g. by user, or by some unexpected event, such as one of the calls was disconnected.

The redirection is tracked from the moment the source call is assigned until the source or target call objects are closed. This means the GUI code can retrieve the state, type, source and target call objects even after the redirect has finished or has been cancelled.

The state can be tracked by registering a listener, here’s a Swift example:

 1class SomeClassName: RedirectionDelegate
 2{
 3    ...
 4    func addRedirectionDelegate()
 5    {
 6        CallRedirectionManager.shared.addStateChangeDelegate(self)
 7    }
 8
 9    func redirectStateChanged(state: CallRedirectState, type: CallRedirectType)
10    {
11        var message: String?
12        if state.isSourceAssigned()
13        {
14            message = "Please pick %s target";
15        }
16        else if state.isTargetAssigned()
17        {
18            message = "%s target assigned";
19        }
20        else if state.isInProgress()
21        {
22            message = "%s target assigned";
23        }
24        else if state.isSucceeded()
25        {
26            message = "%s success";
27        }
28        else if state.isFailed()
29        {
30            message = "%s failed";
31        }
32        else if state.isCancelled()
33        {
34            message = "%s cancelled";
35        }
36        else
37        {
38            message = nil;
39        }
40
41        if m = message
42        {
43            let typePlaceholder = type.isTransferType() ? "Call Transfer" : "Call Forwarding"
44            let formattedMessage = String(format: message, typePlaceholder)
45            print(formattedMessage)
46        }
47    }
48}

And in Java:

 1CallRedirectionManager callRedirectionManager = SDKServices.get(CallRedirectionManager.class);
 2Disposable redirectionStateDisposable = callRedirectionManager.registerOnStateChangedCallback((type, state) -> {
 3    String message = null;
 4    switch(state)
 5    {
 6        case SourceAssigned:
 7            message = "Please pick %s target";
 8            break;
 9        case TargetAssigned:
10            message = "%s target assigned";
11            break;
12        case InProgress:
13            // we can show progress indicator here
14            message = "%s in progress";
15            break;
16        case Succeeded:
17            message = "%s success";
18            break;
19        case Failed:
20            message = "%s failed";
21            break;
22        case Cancelled:
23            message = "%s cancelled";
24            break;
25        default:
26            break;
27    }
28    if (message != null)
29    {
30        String typePlaceholder = type.isTransferType() ? "Call Transfer" : "Call Forwarding";
31        Toast.makeText(this, String.format(message, typePlaceholder), Toast.LENGTH_SHORT).show();
32    }
33});

You can also retrieve the current active redirection type by invoking getCurrentRedirectFlow and the current state by invoking getState.

API overview

The breakdown of the most important redirection manager functions follows:

getCurrentRedirectFlow

Returns the current redirection flow or None if no redirection is currently tracked.

getState

Returns the current redirection state.

getRedirectSource

Returns the source call object.

getRedirectTarget

Returns the target call object (only available in attended transfer).

cancelRedirect

Cancels any tracked redirection flow. Cancel has no effect if redirect state is InProgress.

canInitiateRedirect

Checks if the redirect manager is ready perform a transfer or forward.

getRedirectCapabilities

Returns the transfer and forward capabilities of the supplied call.

setBlindTransferSource

Sets the source call for blind transfer. The source call must be in Established state.

setAttendedTransferSource

Sets the source call for attended transfer. The source call must be in Established state.

setForwardingSource

Sets the source call for call forwarding. The source call must be in IncomingTrying, IncomingRinging or IncomingIgnored state.

setAttendedTransferTarget

Sets the target call for attended transfer. The target call must be in Established state.

performForwardToTarget

Performs a call forward to the specified target. The forwarding source call must be set setForwardingSource before calling this function and the state must be SourceAssigned.

performBlindTransferToTarget

Performs a blind transfer to the specified target. The forwarding source call must be set setForwardingSource before calling this function and the state must be SourceAssigned.

performAttendedTransfer

Performs an attended transfer between the source previously set via setAttendedTransferSource and the target previously set via setAttendedTransferTarget. The state must be TargetAssigned.

performAttendedTransferBetween

Performs an attended transfer between the supplied source and target. This can be invoked directly without setting the source and target calls. The state must not be InProgress.

Blind transfer flow

The typical flow of blind transfer is as follows:

  1. A call is established.

  2. GUI checks the redirection capabilities by calling getRedirectCapabilities for the current call, and enables the transfer button if blind transfer is available.

  3. The user clicks on the transfer button on the call screen.

  4. GUI invokes setBlindTransferSource for the current call.

  5. GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::SourceAssigned.

  6. The GUI updates the UI to allow the user enter the number/contact to transfer to. The user should be able to cancel the transfer via a button, if the cancel button is clicked, cancelRedirect is called.

  7. The user dials a number or selects a contact to transfer to

  8. GUI creates and posts a CallEvent for the call to be transferred to, as if it were a regular outgoing call

  9. GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::InProgress .

  10. GUI updates the UI to show that the transfer is in progress, at this point it is no longer possible to cancel the transfer.

  11. Based on the result of the transfer, GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::Succeeded or RedirectState::Failed or RedirectState::Cancelled.

  12. GUI updates its layout to show the result of the transfer.

  13. The original call is disconnected. The GUI should close the call object. When the call object is closed, the state transitions back to RedirectState::Inactive state.

Attended transfer flow - multiple established calls

The simplest possible scenario of attended transfer starts with two established calls:

  1. Two calls are established.

  2. GUI checks the redirection capabilities by invoking getRedirectCapabilities for the current call, and enables the attended transfer button if attended transfer is available.

  3. The user clicks on the attended transfer button on the call screen.

  4. The capabilities are queried again via getRedirectCapabilities, the AttendedTransferCapability field of the RedirectCapabilities object is checked to see if attended transfer is still available.

  5. As two calls are currently established, the AttendedTransferCapability returns the value Direct.

  6. The transfer target call is retrieved from RedirectCapabilities::attendedTransferTargets array, and GUI calls performAttendedTransferBetween with the two calls as parameters.

The case with three or more established calls is similar to the case with two calls. The AttendedTransferCapability shows the type PickAnotherCall, and the GUI needs to present the user with a list of calls to choose from. The GUI can use the RedirectCapabilities::attendedTransferTargets array to get the list of calls that can be used as transfer targets. Once the user selects a target call, the GUI invokes performAttendedTransferBetween with the source and target calls as parameters.

Attended transfer flow - one established call

The most complex attended transfer flow occurs when only one call is established:

  1. A call is established.

  2. GUI checks the redirection capabilities by invokes getRedirectCapabilities for the current call, and enables the attended transfer button if attended transfer is available.

  3. The user clicks on the attended transfer button on the call screen.

  4. The capabilities are queried again via getRedirectCapabilities, the AttendedTransferCapability field of the RedirectCapabilities returns NewCall.

  5. GUI invokes setAttendedTransferSource for the current call.

  6. GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::SourceAssigned.

  7. The GUI updates the UI to allow the user enter the number/contact to transfer to. The user should be able to cancel the transfer via a button, if the cancel button is clicked, cancelRedirect is invoked.

  8. The user dials a number or selects a contact to transfer to.

  9. GUI creates and posts a CallEvent for the target call, as if it were a regular outgoing call.

  10. Once the call gets into Call::State::Established state, the redirection manager calls setAttendedTransferTarget on the new call automatically.

  11. GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::TargetAssigned.

  12. GUI should display the new call and should allow the user to switch between the calls, merge them into a conference, or put them on hold etc.

  13. User clicks on the attended transfer button again.

  14. GUI invokes performAttendedTransfer.

  15. GUI gets notified via its registered StateChangeCallback about a transition to RedirectState::InProgress .

  16. Based on the result of the transfer, GUI gets notified about a state transition to RedirectState::Succeeded or RedirectState::Failed or RedirectState::Cancelled

  17. GUI updates its layout according to the result of the forward.

  18. The source and target calls are disconnected. GUI should close the call object. When the call object is closed, the state transitions back to RedirectState::Inactive state.