Transfer calls
During an active call, you may want to transfer the call to another person, number, or to voicemail. Let's learn how.
Prerequisites
- An Azure account with an active subscription. Create an account for free.
- A deployed Communication Services resource. Create a Communication Services resource.
- A user access token to enable the calling client. For more information, see Create and manage access tokens.
- Optional: Complete the quickstart to add voice calling to your application
Install the SDK
Use the npm install
command to install the Azure Communication Services Common and Calling SDK for JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Initialize required objects
A CallClient
instance is required for most call operations. When you create a new CallClient
instance, you can configure it with custom options like a Logger
instance.
With the CallClient
instance, you can create a CallAgent
instance by calling the createCallAgent
. This method asynchronously returns a CallAgent
instance object.
The createCallAgent
method uses CommunicationTokenCredential
as an argument. It accepts a user access token.
You can use the getDeviceManager
method on the CallClient
instance to access deviceManager
.
const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the logger's log level
setLogLevel('verbose');
// Redirect log output to console, file, buffer, REST API, or whatever location you want
AzureLogger.log = (...args) => {
console.log(...args); // Redirect log output to console
};
const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()
How to best manage SDK connectivity to Microsoft infrastructure
The Call Agent
instance helps you manage calls (to join or start calls). In order to work your calling SDK needs to connect to Microsoft infrastructure to get notifications of incoming calls and coordinate other call details. Your Call Agent
has two possible states:
Connected - A Call Agent
connectionStatue value of Connected
means the client SDK is connected and capable of receiving notifications from Microsoft infrastructure.
Disconnected - A Call Agent
connectionStatue value of Disconnected
states there's an issue that is preventing the SDK it from properly connecting. Call Agent
should be re-created.
invalidToken
: If a token is expired or is invalidCall Agent
instance disconnects with this error.connectionIssue
: If there's an issue with the client connecting to Microsoft infrascture, after many retriesCall Agent
exposes theconnectionIssue
error.
You can check if your local Call Agent
is connected to Microsoft infrastructure by inspecting the current value of connectionState
property. During an active call you can listen to the connectionStateChanged
event to determine if Call Agent
changes from Connected to Disconnected state.
const connectionState = callAgentInstance.connectionState;
console.log(connectionState); // it may return either of 'Connected' | 'Disconnected'
const connectionStateCallback = (args) => {
console.log(args); // it will return an object with oldState and newState, each of having a value of either of 'Connected' | 'Disconnected'
// it will also return reason, either of 'invalidToken' | 'connectionIssue'
}
callAgentInstance.on('connectionStateChanged', connectionStateCallback);
Call transfer is an extended feature of the core Call
API. You first need to import calling Features from the Calling SDK:
import { Features} from "@azure/communication-calling";
Then you can get the transfer feature API object from the call instance:
const callTransferApi = call.feature(Features.Transfer);
Call transfers involve three parties:
- Transferor: The person who initiates the transfer request.
- Transferee: The person who is being transferred.
- Transfer target: The person who is being transferred to.
Transfer to participant:
- There's already a connected call between the transferor and the transferee. The transferor decides to transfer the call from the transferee to the transfer target.
- The transferor calls the
transfer
API. - The transfer target receives an incoming call.
To transfer a current call, you can use the transfer
API. transfer
takes the optional transferCallOptions
, which allows you to set a disableForwardingAndUnanswered
flag:
disableForwardingAndUnanswered = false
: If the transfer target doesn't answer the transfer call, the transfer follows the transfer target forwarding and unanswered settings.disableForwardingAndUnanswered = true
: If the transfer target doesn't answer the transfer call, the transfer attempt ends.
// transfer target can be an Azure Communication Services user
const id = { communicationUserId: <ACS_USER_ID> };
// call transfer API
const transfer = callTransferApi.transfer({targetParticipant: id});
Transfer to call:
- There's already a connected call between the transferor and the transferee.
- There's already a connected call between the transferor and the transfer target.
- The transferor decides to transfer the call with the transferee to the call with transfer target.
- The transferor calls the
transfer
API. - The transfer target receives an incoming call.
To transfer a current call, you can use the transfer
API.
// transfer to the target call specifying the call id
const id = { targetCallId: <CALL_ID> };
// call transfer API
const transfer = callTransferApi.transfer({ targetCallId: <CALL_ID> });
The transfer
API allows you to subscribe to stateChanged
. It also comes with a transfer state
and error
properties
// transfer state
const transferState = transfer.state; // None | Transferring | Transferred | Failed
// to check the transfer failure reason
const transferError = transfer.error; // transfer error code that describes the failure if a transfer request failed
The transferee can listen to a transferAccepted
event. The listener for this event has a TransferEventArgs
which contains the call object of the new transfer call
between the transferee and the transfer target.
// Transferee can subscribe to the transferAccepted event
callTransferApi.on('transferAccepted', args => {
const newTransferCall = args.targetCall;
});
The transferor can subscribe to events for change of the state of the transfer. If the call to the transferee was successfully connected with Transfer target, transferor can hang up the original call with transferee.
transfer.on('stateChanged', () => {
if (transfer.state === 'Transferred') {
call.hangUp();
}
});
Transfer to voicemail:
- There is a connected call between the transferor and the transferee.
- The Teams User Identifier of the target participant voicemail is known.
- The transferor decides to transfer the call with the transferee to the target participant's voicemail using the target participant's Teams User Identifier.
- The transferor calls the
transfer
API. - The transferee receives the transfer request.
To transfer a current call, you can use the transfer
API.
// transfer to the target participant voicemail specified by their Teams User Identifier
const id: MicrosoftTeamsUserIdentifier = { microsoftTeamsUserId: userId}
// call transfer API
const transfer = callTransferApi.transfer({ targetParticipantVoicemail: id });
The transfer
API allows you to subscribe to stateChanged
. It also comes with a transfer state
and error
properties
// transfer state
const transferState = transfer.state; // None | Transferring | Transferred | Failed
// to check the transfer failure reason
const transferError = transfer.error; // transfer error code that describes the failure if a transfer request failed
The transferee can listen to a transferAccepted
event. The listener for this event has a TransferEventArgs
which contains the call object of the new transfer call
between the transferee and the target participant voicemail.
// Transferee can subscribe to the transferAccepted event
callTransferApi.on('transferAccepted', args => {
const newTransferCall = args.targetCall;
});
The transferor can subscribe to events for change of the state of the transfer. If the call to the transferee was successfully connected with target participant voicemail, transferor can hang up the original call with transferee.
transfer.on('stateChanged', () => {
if (transfer.state === 'Transferred') {
call.hangUp();
}
});