Quickstart: Add voice calling to your app

Important

Azure Communication Services is currently in public preview. This preview version is provided without a service-level agreement, and it's not recommended for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.

Get started with Azure Communication Services by using the Communication Services calling client library to add voice and video calling to your app.

Important

Azure Communication Services does not support emergency calling

Azure Communication Services' outbound voice calling services cannot be used for contacting emergency services. You should maintain traditional telephone service for placing emergency calls.

In this quickstart, you'll learn how start a call using the Azure Communication Services Calling client library for JavaScript. This document is referencing types in version 1.0.0-beta.5 of calling library.

Note

This document uses version 1.0.0-beta.6 of the calling client library.

Prerequisites

Setting up

Create a new Node.js application

Open your terminal or command window create a new directory for your app, and navigate to it.

mkdir calling-quickstart && cd calling-quickstart

Run npm init -y to create a package.json file with default settings.

npm init -y

Install the package

Use the npm install command to install the Azure Communication Services Calling client library for JavaScript.

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

The following versions of webpack are recommended for this quickstart:

"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"

The --save option lists the library as a dependency in your package.json file.

Set up the app framework

This quickstart uses webpack to bundle the application assets. Run the following command to install the webpack, webpack-cli and webpack-dev-server npm packages and list them as development dependencies in your package.json:

npm install webpack@4.42.0 webpack-cli@3.3.11 webpack-dev-server@3.10.3 --save-dev

Create an index.html file in the root directory of your project. We'll use this file to configure a basic layout that will allow the user to place a call.

Here's the code:

<!DOCTYPE html>
<html>
  <head>
    <title>Communication Client - Calling Sample</title>
  </head>
  <body>
    <h4>Azure Communication Services</h4>
    <h1>Calling Quickstart</h1>
    <input 
      id="callee-id-input"
      type="text"
      placeholder="Who would you like to call?"
      style="margin-bottom:1em; width: 200px;"
    />
    <div>
      <button id="call-button" type="button" disabled="true">
        Start Call
      </button>
      &nbsp;
      <button id="hang-up-button" type="button" disabled="true">
        Hang Up
      </button>
    </div>
    <script src="./bundle.js"></script>
  </body>
</html>

Create a file in the root directory of your project called client.js to contain the application logic for this quickstart. Add the following code to import the calling client and get references to the DOM elements so we can attach our business logic.

import { CallClient, CallAgent } from "@azure/communication-calling";
import { AzureCommunicationTokenCredential } from '@azure/communication-common';

let call;
let callAgent;
const calleeInput = document.getElementById("callee-id-input");
const callButton = document.getElementById("call-button");
const hangUpButton = document.getElementById("hang-up-button");

Object model

The following classes and interfaces handle some of the major features of the Azure Communication Services Calling client library:

Name Description
CallClient The CallClient is the main entry point to the Calling client library.
CallAgent The CallAgent is used to start and manage calls.
AzureCommunicationTokenCredential The AzureCommunicationTokenCredential class implements the CommunicationTokenCredential interface which is used to instantiate the CallAgent.

Authenticate the client

You need to replace <USER_ACCESS_TOKEN> with a valid user access token for your resource. Refer to the user access token documentation if you don't already have a token available. Using the CallClient, initialize a CallAgent instance with a CommunicationTokenCredential which will enable us to make and receive calls. Add the following code to client.js:

async function init() {
    const callClient = new CallClient();
    const tokenCredential = new AzureCommunicationTokenCredential("<USER ACCESS TOKEN>");
    callAgent = await callClient.createCallAgent(tokenCredential);
    callButton.disabled = false;
}
init();

Start a call

Add an event handler to initiate a call when the callButton is clicked:

callButton.addEventListener("click", () => {
    // start a call
    const userToCall = calleeInput.value;
    call = callAgent.startCall(
        [{ communicationUserId: userToCall }],
        {}
    );
    // toggle button states
    hangUpButton.disabled = false;
    callButton.disabled = true;
});

End a call

Add an event listener to end the current call when the hangUpButton is clicked:

hangUpButton.addEventListener("click", () => {
  // end the current call
  call.hangUp({ forEveryone: true });

  // toggle button states
  hangUpButton.disabled = true;
  callButton.disabled = false;
});

The forEveryone property ends the call for all call participants.

Run the code

Use the webpack-dev-server to build and run your app. Run the following command to bundle application host in on a local webserver:

npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map

Open your browser and navigate to http://localhost:8080/. You should see the following:

Screenshot of the completed JavaScript Application.

You can make an outbound VOIP call by providing a user ID in the text field and clicking the Start Call button. Calling 8:echo123 connects you with an echo bot, this is great for getting started and verifying your audio devices are working.

In this quickstart, you'll learn how to start a call using the Azure Communication Services Calling client library for Android.

Note

This document uses version 1.0.0-beta.8 of the calling client library.

Prerequisites

Setting up

Create an Android app with an empty activity

From Android Studio, select Start a new Android Studio project.

