Add a Microsoft Teams user to an existing call using Call Automation

Important

This feature of Azure Communication Services is currently in preview.

Preview APIs and SDKs are provided without a service-level agreement. We recommend that you don't use them for production workloads. Some features might not be supported, or they might have constrained capabilities.

For more information, review Supplemental Terms of Use for Microsoft Azure Previews.

In this quickstart, we use the Azure Communication Services Call Automation APIs to add, remove and transfer call to a Teams user.

Prerequisites

  • An Azure account with an active subscription.
  • A Microsoft Teams phone license and a Teams tenant with administrative privileges. Teams phone license is a must in order to use this feature, learn more about Teams licenses here. Administrative privileges are required to authorize Communication Services resource to call Teams users, explained later in Step 1.
  • A deployed Communication Service resource and valid connection string found by selecting Keys in left side menu on Azure portal.
  • Acquire a PSTN phone number from the Communication Service resource. Note the phone number you acquired to use in this quickstart.
  • An Azure Event Grid subscription to receive the IncomingCall event.
  • The latest Azure Communication Service Call Automation API library for your operating system.
  • A web service that implements the Call Automation API library, follow this tutorial.

Step 1: Authorization for your Azure Communication Services Resource to enable calling to Microsoft Teams users

To enable calling through Call Automation APIs, a Microsoft Teams Administrator or Global Administrator must explicitly enable the Communication Services resource(s) access to their tenant to allow calling.

Set-CsTeamsAcsFederationConfiguration (MicrosoftTeamsPowerShell) Tenant level setting that enables/disables federation between their tenant and specific Communication Services resources.

Set-CsExternalAccessPolicy (SkypeForBusiness) User policy that allows the admin to further control which users in their organization can participate in federated communications with Communication Services users.

Step 2: Use the Graph API to get Microsoft Entra object ID for Teams users and optionally check their presence

A Teams user’s Microsoft Entra object ID (OID) is required to add them to or transfer to them from a Communication Services call. The OID can be retrieved through 1) Office portal, 2) Microsoft Entra admin center, 3) Microsoft Entra Connect; or 4) Graph API. The example below uses Graph API.

Consent must be granted by a Microsoft Entra admin before Graph can be used to search for users, learn more by following on the Microsoft Graph Security API overview document. The OID can be retrieved using the list users API to search for users. The following shows a search by display name, but other properties can be searched as well:

List users using Microsoft Graph v1.0:

Request:
	https://graph.microsoft.com/v1.0/users?$search="displayName:Art Anderson"
Permissions:
	Application and delegated. Refer to documentation.
Response:
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
    "value": [
        {
            "displayName": "Art Anderson",
            "mail": "artanderson@contoso.com",
            "id": "fc4ccb5f-8046-4812-803f-6c344a5d1560"
        }

Optionally, Presence for a user can be retrieved using the get presence API and the user ObjectId. Learn more on the Microsoft Graph v1.0 documentation.

Request:
https://graph.microsoft.com/v1.0/users/fc4ccb5f-8046-4812-803f-6c344a5d1560/presence
Permissions:
Delegated only. Application not supported.  Refer to documentation.
Response:
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('fc4ccb5f-8046-4812-803f-6c344a5d1560')/presence/$entity",
    "id": "fc4ccb5f-8046-4812-803f-6c344a5d1560",
    "availability": "Offline",
    "activity": "Offline"

Step 3: Add a Teams user to an existing Communication Services call controlled by Call Automation APIs

You need to complete the prerequisite step and have a web service app to control a Communication Services call. Using the callConnection object, add a participant to the call.

CallAutomationClient client = new CallAutomationClient('<Connection_String>');
AnswerCallResult answer = await client.AnswerCallAsync(incomingCallContext, new Uri('<Callback_URI>'));
await answer.Value.CallConnection.AddParticipantAsync(
    new CallInvite(new MicrosoftTeamsUserIdentifier('<Teams_User_Guid>'))
    {
        SourceDisplayName = "Jack (Contoso Tech Support)"
    });
CallAutomationClient client = new CallAutomationClientBuilder().connectionString("<resource_connection_string>").buildClient();
AnswerCallResult answer = client.answerCall(incomingCallContext, "<Callback_URI>"));
answer.getCallConnection().addParticipant(
    new CallInvite(new MicrosoftTeamsUserIdentifier("<Teams_User_Guid>"))
        .setSourceDisplayName("Jack (Contoso Tech Support)"));
const client = new CallAutomationClient("<resource_connection_string>");
const answer = await client.answerCall(incomingCallContext, "<Callback_URI>"));
answer.callConnection.addParticipant({
    targetParticipant: { microsoftTeamsUserId: "<Teams_User_Guid>" },
    sourceDisplayName: "Jack (Contoso Tech Support)"
});
call_automation_client = CallAutomationClient.from_connection_string("<resource_connection_string>")
answer = call_automation_client.answer_call(incoming_call_context = incoming_call_context, callback_url = "<Callback_URI>")
call_connection_client = call_automation_client.get_call_connection(answer.call_connection_id)
call_connection_client.add_participant(target_participant = CallInvite(
    target = MicrosoftTeamsUserIdentifier(user_id="<USER_ID>"),
    source_display_name = "Jack (Contoso Tech Support)"))

On the Microsoft Teams desktop client, Jack's call will be sent to the Microsoft Teams user through an incoming call toast notification.

Screenshot of Microsoft Teams desktop client, Jack's call is sent to the Microsoft Teams user through an incoming call toast notification.

After the Microsoft Teams user accepts the call, the in-call experience for the Microsoft Teams user will have all the participants displayed on the Microsoft Teams roster. Note that your application that is managing the call using Call Automation API will remain hidden to Teams user on the call screen. Screenshot of Microsoft Teams user accepting the call and entering the in-call experience for the Microsoft Teams user.

Step 4: Remove a Teams user from an existing Communication Services call controlled by Call Automation APIs

await answer.Value.CallConnection.RemoveParticipantAsync(new MicrosoftTeamsUserIdentifier('<Teams_User_Guid>'));
answer.getCallConnection().removeParticipant(new MicrosoftTeamsUserIdentifier("<Teams_User_Guid>"));
answer.callConnection.removeParticipant({ microsoftTeamsUserId: "<Teams_User_Guid>" });
call_connection_client.remove_participant(target_participant = MicrosoftTeamsUserIdentifier(user_id="<USER_ID>"))

Optional feature: Transfer to a Teams user from an existing Communication Services call controlled by Call Automation APIs

await answer.Value.CallConnection.TransferCallToParticipantAsync(new MicrosoftTeamsUserIdentifier('<Teams_User_Guid>'));
answer.getCallConnection().transferCallToParticipant(new MicrosoftTeamsUserIdentifier("<Teams_User_Guid>"));
answer.callConnection.transferCallToParticipant({ microsoftTeamsUserId: "<Teams_User_Guid>" });
call_connection_client.transfer_call_to_participant(target_participant = MicrosoftTeamsUserIdentifier(user_id = "<USER_ID>"))

Clean up resources

If you want to clean up and remove a Communication Services subscription, you can delete the resource or resource group. Deleting the resource group also deletes any other resources associated with it. Learn more about cleaning up resources.

Next steps