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: .. code-block:: :linenos: let manager = CallRedirectionManager.shared And in Java: .. code-block:: :linenos: CallRedirectionManager 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: .. code-block:: :linenos: class SomeClassName: RedirectionDelegate { ... func addRedirectionDelegate() { CallRedirectionManager.shared.addStateChangeDelegate(self) } func redirectStateChanged(state: CallRedirectState, type: CallRedirectType) { var message: String? if state.isSourceAssigned() { message = "Please pick %s target"; } else if state.isTargetAssigned() { message = "%s target assigned"; } else if state.isInProgress() { message = "%s target assigned"; } else if state.isSucceeded() { message = "%s success"; } else if state.isFailed() { message = "%s failed"; } else if state.isCancelled() { message = "%s cancelled"; } else { message = nil; } if m = message { let typePlaceholder = type.isTransferType() ? "Call Transfer" : "Call Forwarding" let formattedMessage = String(format: message, typePlaceholder) print(formattedMessage) } } } And in Java: .. code-block:: :linenos: CallRedirectionManager callRedirectionManager = SDKServices.get(CallRedirectionManager.class); Disposable redirectionStateDisposable = callRedirectionManager.registerOnStateChangedCallback((type, state) -> { String message = null; switch(state) { case SourceAssigned: message = "Please pick %s target"; break; case TargetAssigned: message = "%s target assigned"; break; case InProgress: // we can show progress indicator here message = "%s in progress"; break; case Succeeded: message = "%s success"; break; case Failed: message = "%s failed"; break; case Cancelled: message = "%s cancelled"; break; default: break; } if (message != null) { String typePlaceholder = type.isTransferType() ? "Call Transfer" : "Call Forwarding"; Toast.makeText(this, String.format(message, typePlaceholder), Toast.LENGTH_SHORT).show(); } }); 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: #. A call is established. #. GUI checks the redirection capabilities by calling ``getRedirectCapabilities`` for the current call, and enables the transfer button if blind transfer is available. #. The user clicks on the transfer button on the call screen. #. GUI invokes ``setBlindTransferSource`` for the current call. #. GUI gets notified via its registered ``StateChangeCallback`` about a transition to ``RedirectState::SourceAssigned``. #. 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. #. The user dials a number or selects a contact to transfer to #. GUI creates and posts a CallEvent for the call to be transferred to, as if it were a regular outgoing call #. GUI gets notified via its registered ``StateChangeCallback`` about a transition to ``RedirectState::InProgress`` . #. GUI updates the UI to show that the transfer is in progress, at this point it is no longer possible to cancel the transfer. #. 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``. #. GUI updates its layout to show the result of the transfer. #. 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: #. Two calls are established. #. GUI checks the redirection capabilities by invoking ``getRedirectCapabilities`` for the current call, and enables the attended transfer button if attended transfer is available. #. The user clicks on the attended transfer button on the call screen. #. The capabilities are queried again via ``getRedirectCapabilities``, the ``AttendedTransferCapability`` field of the ``RedirectCapabilities`` object is checked to see if attended transfer is still available. #. As two calls are currently established, the ``AttendedTransferCapability`` returns the value ``Direct``. #. 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: #. A call is established. #. GUI checks the redirection capabilities by invokes ``getRedirectCapabilities`` for the current call, and enables the attended transfer button if attended transfer is available. #. The user clicks on the attended transfer button on the call screen. #. The capabilities are queried again via ``getRedirectCapabilities``, the ``AttendedTransferCapability`` field of the ``RedirectCapabilities`` returns ``NewCall``. #. GUI invokes ``setAttendedTransferSource`` for the current call. #. GUI gets notified via its registered ``StateChangeCallback`` about a transition to ``RedirectState::SourceAssigned``. #. 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. #. The user dials a number or selects a contact to transfer to. #. GUI creates and posts a CallEvent for the target call, as if it were a regular outgoing call. #. Once the call gets into ``Call::State::Established`` state, the redirection manager calls ``setAttendedTransferTarget`` on the new call automatically. #. GUI gets notified via its registered ``StateChangeCallback`` about a transition to ``RedirectState::TargetAssigned``. #. 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. #. User clicks on the attended transfer button again. #. GUI invokes ``performAttendedTransfer``. #. GUI gets notified via its registered ``StateChangeCallback`` about a transition to ``RedirectState::InProgress`` . #. Based on the result of the transfer, GUI gets notified about a state transition to ``RedirectState::Succeeded`` or ``RedirectState::Failed`` or ``RedirectState::Cancelled`` #. GUI updates its layout according to the result of the forward. #. 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.