Screenshot showing the 'Start a new Android Studio Project' button selected in Android Studio.

Select "Empty Activity" project template under "Phone and Tablet".

Screenshot showing the 'Empty Activity' option selected in the Project Template Screen.

Select Minimum client library of "API 26: Android 8.0 (Oreo)" or greater.

Screenshot showing the 'Empty Activity' option selected in the Project Template Screen 2.

Install the package

Locate your project level build.gradle and make sure to add mavenCentral() to the list of repositories under buildscript and allprojects

buildscript {
    repositories {
    ...
        mavenCentral()
    ...
    }
}
allprojects {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

Then, in your module level build.gradle add the following lines to the dependencies and android sections

android {
    ...
    packagingOptions {
        pickFirst  'META-INF/*'
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    ...
    implementation 'com.azure.android:azure-communication-calling:1.0.0-beta.8'
    ...
}

Add permissions to application manifest

In order to request permissions required to make a call, they must first be declared in the Application Manifest (app/src/main/AndroidManifest.xml). Replace the content of file with the following:

    <?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 client library depends on the Apache HTTP client library.
When targeting Android client library 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 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:

<?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=".MainActivity">

    <Button
        android:id="@+id/call_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="Call"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <EditText
        android:id="@+id/callee_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Callee Id"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toTopOf="@+id/call_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="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 will handle requesting runtime permissions, creating the call agent, and placing the call when the button is pressed. Each will be covered in its own section. The onCreate method will be overridden to invoke getAllPermissions and createAgent as well as add the bindings for the call button. This will occur only once when the activity is created. For more information on onCreate, see the guide Understand the Activity Lifecycle.

Navigate to MainActivity.java and replace the content with the following code:

package com.contoso.acsquickstart;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.azure.android.communication.common.CommunicationUserIdentifier;
import com.azure.android.communication.common.CommunicationTokenCredential;
import com.azure.android.communication.calling.CallAgent;
import com.azure.android.communication.calling.CallClient;
import com.azure.android.communication.calling.StartCallOptions;


import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    
    private CallAgent callAgent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getAllPermissions();
        createAgent();
        
        // Bind call button to call `startCall`
        Button callButton = findViewById(R.id.call_button);
        callButton.setOnClickListener(l -> startCall());
    }

    /**
     * Request each required permission if the app doesn't already have it.
     */
    private void getAllPermissions() {
        // See section on requesting permissions
    }

    /**
      * Create the call agent for placing calls
      */
    private void createAgent() {
        // See section on creating the call agent
    }

    /**
     * Place a call to the callee id provided in `callee_id` text input.
     */
    private void startCall() {
        // See section on starting the call
    }
}

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 this, getAllPermissions can be implemented to call ActivityCompat.checkSelfPermission and ActivityCompat.requestPermissions for each required permission.

/**
 * Request each required permission if the app doesn't already have it.
 */
private void getAllPermissions() {
    String[] requiredPermissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE};
    ArrayList<String> permissionsToAskFor = new ArrayList<>();
    for (String permission : requiredPermissions) {
        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.

Object model

The following classes and interfaces handle some of the major features of the Azure Communication Services Calling client library:

Name Description
CallClient The CallClient is the main entry point to the Calling client library.
CallAgent The CallAgent is used to start and manage calls.
CommunicationUserCredential The CommunicationUserCredential is used as the token credential to instantiate the CallAgent.
CommunicationIdentifier The CommunicationIdentifier is used as different type of participant that would could be part of a call.

Create an agent from the user access token

With the user token an authenticated call agent can be instantiated. Generally this token will be generated from a service with authentication specific to the application. For more information on user access tokens check the User Access Tokens guide. For the quickstart, replace <User_Access_Token> with a user access token generated for your Azure Communication Service resource.


/**
 * 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();
    }
}

Start a call using the call agent

Placing the call can be done via the call agent, and just requires providing a list of callee IDs and the call options. For the quickstart, the default call options without video and a single callee ID from the text input will be used.

/**
 * Place a call to the callee id provided in `callee_id` text input.
 */
private void startCall() {
    EditText calleeIdView = findViewById(R.id.callee_id);
    String calleeId = calleeIdView.getText().toString();
    
    StartCallOptions options = new StartCallOptions();

    callAgent.call(
        getApplicationContext(),
        new CommunicationUserIdentifier[] {new CommunicationUserIdentifier(calleeId)},
        options);
}

Launch the app and call the echo bot

The app can now be launched using the "Run App" button on the toolbar (Shift+F10). Verify you are able to place calls by calling 8:echo123. A pre-recorded message will play then repeat your message back to you.

Screenshot showing the completed application.

Sample Code

You can download the sample app from GitHub

In this quickstart, you'll learn how to start a call using the Azure Communication Services Calling client library for iOS.

Note

This document uses version 1.0.0-beta.8 of the calling client library.

Prerequisites

To complete this tutorial, you’ll need the following prerequisites:

Setting up

Creating the Xcode project

In Xcode, create a new iOS project and select the Single View App template. This tutorial uses the SwiftUI framework, so you should set the Language to Swift and the User Interface to SwiftUI. You're not going to create tests during this quick start. Feel free to uncheck Include Tests.

Screenshot showing the New Project window within Xcode.

Install the package and dependencies with CocoaPods

  1. Create a Podfile for your application, like this:

    platform :ios, '13.0'
    use_frameworks!
    
    target 'AzureCommunicationCallingSample' do
      pod 'AzureCommunicationCalling', '~> 1.0.0-beta.8'
      pod 'AzureCommunication', '~> 1.0.0-beta.8'
      pod 'AzureCore', '~> 1.0.0-beta.8'
    end
    
  2. Run pod install.

  3. Open the .xcworkspace with Xcode.

Request access to the microphone

In order to access the device's microphone, you need to update your app's Information Property List with an NSMicrophoneUsageDescription. You set the associated value to a string that will be included in the dialog the system uses to request access from the user.

Right-click the Info.plist entry of the project tree and select Open As > Source Code. Add the following lines the top level <dict> section, and then save the file.

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>

Set up the app framework

Open your project's ContentView.swift file and add an import declaration to the top of the file to import the AzureCommunicationCalling library. In addition, import AVFoundation, we will need this for audio permission request in the code.

import AzureCommunicationCalling
import AVFoundation

Replace the implementation of the ContentView struct with some simple UI controls that enable a user to initiate and end a call. We will attach business logic to these controls in this quickstart.

struct ContentView: View {
    @State var callee: String = ""
    @State var callClient: CallClient?
    @State var callAgent: CallAgent?
    @State var call: Call?

    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Who would you like to call?", text: $callee)
                    Button(action: startCall) {
                        Text("Start Call")
                    }.disabled(callAgent == nil)
                    Button(action: endCall) {
                        Text("End Call")
                    }.disabled(call == nil)
                }
            }
            .navigationBarTitle("Calling Quickstart")
        }.onAppear {
            // Initialize call agent
        }
    }

    func startCall() {
        // Ask permissions
        AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
            if granted {
                // Add start call logic
            }
        }
    }

    func endCall() {
        // Add end call logic
    }
}

Object model

The following classes and interfaces handle some of the major features of the Azure Communication Services Calling client library:

Name Description
CallClient The CallClient is the main entry point to the Calling client library.
CallAgent The CallAgent is used to start and manage calls.
CommunicationTokenCredential The CommunicationTokenCredential is used as the token credential to instantiate the CallAgent.
CommunicationUserIdentifier The CommunicationUserIdentifier is used to represent the identity of the user which can be one of the following: CommunicationUserIdentifier/PhoneNumberIdentifier/CallingApplication.

Authenticate the client

Initialize a CallAgent instance with a User Access Token which will enable us to make and receive calls. Add the following code to the onAppear callback in ContentView.swift:

var userCredential: CommunicationTokenCredential?
do {
    userCredential = try CommunicationTokenCredential(token: "<USER ACCESS TOKEN>")
} catch {
    print("ERROR: It was not possible to create user credential.")
    return
}

self.callClient = CallClient()

// Creates the call agent
self.callClient?.createCallAgent(userCredential: userCredential) { (agent, error) in
    if error != nil {
        print("ERROR: It was not possible to create a call agent.")
        return
    }

    if let agent = agent {
        self.callAgent = agent
        print("Call agent successfully created.")
    }
}

You need to replace <USER ACCESS TOKEN> with a valid user access token for your resource. Refer to the user access token documentation if you don't already have a token available.

Start a call

The startCall method is set as the action that will be performed when the Start Call button is tapped. Update the implementation to start a call with the ASACallAgent:

func startCall()
{
    // Ask permissions
    AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
        if granted {
            // start call logic
            let callees:[CommunicationIdentifier] = [CommunicationUserIdentifier(identifier: self.callee)]
            self.call = self.callAgent?.call(participants: callees, options: StartCallOptions())
        }
    }
}

You also can use the properties in StartCallOptions to set the initial options for the call (i.e. it allows starting the call with the microphone muted).

End a call

Implement the endCall method to end the current call when the End Call button is tapped.

func endCall()
{    
    self.call!.hangup(HangupOptions()) { (error) in
        if (error != nil) {
            print("ERROR: It was not possible to hangup the call.")
        }
    }
}

Run the code

You can build and run your app on iOS simulator by selecting Product > Run or by using the (⌘-R) keyboard shortcut.

Final look and feel of the quick start app

You can make an outbound VOIP call by providing a user ID in the text field and tapping the Start Call button. Calling 8:echo123 connects you with an echo bot, this is great for getting started and verifying your audio devices are working.

Note

The first time you make a call, the system will prompt you for access to the microphone. In a production application, you should use the AVAudioSession API to check the permission status and gracefully update your application's behavior when permission is not granted.

Sample Code

You can download the sample app from GitHub

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

For more information, see the following articles: