Proposed Pull Request Change

author ms.service ms.topic ms.date ms.author ms.custom
jiyoonlee azure-communication-services include 09/26/2024 jiyoonlee sfi-ropc-nochange
📄 Document Links
GitHub View on GitHub Microsoft Learn View on Microsoft Learn
Raw New Markdown
Generating updated version of doc...
Rendered New Markdown
Generating updated version of doc...
+0 -0
+0 -0
--- author: jiyoonlee ms.service: azure-communication-services ms.topic: include ms.date: 09/26/2024 ms.author: jiyoonlee ms.custom: sfi-ropc-nochange --- In this quickstart you are going to learn how to start a call from Azure Communication Services user to Teams Auto Attendant. You are going to achieve it with the following steps: 1. Enable federation of Azure Communication Services resource with Teams Tenant. 2. Select or create Teams Auto Attendant via Teams Admin Center. 3. Get email address of Auto Attendant via Teams Admin Center. 4. Get Object ID of the Auto Attendant via Graph API. 5. Start a call with Azure Communication Services Calling SDK. If you'd like to skip ahead to the end, you can download this quickstart as a sample on [GitHub](https://github.com/Azure-Samples/communication-services-android-quickstarts/tree/main/Add%20Voice%20Calling). [!INCLUDE [Enable interoperability in your Teams tenant](../../../../concepts/includes/enable-interoperability-for-teams-tenant.md)] ## Create or select Teams Auto Attendant Teams Auto Attendant is system that provides an automated call handling system for incoming calls. It serves as a virtual receptionist, allowing callers to be automatically routed to the appropriate person or department without the need for a human operator. You can select existing or create new Auto Attendant via [Teams Admin Center](https://aka.ms/teamsadmincenter). Learn more about how to create Auto Attendant using Teams Admin Center [here](/microsoftteams/create-a-phone-system-auto-attendant?tabs=general-info). ## Find Object ID for Auto Attendant After Auto Attendant is created, we need to find correlated Object ID to use it later for calls. Object ID is connected to Resource Account that was attached to Auto Attendant - open [Resource Accounts tab](https://admin.teams.microsoft.com/company-wide-settings/resource-accounts) in Teams Admin and find email of account. :::image type="content" source="../../../media/teams-call-queue-resource-account.png" alt-text="Screenshot of Resource Accounts in Teams Admin Portal."::: All required information for Resource Account can be found in [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer) using this email in the search. ```console https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com ``` In results we'll are able to find "ID" field ```json "userPrincipalName": "lab-test2-cq@contoso.com", "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db" ``` To use in the calling App, we need to add a prefix to this ID. Currently, the following are supported: - Public cloud Auto Attendant: `28:orgid:<id>` - Government cloud Auto Attendant: `28:gcch:<id>` ## Prerequisites - An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/pricing/purchase-options/azure-account?cid=msft_learn). - [Android Studio](https://developer.android.com/studio), for creating your Android application. - A deployed Communication Services resource. [Create a Communication Services resource](../../../create-communication-resource.md). - A [User Access Token](../../../identity/access-tokens.md) for your Azure Communication Service. You can also use the Azure CLI and run the command with your connection string to create a user and an access token. ```azurecli-interactive az communication identity token issue --scope voip --connection-string "yourConnectionString" ``` For details, see [Use Azure CLI to Create and Manage Access Tokens](../../../identity/access-tokens.md?pivots=platform-azcli). - Minimum support for Teams calling applications: 2.12.0-beta.1 ## Setting up ### Create an Android app with an empty activity From Android Studio, select Start a new Android Studio project. :::image type="content" source="../../media/android/studio-new-project.png" alt-text="Screenshot showing the 'Start a new Android Studio Project' button selected in Android Studio."::: Select "Empty Views Activity" project template under "Phone and Tablet". :::image type="content" source="../../media/android/studio-blank-activity.png" alt-text="Screenshot showing the 'Empty Activity' option selected in the Project Template Screen."::: Select Minimum SDK of "API 26: Android 8.0 (Oreo)" or greater. :::image type="content" source="../../media/android/studio-calling-min-api.png" alt-text="Screenshot showing the 'Empty Activity' option selected in the Project Template Screen 2."::: ### Install the package <!-- TODO: update with instructions on how to download, install and add package to project --> Locate your project `settings.gradle.kts` and make sure to see `mavenCentral()` at the list of repositories under `pluginManagement` and `dependencyResolutionManagement` ```groovy pluginManagement { repositories { ... mavenCentral() ... } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { ... mavenCentral() } } ``` Then, in your module level build.gradle add the following lines to the dependencies and android sections ```groovy android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { ... implementation ("com.azure.android:azure-communication-calling:2.6.0") ... } ``` ### Add permissions to application manifest In order to request permissions required to make a call, they must be declared in the Application Manifest (`app/src/main/AndroidManifest.xml`). Replace the content of file with the following code: ```xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.contoso.acsquickstart"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!--Our Calling SDK depends on the Apache HTTP SDK. When targeting Android SDK 28+, this library needs to be explicitly referenced. See https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p--> <uses-library android:name="org.apache.http.legacy" android:required="false"/> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ``` ### Set up the layout for the app Two inputs are needed: a text input for the callee ID, and a button for placing the call. These inputs can be added through the designer or by editing the layout xml. Create a button with an ID of `call_button` and a text input of `callee_id`. Navigate to (`app/src/main/res/layout/activity_main.xml`) and replace the content of file with the following code: ```xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${launchApp}"> <EditText android:id="@+id/callee_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="Callee Id" android:inputType="textPersonName" android:layout_marginTop="100dp" android:layout_marginHorizontal="20dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="46dp" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> <Button android:id="@+id/call_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Call" /> <Button android:id="@+id/hangup_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hangup" /> </LinearLayout> <TextView android:id="@+id/status_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> ``` ### Create the main activity scaffolding and bindings With the layout created the bindings can be added as well as the basic scaffolding of the activity. The activity handles requesting runtime permissions, creating the call agent, and placing the call when the button is pressed. The `onCreate` method is overridden to invoke `getAllPermissions` and `createAgent` and to add the bindings for the call button. This event occurs only once when the activity is created. For more information, on `onCreate`, see the guide [Understand the Activity Lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle). Navigate to **MainActivity.java** and replace the content with the following code: ```java package com.contoso.acsquickstart; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import android.Manifest; import android.content.pm.PackageManager; import android.media.AudioManager; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.concurrent.ExecutionException; import com.azure.android.communication.common.CommunicationIdentifier; import com.azure.android.communication.common.CommunicationUserIdentifier; import com.azure.android.communication.calling.Call; import com.azure.android.communication.calling.CallAgent; import com.azure.android.communication.calling.CallClient; import com.azure.android.communication.calling.HangUpOptions; import com.azure.android.communication.common.CommunicationTokenCredential; import com.azure.android.communication.calling.StartCallOptions; public class MainActivity extends AppCompatActivity { private static final String[] allPermissions = new String[] { Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE }; private static final String UserToken = "<User_Access_Token>"; TextView statusBar; private CallAgent agent; private Call call; private Button callButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); callButton = findViewById(R.id.call_button); getAllPermissions(); createAgent(); callButton.setOnClickListener(l -> startCall()); Button hangupButton = findViewById(R.id.hangup_button); hangupButton.setOnClickListener(l -> endCall()); statusBar = findViewById(R.id.status_bar); setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); } /** * Start a call */ private void startCall() { if (UserToken.startsWith("<")) { Toast.makeText(this, "Please enter token in source code", Toast.LENGTH_SHORT).show(); return; } EditText calleeIdView = findViewById(R.id.callee_id); String calleeId = calleeIdView.getText().toString(); if (calleeId.isEmpty()) { Toast.makeText(this, "Please enter callee", Toast.LENGTH_SHORT).show(); return; } ArrayList<CommunicationIdentifier> participants = new ArrayList<>(); participants.add(new MicrosoftTeamsAppIdentifier(calleeId)); StartCallOptions options = new StartCallOptions(); call = agent.startCall( getApplicationContext(), participants, options); call.addOnStateChangedListener(p -> setStatus(call.getState().toString())); } /** * Ends the call previously started */ private void endCall() { try { call.hangUp(new HangUpOptions()).get(); } catch (ExecutionException | InterruptedException e) { Toast.makeText(this, "Unable to hang up call", Toast.LENGTH_SHORT).show(); } } /** * Create the call agent */ private void createAgent() { try { CommunicationTokenCredential credential = new CommunicationTokenCredential(UserToken); agent = new CallClient().createCallAgent(getApplicationContext(), credential).get(); } catch (Exception ex) { Toast.makeText(getApplicationContext(), "Failed to create call agent.", Toast.LENGTH_SHORT).show(); } } /** * Ensure all permissions were granted, otherwise inform the user permissions are missing. */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, int[] grantResults) { boolean allPermissionsGranted = true; for (int result : grantResults) { allPermissionsGranted &= (result == PackageManager.PERMISSION_GRANTED); } if (!allPermissionsGranted) { Toast.makeText(this, "All permissions are needed to make the call.", Toast.LENGTH_LONG).show(); finish(); } } /** * Shows message in the status bar */ private void setStatus(String status) { runOnUiThread(() -> statusBar.setText(status)); } } ``` ### Request permissions at runtime For Android 6.0 and higher (API level 23) and `targetSdkVersion` 23 or higher, permissions are granted at runtime instead of when the app is installed. In order to support it, `getAllPermissions` can be implemented to call `ActivityCompat.checkSelfPermission` and `ActivityCompat.requestPermissions` for each required permission. ```java /** * Request each required permission if the app doesn't already have it. */ private void getAllPermissions() { ArrayList<String> permissionsToAskFor = new ArrayList<>(); for (String permission : allPermissions) { if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { permissionsToAskFor.add(permission); } } if (!permissionsToAskFor.isEmpty()) { ActivityCompat.requestPermissions(this, permissionsToAskFor.toArray(new String[0]), 1); } } ``` > [!NOTE] > When designing your app, consider when these permissions should be requested. Permissions should be requested as they are needed, not ahead of time. For more information, see, the [Android Permissions Guide.](https://developer.android.com/training/permissions/requesting) ## Object model The following classes and interfaces handle some of the major features of the Azure Communication Services Calling SDK: | Name | Description | | ------------------------------------- | ------------------------------------------------------------ | | `CallClient`| The `CallClient` is the main entry point to the Calling SDK.| | `CallAgent` | The `CallAgent` is used to start and manage calls. | | `CommunicationTokenCredential` | The `CommunicationTokenCredential` is used as the token credential to instantiate the `CallAgent`.| | `CommunicationIdentifier` | The `CommunicationIdentifier` is used as different type of participant that could be part of a call.| ## Create an agent from the user access token With a user token, an authenticated call agent can be instantiated. Generally this token is generated from a service with authentication specific to the application. For more information on user access tokens, check the [User Access Tokens](../../../identity/access-tokens.md) guide. For the quickstart, replace `<User_Access_Token>` with a user access token generated for your Azure Communication Service resource. ```java /** * Create the call agent for placing calls */ private void createAgent() { String userToken = "<User_Access_Token>"; try { CommunicationTokenCredential credential = new CommunicationTokenCredential(userToken); callAgent = new CallClient().createCallAgent(getApplicationContext(), credential).get(); } catch (Exception ex) { Toast.makeText(getApplicationContext(), "Failed to create call agent.", Toast.LENGTH_SHORT).show(); } } ``` ## Run the code The app can now be launched using the "Run App" button on the toolbar. Manual steps to set up the call: 1. Launch the app using Android Studio. 2. Enter the Auto Attendant Object ID (with prefix), and select the "Start Call" button. Application will start the outgoing call to the Auto Attendant with given object ID. 3. Call is connected to the Auto Attendant. 4. Communication Services user is routed through Auto Attendant based on its configuration.
Success! Branch created successfully. Create Pull Request on GitHub
Error: