Partager via


Démarrage rapide : Joindre votre application d’appels à un standard automatique Teams

Dans ce guide de démarrage rapide, vous allez apprendre à démarrer l’appel d’un utilisateur Azure Communication Services vers un standard automatique Teams. Vous allez y parvenir en procédant comme suit :

  1. Activez la fédération de la ressource Azure Communication Services ressource avec le locataire Teams.
  2. Sélectionnez ou créez un standard automatique Teams via le centre d’administration Teams.
  3. Obtenez l’adresse e-mail du standard automatique via le centre d’administration Teams.
  4. Obtenez l’ID d’objet du standard automatique via l’API Graph.
  5. Démarrez un appel avec le kit de développement logiciel (SDK) Azure Communication Services Calling.

Si vous souhaitez passer à la fin, vous pouvez télécharger ce guide de démarrage rapide en guise d’exemple sur GitHub.

Activer l’interopérabilité dans votre locataire Teams

Un utilisateur Microsoft Entra avec un rôle Administrateur Teams peut exécuter la cmdlet PowerShell avec le module Microsoft Teams pour activer la ressource Communication Services dans le locataire.

1. Préparer le module Microsoft Teams

Tout d’abord, ouvrez PowerShell et vérifiez l’existence du module Teams avec la commande suivante :

Get-module *teams* 

Si vous ne voyez pas le module MicrosoftTeams, installez-le d’abord. Pour installer le module, vous devez exécuter PowerShell en tant qu’administrateur. Exécutez ensuite la commande suivante :

	Install-Module -Name MicrosoftTeams

Vous êtes alors informé des modules à installer, que vous pouvez confirmer avec une réponse Y ou A. Si le module est installé mais obsolète, vous pouvez exécuter la commande suivante pour mettre à jour le module :

	Update-Module MicrosoftTeams

2. Se connecter au module Microsoft Teams

Une fois le module installé et prêt, vous pouvez vous connecter au module Microsoft Teams avec la commande suivante. Une fenêtre interactive vous invite à vous connecter. Le compte d’utilisateur que vous utilisez doit avoir des autorisations d’administrateur Teams. Sinon, vous pouvez obtenir une réponse access denied aux étapes suivantes.

Connect-MicrosoftTeams

3. Activer la configuration du locataire

L’interopérabilité avec les ressources Communication Services est contrôlée par la configuration du locataire et la stratégie attribuée. Le locataire Teams a une seule configuration de locataire, et les utilisateurs Teams ont une stratégie générale ou une stratégie personnalisée attribuée. Pour plus d’informations, consultez Attribuer des stratégies dans Teams.

Une fois connecté, vous pouvez exécuter l’applet de commande Set-CsTeamsAcsFederationConfiguration pour activer la ressource Communication Services dans votre locataire. Remplacez le texte IMMUTABLE_RESOURCE_ID par un ID de ressource immuable dans votre ressource de communication. Plus de détails sur l’obtention de ces informations sont disponibles ici.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Activer une stratégie de locataire

Chaque utilisateur Teams a une External Access Policy attribuée qui détermine si les utilisateurs Communication Services peuvent appeler cet utilisateur Teams. Utilisez l’applet de commande Set-CsExternalAccessPolicy pour vérifier que la stratégie attribuée à l’utilisateur Teams a défini EnableAcsFederationAccess sur $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Créer ou sélectionner un standard automatique Teams

Le standard automatique Teams est un système qui fournit un système de gestion automatisée d’appels pour les appels entrants. Il sert de réceptionniste virtuel, ce qui permet aux appelants d’être automatiquement routés vers la personne ou le service approprié sans avoir besoin d’un opérateur humain. Vous pouvez sélectionner un standard automatique existant ou en créer un via le centre d’administration Teams.

Découvrez comment créer un standard automatique à l’aide du centre d’administration Teams ici.

Rechercher l’ID d’objet du standard automatique

Une fois le standard automatique créé, nous devons trouver l’ID d’objet corrélé pour l’utiliser ultérieurement lors des appels. L’ID d’objet est connecté au compte de ressource qui a été attaché au standard automatique. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail du compte. Capture d’écran des comptes de ressource dans le portail d’administration Teams.Vous trouverez toutes les informations nécessaires à un compte de ressource dans Microsoft Graph Explorer en utilisant cet e-mail dans la recherche.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

Dans les résultats, nous pouvons trouver le champ « ID »

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

Prérequis

Configuration

Création d’une application Node.js

Ouvrez votre fenêtre de terminal ou de commande, créez un répertoire pour votre application, puis accédez-y.

mkdir calling-quickstart && cd calling-quickstart

Installer le package

Utilisez la commande npm install pour installer le SDK Azure Communication Services Calling pour JavaScript.

Important

Ce guide de démarrage rapide utilise la version next du SDK Azure Communication Services Calling.

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

Configurer le framework d’application

Ce guide de démarrage rapide utilise webpack pour regrouper les ressources de l’application. Exécutez la commande suivante pour installer les packages npm webpack, webpack-cli et webpack-dev-server, puis listez-les comme dépendances de développement dans votre fichier package.json :

npm install copy-webpack-plugin@^11.0.0 webpack@^5.88.2 webpack-cli@^5.1.4 webpack-dev-server@^4.15.1 --save-dev

Créez un fichier index.html dans le répertoire racine de votre projet. Nous utiliserons ce fichier pour configurer une disposition de base qui permettra à l’utilisateur d’effectuer un appel vidéo 1 à 1.

Voici le code :

<!-- index.html -->
<!DOCTYPE html>
<html>
    <head>
        <title>Azure Communication Services - Calling Web SDK</title>
    </head>
    <body>
        <h4>Azure Communication Services - Calling Web SDK</h4>
        <input id="user-access-token"
            type="text"
            placeholder="User access token"
            style="margin-bottom:1em; width: 500px;"/>
        <button id="initialize-teams-call-agent" type="button">Initialize Call Agent</button>
        <br>
        <br>
        <input id="application-object-id"
            type="text"
            placeholder="Enter application objectId identity in format: 'APP_GUID'"
            style="margin-bottom:1em; width: 500px; display: block;"/>
        <button id="start-call-button" type="button" disabled="true">Start Call</button>
        <button id="hangup-call-button" type="button" disabled="true">Hang up Call</button>
        <button id="accept-call-button" type="button" disabled="true">Accept Call</button>
        <button id="start-video-button" type="button" disabled="true">Start Video</button>
        <button id="stop-video-button" type="button" disabled="true">Stop Video</button>
        <br>
        <br>
        <div id="connectedLabel" style="color: #13bb13;" hidden>Call is connected!</div>
        <br>
        <div id="remoteVideoContainer" style="width: 40%;" hidden>Remote participants' video streams:</div>
        <br>
        <div id="localVideoContainer" style="width: 30%;" hidden>Local video stream:</div>
        <!-- points to the bundle generated from client.js -->
        <script src="./main.js"></script>
    </body>
</html>

Modèle d’objet Azure Communication Services Calling Web SDK

Les classes et les interfaces suivantes gèrent certaines des principales fonctionnalités du SDK Appel Azure Communication Services :

Nom Description
CallClient Point d’entrée principal du SDK Appel.
CallAgent Sert à démarrer et à gérer les appels.
DeviceManager Utilisé pour gérer les appareils multimédias.
Call Utilisé pour représenter un appel.
LocalVideoStream Utilisé pour créer un flux vidéo local pour un appareil photo sur le système local.
RemoteParticipant Utilisé pour représenter un participant distant dans l’appel.
RemoteVideoStream Utilisé pour représenter un flux vidéo distant d’un participant distant.

Créez un fichier dans le répertoire racine de votre projet sous le nom client.js qui contiendra la logique d’application pour ce guide de démarrage rapide. Ajoutez le code suivant à client.js :

// Make sure to install the necessary dependencies
const { CallClient, VideoStreamRenderer, LocalVideoStream } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential } = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the log level and output
setLogLevel('verbose');
AzureLogger.log = (...args) => {
    console.log(...args);
};
// Calling web sdk objects
let callAgent;
let deviceManager;
let call;
let incomingCall;
let localVideoStream;
let localVideoStreamRenderer;
// UI widgets
let userAccessToken = document.getElementById('user-access-token');
let applicationObjectId = document.getElementById('application-object-id');
let initializeCallAgentButton = document.getElementById('initialize-teams-call-agent');
let startCallButton = document.getElementById('start-call-button');
let hangUpCallButton = document.getElementById('hangup-call-button');
let acceptCallButton = document.getElementById('accept-call-button');
let startVideoButton = document.getElementById('start-video-button');
let stopVideoButton = document.getElementById('stop-video-button');
let connectedLabel = document.getElementById('connectedLabel');
let remoteVideoContainer = document.getElementById('remoteVideoContainer');
let localVideoContainer = document.getElementById('localVideoContainer');
/**
 * Create an instance of CallClient. Initialize a CallAgent instance with a AzureCommunicationTokenCredential via created CallClient. CallAgent enables us to make outgoing calls and receive incoming calls. 
 * You can then use the CallClient.getDeviceManager() API instance to get the DeviceManager.
 */
initializeCallAgentButton.onclick = async () => {
    try {
        const callClient = new CallClient(); 
        tokenCredential = new AzureCommunicationTokenCredential(userAccessToken.value.trim());
        callAgent = await callClient.createCallAgent(tokenCredential)
        // Set up a camera device to use.
        deviceManager = await callClient.getDeviceManager();
        await deviceManager.askDevicePermission({ video: true });
        await deviceManager.askDevicePermission({ audio: true });
        // Listen for an incoming call to accept.
        callAgent.on('incomingCall', async (args) => {
            try {
                incomingCall = args.incomingCall;
                acceptCallButton.disabled = false;
                startCallButton.disabled = true;
            } catch (error) {
                console.error(error);
            }
        });
        startCallButton.disabled = false;
        initializeCallAgentButton.disabled = true;
    } catch(error) {
        console.error(error);
    }
}
/**
 * Place a 1:1 outgoing video call to an Teams Auto attendant
 * Add an event listener to initiate a call when the `startCallButton` is selected.
 * Enumerate local cameras using the deviceManager `getCameraList` API.
 * In this quickstart, we're using the first camera in the collection. Once the desired camera is selected, a
 * LocalVideoStream instance will be constructed and passed within `videoOptions` as an item within the
 * localVideoStream array to the call method. When the call connects, your application will be sending a video stream to the other participant. 
 */
startCallButton.onclick = async () => {
    try {
        const localVideoStream = await createLocalVideoStream();
        const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
        call = callAgent.startCall([{ teamsAppId: applicationObjectId.value.trim(), cloud:"public" }], { videoOptions: videoOptions });
        // Subscribe to the call's properties and events.
        subscribeToCall(call);
    } catch (error) {
        console.error(error);
    }
}
/**
 * Accepting an incoming call with a video
 * Add an event listener to accept a call when the `acceptCallButton` is selected.
 * You can accept incoming calls after subscribing to the `CallAgent.on('incomingCall')` event.
 * You can pass the local video stream to accept the call with the following code.
 */
acceptCallButton.onclick = async () => {
    try {
        const localVideoStream = await createLocalVideoStream();
        const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
        call = await incomingCall.accept({ videoOptions });
        // Subscribe to the call's properties and events.
        subscribeToCall(call);
    } catch (error) {
        console.error(error);
    }
}
// Subscribe to a call obj.
// Listen for property changes and collection updates.
subscribeToCall = (call) => {
    try {
        // Inspect the initial call.id value.
        console.log(`Call Id: ${call.id}`);
        //Subscribe to call's 'idChanged' event for value changes.
        call.on('idChanged', () => {
            console.log(`Call ID changed: ${call.id}`); 
        });
        // Inspect the initial call.state value.
        console.log(`Call state: ${call.state}`);
        // Subscribe to call's 'stateChanged' event for value changes.
        call.on('stateChanged', async () => {
            console.log(`Call state changed: ${call.state}`);
            if(call.state === 'Connected') {
                connectedLabel.hidden = false;
                acceptCallButton.disabled = true;
                startCallButton.disabled = true;
                hangUpCallButton.disabled = false;
                startVideoButton.disabled = false;
                stopVideoButton.disabled = false;
            } else if (call.state === 'Disconnected') {
                connectedLabel.hidden = true;
                startCallButton.disabled = false;
                hangUpCallButton.disabled = true;
                startVideoButton.disabled = true;
                stopVideoButton.disabled = true;
                console.log(`Call ended, call end reason={code=${call.callEndReason.code}, subCode=${call.callEndReason.subCode}}`);
            }   
        });

        call.on('isLocalVideoStartedChanged', () => {
            console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
        });
        console.log(`isLocalVideoStarted: ${call.isLocalVideoStarted}`);
        call.localVideoStreams.forEach(async (lvs) => {
            localVideoStream = lvs;
            await displayLocalVideoStream();
        });
        call.on('localVideoStreamsUpdated', e => {
            e.added.forEach(async (lvs) => {
                localVideoStream = lvs;
                await displayLocalVideoStream();
            });
            e.removed.forEach(lvs => {
               removeLocalVideoStream();
            });
        });
        
        // Inspect the call's current remote participants and subscribe to them.
        call.remoteParticipants.forEach(remoteParticipant => {
            subscribeToRemoteParticipant(remoteParticipant);
        });
        // Subscribe to the call's 'remoteParticipantsUpdated' event to be
        // notified when new participants are added to the call or removed from the call.
        call.on('remoteParticipantsUpdated', e => {
            // Subscribe to new remote participants that are added to the call.
            e.added.forEach(remoteParticipant => {
                subscribeToRemoteParticipant(remoteParticipant)
            });
            // Unsubscribe from participants that are removed from the call
            e.removed.forEach(remoteParticipant => {
                console.log('Remote participant removed from the call.');
            });
        });
    } catch (error) {
        console.error(error);
    }
}
// Subscribe to a remote participant obj.
// Listen for property changes and collection updates.
subscribeToRemoteParticipant = (remoteParticipant) => {
    try {
        // Inspect the initial remoteParticipant.state value.
        console.log(`Remote participant state: ${remoteParticipant.state}`);
        // Subscribe to remoteParticipant's 'stateChanged' event for value changes.
        remoteParticipant.on('stateChanged', () => {
            console.log(`Remote participant state changed: ${remoteParticipant.state}`);
        });
        // Inspect the remoteParticipants's current videoStreams and subscribe to them.
        remoteParticipant.videoStreams.forEach(remoteVideoStream => {
            subscribeToRemoteVideoStream(remoteVideoStream)
        });
        // Subscribe to the remoteParticipant's 'videoStreamsUpdated' event to be
        // notified when the remoteParticipant adds new videoStreams and removes video streams.
        remoteParticipant.on('videoStreamsUpdated', e => {
            // Subscribe to newly added remote participant's video streams.
            e.added.forEach(remoteVideoStream => {
                subscribeToRemoteVideoStream(remoteVideoStream)
            });
            // Unsubscribe from newly removed remote participants' video streams.
            e.removed.forEach(remoteVideoStream => {
                console.log('Remote participant video stream was removed.');
            })
        });
    } catch (error) {
        console.error(error);
    }
}
/**
 * Subscribe to a remote participant's remote video stream obj.
 * You have to subscribe to the 'isAvailableChanged' event to render the remoteVideoStream. If the 'isAvailable' property
 * changes to 'true' a remote participant is sending a stream. Whenever the availability of a remote stream changes
 * you can choose to destroy the whole 'Renderer' a specific 'RendererView' or keep them. Displaying RendererView without a video stream will result in a blank video frame. 
 */
subscribeToRemoteVideoStream = async (remoteVideoStream) => {
    // Create a video stream renderer for the remote video stream.
    let videoStreamRenderer = new VideoStreamRenderer(remoteVideoStream);
    let view;
    const renderVideo = async () => {
        try {
            // Create a renderer view for the remote video stream.
            view = await videoStreamRenderer.createView();
            // Attach the renderer view to the UI.
            remoteVideoContainer.hidden = false;
            remoteVideoContainer.appendChild(view.target);
        } catch (e) {
            console.warn(`Failed to createView, reason=${e.message}, code=${e.code}`);
        }	
    }
    
    remoteVideoStream.on('isAvailableChanged', async () => {
        // Participant has switched video on.
        if (remoteVideoStream.isAvailable) {
            await renderVideo();
        // Participant has switched video off.
        } else {
            if (view) {
                view.dispose();
                view = undefined;
            }
        }
    });
    // Participant has video on initially.
    if (remoteVideoStream.isAvailable) {
        await renderVideo();
    }
}
// Start your local video stream.
// This will send your local video stream to remote participants so they can view it.
startVideoButton.onclick = async () => {
    try {
        const localVideoStream = await createLocalVideoStream();
        await call.startVideo(localVideoStream);
    } catch (error) {
        console.error(error);
    }
}
// Stop your local video stream.
// This will stop your local video stream from being sent to remote participants.
stopVideoButton.onclick = async () => {
    try {
        await call.stopVideo(localVideoStream);
    } catch (error) {
        console.error(error);
    }
}
/**
 * To render a LocalVideoStream, you need to create a new instance of VideoStreamRenderer, and then
 * create a new VideoStreamRendererView instance using the asynchronous createView() method.
 * You may then attach view.target to any UI element. 
 */
// Create a local video stream for your camera device
createLocalVideoStream = async () => {
    const camera = (await deviceManager.getCameras())[0];
    if (camera) {
        return new LocalVideoStream(camera);
    } else {
        console.error(`No camera device found on the system`);
    }
}
// Display your local video stream preview in your UI
displayLocalVideoStream = async () => {
    try {
        localVideoStreamRenderer = new VideoStreamRenderer(localVideoStream);
        const view = await localVideoStreamRenderer.createView();
        localVideoContainer.hidden = false;
        localVideoContainer.appendChild(view.target);
    } catch (error) {
        console.error(error);
    } 
}
// Remove your local video stream preview from your UI
removeLocalVideoStream = async() => {
    try {
        localVideoStreamRenderer.dispose();
        localVideoContainer.hidden = true;
    } catch (error) {
        console.error(error);
    } 
}
// End the current call
hangUpCallButton.addEventListener("click", async () => {
    // end the current call
    await call.hangUp();
});

Ajouter le code du serveur local webpack

Créez un fichier dans le répertoire racine de votre projet sous le nom webpack.config.js qui contiendra la logique de serveur local pour ce guide de démarrage rapide. Ajoutez le code suivant à webpack.config.js :

const path = require('path');
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
    mode: 'development',
    entry: './client.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
    },
    devServer: {
        static: {
            directory: path.join(__dirname, './')
        },
    },
    plugins: [
        new CopyPlugin({
            patterns: [
                './index.html'
            ]
        }),
    ]
};

Exécuter le code

Utilisez webpack-dev-server pour créer et exécuter votre application. Exécutez la commande suivante pour créer un bundle de l’application hôte sur un serveur web local :

npx webpack serve --config webpack.config.js

Étapes manuelles pour configurer l’appel :

  1. Ouvrez votre navigateur et accédez à l’adresse http://localhost:8080/..
  2. Entrez un jeton d’accès utilisateur valide. Consultez la documentation sur les jetons d’accès utilisateur si vous n’avez pas encore de jeton d’accès disponible.
  3. Cliquez sur les boutons « Initialiser l’agent d’appel ».
  4. Entrez l’ID d’objet du standard automatique, puis sélectionnez le bouton « Démarrer l’appel ». L’application démarre l’appel sortant vers le standard automatique avec l’ID d’objet donné.
  5. L’appel est connecté au standard automatique.
  6. L’utilisateur Communication Services est routé via le standard automatique selon sa configuration.

Important

Cette fonctionnalité d’Azure Communication Services est actuellement en préversion.

Ces interfaces de programmation d’applications et kits de développement logiciel (SDK) en préversion sont fournis sans contrat au niveau du service. Nous vous recommandons de ne pas les utiliser pour les charges de travail de production. Certaines fonctionnalités peuvent être limitées ou non prises en charge.

Pour plus d’informations, consultez Conditions d’utilisation supplémentaires relatives aux préversions de Microsoft Azure.

Dans ce guide de démarrage rapide, vous allez apprendre à démarrer l’appel d’un utilisateur Azure Communication Services vers un standard automatique Teams. Vous allez y parvenir en procédant comme suit :

  1. Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
  2. Sélectionnez ou créez un standard automatique Teams via le centre d’administration Teams.
  3. Obtenez l’adresse e-mail du standard automatique via le centre d’administration Teams.
  4. Obtenez l’ID d’objet du standard automatique via l’API Graph.
  5. Démarrez un appel avec le kit de développement logiciel (SDK) Azure Communication Services Calling.

Si vous souhaitez passer à la fin, vous pouvez télécharger ce guide de démarrage rapide en guise d’exemple sur GitHub.

Activer l’interopérabilité dans votre locataire Teams

Un utilisateur Microsoft Entra avec un rôle Administrateur Teams peut exécuter la cmdlet PowerShell avec le module Microsoft Teams pour activer la ressource Communication Services dans le locataire.

1. Préparer le module Microsoft Teams

Tout d’abord, ouvrez PowerShell et vérifiez l’existence du module Teams avec la commande suivante :

Get-module *teams* 

Si vous ne voyez pas le module MicrosoftTeams, installez-le d’abord. Pour installer le module, vous devez exécuter PowerShell en tant qu’administrateur. Exécutez ensuite la commande suivante :

	Install-Module -Name MicrosoftTeams

Vous êtes alors informé des modules à installer, que vous pouvez confirmer avec une réponse Y ou A. Si le module est installé mais obsolète, vous pouvez exécuter la commande suivante pour mettre à jour le module :

	Update-Module MicrosoftTeams

2. Se connecter au module Microsoft Teams

Une fois le module installé et prêt, vous pouvez vous connecter au module Microsoft Teams avec la commande suivante. Une fenêtre interactive vous invite à vous connecter. Le compte d’utilisateur que vous utilisez doit avoir des autorisations d’administrateur Teams. Sinon, vous pouvez obtenir une réponse access denied aux étapes suivantes.

Connect-MicrosoftTeams

3. Activer la configuration du locataire

L’interopérabilité avec les ressources Communication Services est contrôlée par la configuration du locataire et la stratégie attribuée. Le locataire Teams a une seule configuration de locataire, et les utilisateurs Teams ont une stratégie générale ou une stratégie personnalisée attribuée. Pour plus d’informations, consultez Attribuer des stratégies dans Teams.

Une fois connecté, vous pouvez exécuter l’applet de commande Set-CsTeamsAcsFederationConfiguration pour activer la ressource Communication Services dans votre locataire. Remplacez le texte IMMUTABLE_RESOURCE_ID par un ID de ressource immuable dans votre ressource de communication. Plus de détails sur l’obtention de ces informations sont disponibles ici.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Activer une stratégie de locataire

Chaque utilisateur Teams a une External Access Policy attribuée qui détermine si les utilisateurs Communication Services peuvent appeler cet utilisateur Teams. Utilisez l’applet de commande Set-CsExternalAccessPolicy pour vérifier que la stratégie attribuée à l’utilisateur Teams a défini EnableAcsFederationAccess sur $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Créer ou sélectionner un standard automatique Teams

Le standard automatique Teams est un système qui fournit un système de gestion automatisée d’appels pour les appels entrants. Il sert de réceptionniste virtuel, ce qui permet aux appelants d’être automatiquement routés vers la personne ou le service approprié sans avoir besoin d’un opérateur humain. Vous pouvez sélectionner un standard automatique existant ou en créer un via le centre d’administration Teams.

Découvrez comment créer un standard automatique à l’aide du centre d’administration Teams ici.

Rechercher l’ID d’objet du standard automatique

Une fois le standard automatique créé, nous devons trouver l’ID d’objet corrélé pour l’utiliser ultérieurement lors des appels. L’ID d’objet est connecté au compte de ressource qui a été attaché au standard automatique. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail du compte. Capture d’écran des comptes de ressource dans le portail d’administration Teams.Vous trouverez toutes les informations nécessaires à un compte de ressource dans Microsoft Graph Explorer en utilisant cet e-mail dans la recherche.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

Dans les résultats, nous pouvons trouver le champ « ID »

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

Pour l’utiliser dans l’application appelante, nous devons ajouter un préfixe à cet ID. À l’heure actuelle, les éléments suivants sont pris en charge :

  • Standard automatique du cloud public : 28:orgid:<id>
  • Standard automatique du cloud du gouvernement : 28:gcch:<id>

Prérequis

Configuration

Créer une application Android avec une activité vide

Dans Android Studio, sélectionnez Start a new Android Studio project (Commencer un nouveau projet Android Studio).

Capture d’écran montrant le bouton « Start a new Android Studio Project » sélectionné dans Android Studio.

Sélectionnez le modèle de projet « Empty Views Activity » sous « Phone and Tablet ».

Capture d’écran montrant l’option « Empty Activity » sélectionnée dans l’écran Project Template.

Sélectionnez le kit de développement logiciel (SDK) minimal « API 26 : Android 8.0 (Oreo) » ou version ultérieure.

Capture d’écran montrant l’option « Empty Activity » sélectionnée dans l’écran 2 Project Template.

Installer le package

Recherchez votre projet settings.gradle.kts et vérifiez que mavenCentral() est bien dans la liste des référentiels sous pluginManagement et dependencyResolutionManagement.

pluginManagement {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
    ...
        mavenCentral()
    }
}

Ensuite, dans votre niveau de module build.gradle, ajoutez les lignes suivantes aux sections dependencies et android.

android {
    ...
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    ...
    implementation ("com.azure.android:azure-communication-calling:2.6.0")
    ...
}

Ajouter des autorisations au manifeste de l’application

Afin de pouvoir demander les autorisations nécessaires pour effectuer un appel, vous devez les déclarer dans le manifeste de l’application (app/src/main/AndroidManifest.xml). Remplacez le contenu du fichier par ce code :

    <?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>
    

Configurer la disposition de l’application

Deux entrées sont nécessaires : une entrée de texte pour l’ID de l’appelé et un bouton pour établir l’appel. Ces entrées peuvent être ajoutées par le biais du concepteur ou en modifiant le fichier XML de disposition. Créez un bouton avec call_button comme ID et callee_id comme entrée de texte. Accédez à (app/src/main/res/layout/activity_main.xml) et remplacez le contenu du fichier par ce code :

<?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>

Créer la génération de modèles automatique et les liaisons de l’activité principale

La mise en page étant créée, nous pouvons ajouter les liaisons ainsi que la génération de modèles automatique de base de l’activité. L’activité gère les demandes d’autorisations de runtime, la création de l’agent d’appel et l’établissement de l’appel si le bouton est appuyé. La méthode onCreate est remplacée pour appeler getAllPermissions et createAgent, et pour ajouter les liaisons pour le bouton d’appel. Cet événement ne se produit qu’une seule fois lors de la création de l’activité. Pour plus d’informations sur onCreate, consultez le guide Présentation du cycle de vie des activités.

Accédez à MainActivity.java et remplacez le contenu par le code suivant :

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));
    }
}

Demander des autorisations au moment de l’exécution

Pour Android 6.0 et ultérieur (niveau d’API 23) et targetSdkVersion 23 ou plus, les autorisations sont accordées au moment de l’exécution et non lors de l’installation de l’application. Pour le prendre en charge, vous pouvez implémenter getAllPermissions afin d’appeler ActivityCompat.checkSelfPermission et ActivityCompat.requestPermissions pour chaque autorisation requise.

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

Notes

Lorsque vous concevez votre application, tenez compte du moment où ces autorisations doivent être demandées. Les autorisations doivent être demandées lorsqu’elles sont nécessaires, et non à l’avance. Pour plus d’informations, consultez le guide des autorisations Android.

Modèle objet

Les classes et les interfaces suivantes gèrent certaines des principales fonctionnalités du SDK Azure Communication Services Calling :

Nom Description
CallClient CallClient est le point d’entrée principal du SDK Appel.
CallAgent CallAgent sert à démarrer et à gérer les appels.
CommunicationTokenCredential CommunicationTokenCredential sert de jeton d’informations d'identification pour initier le CallAgent.
CommunicationIdentifier CommunicationIdentifier sert de type de participant différent susceptible de faire partie d’un appel.

Créer un agent à partir du jeton d’accès utilisateur

Avec un jeton utilisateur, un agent d’appel authentifié peut être instancié. En règle général, ce jeton est généré à partir d’un service avec une authentification propre à l’application. Pour plus d’informations sur les jetons d’accès utilisateur, consultez le guide Jetons d’accès utilisateur.

Pour les besoins de ce guide de démarrage rapide, remplacez <User_Access_Token> par un jeton d’accès utilisateur généré pour votre ressource Azure Communication Services.


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

Exécuter le code

Vous pouvez maintenant lancer l’application à l’aide du bouton Exécuter l’application dans la barre d’outils.

Étapes manuelles pour configurer l’appel :

  1. Lancez l’application à l’aide d’Android Studio.
  2. Entrez l’ID d’objet du standard automatique (avec préfixe), puis sélectionnez le bouton « Démarrer l’appel ». L’application démarre l’appel sortant vers le standard automatique avec l’ID d’objet donné.
  3. L’appel est connecté au standard automatique.
  4. L’utilisateur Communication Services est routé via le standard automatique selon sa configuration.

Important

Cette fonctionnalité d’Azure Communication Services est actuellement en préversion.

Ces interfaces de programmation d’applications et kits de développement logiciel (SDK) en préversion sont fournis sans contrat au niveau du service. Nous vous recommandons de ne pas les utiliser pour les charges de travail de production. Certaines fonctionnalités peuvent être limitées ou non prises en charge.

Pour plus d’informations, consultez Conditions d’utilisation supplémentaires relatives aux préversions de Microsoft Azure.

Dans ce guide de démarrage rapide, vous allez apprendre à démarrer l’appel d’un utilisateur Azure Communication Services vers un standard automatique Teams. Vous allez y parvenir en procédant comme suit :

  1. Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
  2. Sélectionnez ou créez un standard automatique Teams via le centre d’administration Teams.
  3. Obtenez l’adresse e-mail du standard automatique via le centre d’administration Teams.
  4. Obtenez l’ID d’objet du standard automatique via l’API Graph.
  5. Démarrez un appel avec le kit de développement logiciel (SDK) Azure Communication Services Calling.

Si vous souhaitez passer à la fin, vous pouvez télécharger ce guide de démarrage rapide en guise d’exemple sur GitHub.

Activer l’interopérabilité dans votre locataire Teams

Un utilisateur Microsoft Entra avec un rôle Administrateur Teams peut exécuter la cmdlet PowerShell avec le module Microsoft Teams pour activer la ressource Communication Services dans le locataire.

1. Préparer le module Microsoft Teams

Tout d’abord, ouvrez PowerShell et vérifiez l’existence du module Teams avec la commande suivante :

Get-module *teams* 

Si vous ne voyez pas le module MicrosoftTeams, installez-le d’abord. Pour installer le module, vous devez exécuter PowerShell en tant qu’administrateur. Exécutez ensuite la commande suivante :

	Install-Module -Name MicrosoftTeams

Vous êtes alors informé des modules à installer, que vous pouvez confirmer avec une réponse Y ou A. Si le module est installé mais obsolète, vous pouvez exécuter la commande suivante pour mettre à jour le module :

	Update-Module MicrosoftTeams

2. Se connecter au module Microsoft Teams

Une fois le module installé et prêt, vous pouvez vous connecter au module Microsoft Teams avec la commande suivante. Une fenêtre interactive vous invite à vous connecter. Le compte d’utilisateur que vous utilisez doit avoir des autorisations d’administrateur Teams. Sinon, vous pouvez obtenir une réponse access denied aux étapes suivantes.

Connect-MicrosoftTeams

3. Activer la configuration du locataire

L’interopérabilité avec les ressources Communication Services est contrôlée par la configuration du locataire et la stratégie attribuée. Le locataire Teams a une seule configuration de locataire, et les utilisateurs Teams ont une stratégie générale ou une stratégie personnalisée attribuée. Pour plus d’informations, consultez Attribuer des stratégies dans Teams.

Une fois connecté, vous pouvez exécuter l’applet de commande Set-CsTeamsAcsFederationConfiguration pour activer la ressource Communication Services dans votre locataire. Remplacez le texte IMMUTABLE_RESOURCE_ID par un ID de ressource immuable dans votre ressource de communication. Plus de détails sur l’obtention de ces informations sont disponibles ici.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Activer une stratégie de locataire

Chaque utilisateur Teams a une External Access Policy attribuée qui détermine si les utilisateurs Communication Services peuvent appeler cet utilisateur Teams. Utilisez l’applet de commande Set-CsExternalAccessPolicy pour vérifier que la stratégie attribuée à l’utilisateur Teams a défini EnableAcsFederationAccess sur $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Créer ou sélectionner un standard automatique Teams

Le standard automatique Teams est un système qui fournit un système de gestion automatisée d’appels pour les appels entrants. Il sert de réceptionniste virtuel, ce qui permet aux appelants d’être automatiquement routés vers la personne ou le service approprié sans avoir besoin d’un opérateur humain. Vous pouvez sélectionner un standard automatique existant ou en créer un via le centre d’administration Teams.

Découvrez comment créer un standard automatique à l’aide du centre d’administration Teams ici.

Rechercher l’ID d’objet du standard automatique

Une fois le standard automatique créé, nous devons trouver l’ID d’objet corrélé pour l’utiliser ultérieurement lors des appels. L’ID d’objet est connecté au compte de ressource qui a été attaché au standard automatique. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail du compte. Capture d’écran des comptes de ressource dans le portail d’administration Teams.Vous trouverez toutes les informations nécessaires à un compte de ressource dans Microsoft Graph Explorer en utilisant cet e-mail dans la recherche.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

Dans les résultats, nous pouvons trouver le champ « ID »

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

Pour l’utiliser dans l’application appelante, nous devons ajouter un préfixe à cet ID. À l’heure actuelle, les éléments suivants sont pris en charge :

  • Standard automatique du cloud public : 28:orgid:<id>
  • Standard automatique du cloud du gouvernement : 28:gcch:<id>

Prérequis

  • Obtenez un compte Azure avec un abonnement actif. Créez un compte gratuitement.

  • Un Mac exécutant Xcode, ainsi qu’un certificat de développeur valide installé dans votre trousseau

  • Une ressource Communication Services déployée. Créez une ressource Communication Services. Vous devez enregistrer votre chaîne de connexion pour ce guide de démarrage rapide.

  • Un jeton d’accès utilisateur pour votre service Azure Communication Vous pouvez également utiliser Azure CLI et exécuter la commande avec votre chaîne de connexion pour créer un utilisateur et un jeton d’accès.

    az communication identity token issue --scope voip --connection-string "yourConnectionString"
    

    Pour plus d’informations, consultez Utiliser Azure CLI pour créer et gérer des jetons d’accès.

  • Prise en charge minimale des applications d’appel Teams : 2.14.0-beta.1

Configuration

Création du projet Xcode

Dans Xcode, créez un projet iOS et sélectionnez le modèle App. Ce tutoriel utilise le framework SwiftUI ; vous devez donc définir Swift comme langage et SwiftUI comme interface utilisateur. Vous n’allez pas créer de tests au cours de ce guide démarrage rapide. N’hésitez pas à décocher Inclure des tests.

Capture d’écran représentant la fenêtre Nouveau projet dans Xcode.

Installer le package et les dépendances avec CocoaPods

  1. Afin de créer un Podfile pour votre application, ouvrez le terminal, accédez au dossier du projet, puis exécutez :

    pod init

  2. Ajoutez le code suivant au Podfile et enregistrez-le (assurez-vous que la cible correspond au nom de votre projet) :

    platform :ios, '13.0'
    use_frameworks!
    
    target 'AzureCommunicationCallingSample' do
      pod 'AzureCommunicationCalling', '~> 2.14.0-beta.1'
    end
    
  3. Exécutez pod install.

  4. Ouvrez le .xcworkspace avec Xcode.

Demander l’accès au microphone

Pour accéder au microphone de l’appareil, vous devez mettre à jour la liste des propriétés d’informations de votre application avec un NSMicrophoneUsageDescription. Vous affectez une valeur string comme valeur associée qui était incluse dans la boîte de dialogue utilisée par le système pour demander l’accès de l’utilisateur.

Cliquez avec le bouton droit sur l’entrée Info.plist de l’arborescence du projet, puis sélectionnez Open As>Source Code. Ajoutez les lignes suivantes dans la section <dict> tout en haut, puis enregistrez le fichier.

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

Configurer le framework d’application

Ouvrez le fichier ContentView.swift de votre projet et ajoutez une déclaration import en haut du fichier pour importer l’AzureCommunicationCalling library. Importez également AVFoundation. Il est nécessaire pour la demande d’autorisation audio dans le code.

import AzureCommunicationCalling
import AVFoundation

Remplacez l’implémentation du struct ContentView par des contrôles d’interface utilisateur simples qui permettent à un utilisateur de lancer et de terminer un appel. Dans ce démarrage rapide, nous allons attacher une logique métier à ces contrôles.

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
    }
}

Modèle objet

Les classes et les interfaces suivantes gèrent certaines des principales fonctionnalités du SDK Azure Communication Services Calling :

Nom Description
CallClient CallClient est le point d’entrée principal du SDK Appel.
CallAgent CallAgent sert à démarrer et à gérer les appels.
CommunicationTokenCredential CommunicationTokenCredential sert de jeton d’informations d'identification pour initier le CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier sert à représenter l’identité de l’utilisateur, parmi l’une des options suivantes : CommunicationUserIdentifier, PhoneNumberIdentifier ou CallingApplication.

Authentifier le client

Initialisez une instance CallAgent avec un jeton d’accès utilisateur qui permettra d’établir et de recevoir des appels.

Dans le code suivant, vous devez remplacer <USER ACCESS TOKEN> par un jeton d’accès utilisateur valide pour votre ressource. Consultez la documentation sur les jetons d’accès utilisateur si vous n’avez pas encore de jeton disponible.

Ajoutez le code suivant au rappel onAppear dans 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
    }
    else {
        self.callAgent = agent
        print("Call agent successfully created.")
    }
}

Démarrer un appel

La méthode startCall est définie en tant qu’action qui sera exécutée lors d’un appui sur le bouton Démarrer l’appel. Mettez à jour l’implémentation pour démarrer un appel avec ASACallAgent :

func startCall()
{
    // Ask permissions
    AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
        if granted {
            // start call logic
            let callees:[CommunicationIdentifier] = [MicrosoftTeamsAppIdentifier(self.callee)]
            self.callAgent?.startCall(participants: callees, options: StartCallOptions()) { (call, error) in
                if (error == nil) {
                    self.call = call
                } else {
                    print("Failed to get call object")
                }
            }
        }
    }
}

Vous pouvez également utiliser les propriétés dans StartCallOptions pour définir les options initiales de l’appel (cela permet de démarrer l’appel avec le micro coupé).

Terminer un appel

Implémentez la méthode endCall pour terminer l’appel en cours en cas d’appui sur le bouton End Call.

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

Exécuter le code

Vous pouvez générer et exécuter votre application sur un simulateur iOS en sélectionnant Product>Run ou en utilisant le raccourci clavier (⌘-R).

Remarque

La première fois que vous effectuez un appel, le système vous invite à accorder l’accès au microphone. Dans une application de production, vous devez utiliser l’API AVAudioSession pour vérifier l’état de l’autorisation et mettre à jour le comportement de votre application de manière appropriée quand l’autorisation n’est pas accordée.

Étapes manuelles pour configurer l’appel :

  1. Lancer l’application à l’aide de Xcode
  2. Entrez l’ID d’objet du standard automatique (avec préfixe), puis sélectionnez le bouton « Démarrer l’appel ». L’application démarre l’appel sortant vers le standard automatique avec l’ID d’objet donné.
  3. L’appel est connecté au standard automatique.
  4. L’utilisateur Communication Services est routé via le standard automatique selon sa configuration.

Important

Cette fonctionnalité d’Azure Communication Services est actuellement en préversion.

Ces interfaces de programmation d’applications et kits de développement logiciel (SDK) en préversion sont fournis sans contrat au niveau du service. Nous vous recommandons de ne pas les utiliser pour les charges de travail de production. Certaines fonctionnalités peuvent être limitées ou non prises en charge.

Pour plus d’informations, consultez Conditions d’utilisation supplémentaires relatives aux préversions de Microsoft Azure.

Dans ce guide de démarrage rapide, vous allez apprendre à démarrer l’appel d’un utilisateur Azure Communication Services vers un standard automatique Teams. Vous allez y parvenir en procédant comme suit :

  1. Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
  2. Sélectionnez ou créez un standard automatique Teams via le centre d’administration Teams.
  3. Obtenez l’adresse e-mail du standard automatique via le centre d’administration Teams.
  4. Obtenez l’ID d’objet du standard automatique via l’API Graph.
  5. Démarrez un appel avec le kit de développement logiciel (SDK) Azure Communication Services Calling.

Si vous souhaitez passer à la fin, vous pouvez télécharger ce guide de démarrage rapide en guise d’exemple sur GitHub.

Activer l’interopérabilité dans votre locataire Teams

Un utilisateur Microsoft Entra avec un rôle Administrateur Teams peut exécuter la cmdlet PowerShell avec le module Microsoft Teams pour activer la ressource Communication Services dans le locataire.

1. Préparer le module Microsoft Teams

Tout d’abord, ouvrez PowerShell et vérifiez l’existence du module Teams avec la commande suivante :

Get-module *teams* 

Si vous ne voyez pas le module MicrosoftTeams, installez-le d’abord. Pour installer le module, vous devez exécuter PowerShell en tant qu’administrateur. Exécutez ensuite la commande suivante :

	Install-Module -Name MicrosoftTeams

Vous êtes alors informé des modules à installer, que vous pouvez confirmer avec une réponse Y ou A. Si le module est installé mais obsolète, vous pouvez exécuter la commande suivante pour mettre à jour le module :

	Update-Module MicrosoftTeams

2. Se connecter au module Microsoft Teams

Une fois le module installé et prêt, vous pouvez vous connecter au module Microsoft Teams avec la commande suivante. Une fenêtre interactive vous invite à vous connecter. Le compte d’utilisateur que vous utilisez doit avoir des autorisations d’administrateur Teams. Sinon, vous pouvez obtenir une réponse access denied aux étapes suivantes.

Connect-MicrosoftTeams

3. Activer la configuration du locataire

L’interopérabilité avec les ressources Communication Services est contrôlée par la configuration du locataire et la stratégie attribuée. Le locataire Teams a une seule configuration de locataire, et les utilisateurs Teams ont une stratégie générale ou une stratégie personnalisée attribuée. Pour plus d’informations, consultez Attribuer des stratégies dans Teams.

Une fois connecté, vous pouvez exécuter l’applet de commande Set-CsTeamsAcsFederationConfiguration pour activer la ressource Communication Services dans votre locataire. Remplacez le texte IMMUTABLE_RESOURCE_ID par un ID de ressource immuable dans votre ressource de communication. Plus de détails sur l’obtention de ces informations sont disponibles ici.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Activer une stratégie de locataire

Chaque utilisateur Teams a une External Access Policy attribuée qui détermine si les utilisateurs Communication Services peuvent appeler cet utilisateur Teams. Utilisez l’applet de commande Set-CsExternalAccessPolicy pour vérifier que la stratégie attribuée à l’utilisateur Teams a défini EnableAcsFederationAccess sur $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Créer ou sélectionner un standard automatique Teams

Le standard automatique Teams est un système qui fournit un système de gestion automatisée d’appels pour les appels entrants. Il sert de réceptionniste virtuel, ce qui permet aux appelants d’être automatiquement routés vers la personne ou le service approprié sans avoir besoin d’un opérateur humain. Vous pouvez sélectionner un standard automatique existant ou en créer un via le centre d’administration Teams.

Découvrez comment créer un standard automatique à l’aide du centre d’administration Teams ici.

Rechercher l’ID d’objet du standard automatique

Une fois le standard automatique créé, nous devons trouver l’ID d’objet corrélé pour l’utiliser ultérieurement lors des appels. L’ID d’objet est connecté au compte de ressource qui a été attaché au standard automatique. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail du compte. Capture d’écran des comptes de ressource dans le portail d’administration Teams.Vous trouverez toutes les informations nécessaires à un compte de ressource dans Microsoft Graph Explorer en utilisant cet e-mail dans la recherche.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

Dans les résultats, nous pouvons trouver le champ « ID »

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

Pour l’utiliser dans l’application appelante, nous devons ajouter un préfixe à cet ID. À l’heure actuelle, les éléments suivants sont pris en charge :

  • Standard automatique du cloud public : 28:orgid:<id>
  • Standard automatique du cloud du gouvernement : 28:gcch:<id>

Prérequis

Pour effectuer ce didacticiel, vous avez besoin de ce qui suit :

Configuration

Création du projet

Dans Visual Studio, créez un projet avec le modèle Application vide (Windows universel) pour configurer une application de plateforme Windows universelle (UWP) monopage.

Capture d’écran montrant la fenêtre Nouveau projet UWP dans Visual Studio.

Installer le package

Cliquez avec le bouton droit sur votre projet et accédez à Manage Nuget Packages pour installer la version Azure.Communication.Calling.WindowsClient 1.4.0 ou supérieure. Vérifiez que Include Prerelease est coché si vous souhaitez voir les versions de la préversion publique.

Demander l'accès

Accédez à Package.appxmanifest et sélectionnez Capabilities. Cochez la case Internet (Client) et Internet (Client & Server) pour obtenir un accès entrant et sortant à Internet. Vérifiez Microphone pour accéder au flux audio du microphone et Webcam au flux vidéo de la caméra.

Capture d’écran montrant la demande d’accès à Internet et au microphone dans Visual Studio.

Configurer le framework d’application

Nous devons configurer une disposition de base pour attacher notre logique. Afin de passer un appel sortant, nous avons besoin d’une TextBox pour fournir l’ID d’utilisateur de l’appelé. Nous avons également besoin d’un bouton Start/Join call et d’un bouton Hang up. Des Mute cases à cocher et un BackgroundBlur sont également inclus dans cet exemple pour illustrer les fonctionnalités de basculement des états audio et des effets vidéo.

Ouvrez le fichier MainPage.xaml de votre projet et ajoutez le nœud Grid à votre Page :

<Page
    x:Class="CallingQuickstart.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CallingQuickstart"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Width="800" Height="600">

        <!-- Don't forget to replace ‘CallingQuickstart’ with your project’s name -->


    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="16*"/>
            <RowDefinition Height="30*"/>
            <RowDefinition Height="200*"/>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="16*"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="10,10,10,10" />

        <Grid x:Name="AppTitleBar" Background="LightSeaGreen">
            <TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="7,7,0,0"/>
        </Grid>

        <Grid Grid.Row="2">
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <MediaPlayerElement x:Name="LocalVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="0" VerticalAlignment="Center" AutoPlay="True" />
            <MediaPlayerElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center" AutoPlay="True" />
        </Grid>
        <StackPanel Grid.Row="3" Orientation="Vertical" Grid.RowSpan="2">
            <StackPanel Orientation="Horizontal">
                <Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
                <Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
                <CheckBox x:Name="MuteLocal" Content="Mute" Margin="10,0,0,0" Click="MuteLocal_Click" Width="74"/>
            </StackPanel>
        </StackPanel>
        <TextBox Grid.Row="5" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
    </Grid>
</Page>

Ouvrez le fichier MainPage.xaml.cs et remplacez le contenu par l’implémentation suivante :

using Azure.Communication.Calling.WindowsClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Media.Core;
using Windows.Networking.PushNotifications;
using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace CallingQuickstart
{
    public sealed partial class MainPage : Page
    {
        private const string authToken = "<AUTHENTICATION_TOKEN>";

        private CallClient callClient;
        private CallTokenRefreshOptions callTokenRefreshOptions = new CallTokenRefreshOptions(false);
        private CallAgent callAgent;
        private CommunicationCall call;

        private LocalOutgoingAudioStream micStream;

        #region Page initialization
        public MainPage()
        {
            this.InitializeComponent();
            // Additional UI customization code goes here
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            await InitCallAgentAndDeviceManagerAsync();

            base.OnNavigatedTo(e);
        }
        #endregion

        #region UI event handlers
        private async void CallButton_Click(object sender, RoutedEventArgs e)
        {
            // Start a call
        }

        private async void HangupButton_Click(object sender, RoutedEventArgs e)
        {
            // Hang up a call
        }

        private async void MuteLocal_Click(object sender, RoutedEventArgs e)
        {
            // Toggle mute/unmute audio state of a call
        }
        #endregion

        #region API event handlers
        private async void OnIncomingCallAsync(object sender, IncomingCallReceivedEventArgs args)
        {
            // Handle incoming call event
        }

        private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
        {
            // Handle connected and disconnected state change of a call
        }
        #endregion

        #region Helper methods

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            //Initialize the call agent and search for devices
        }


        private async Task<CommunicationCall> StartCallAsync(string acsCallee)
        {
            // Start a call to an Azure Communication Services user using the CallAgent and the callee id
        }

        #endregion
    }
}

Modèle objet

Le tableau suivant a répertorié les classes et interfaces suivantes gèrent certaines des principales fonctionnalités du SDK Appel d’Azure Communication Services :

Nom Description
CallClient CallClient est le point d’entrée principal du SDK Appel.
CallAgent CallAgent sert à démarrer et à gérer les appels.
CommunicationCall Le CommunicationCall est utilisé pour gérer un appel en cours.
CallTokenCredential CallTokenCredential sert de jeton d’informations d'identification pour initier le CallAgent.
CallIdentifier CallIdentifier sert à représenter l’identité de l’utilisateur, parmi l’une des options suivantes : UserCallIdentifier, PhoneNumberCallIdentifier, etc.

Authentifier le client

Initialisez une instance CallAgent avec un jeton d’accès utilisateur qui permet de passer et de recevoir des appels, et éventuellement d’obtenir une instance DeviceManager pour rechercher des configurations d’appareil client.

Dans le code, remplacez <AUTHENTICATION_TOKEN> par un jeton d’accès utilisateur. Consultez la documentation sur les jetons d’accès utilisateur si vous n’avez pas encore de jeton disponible.

Ajouter InitCallAgentAndDeviceManagerAsync une fonction, qui démarre le KIT de développement logiciel (SDK). Cette assistance peut être personnalisée pour répondre aux exigences de votre application.

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            this.callClient = new CallClient(new CallClientOptions() {
                Diagnostics = new CallDiagnosticsOptions() { 
                    
                    // make sure to put your project AppName
                    AppName = "CallingQuickstart",

                    AppVersion="1.0",

                    Tags = new[] { "Calling", "ACS", "Windows" }
                    }

                });

            // Set up local audio stream using the first mic enumerated
            var deviceManager = await this.callClient.GetDeviceManagerAsync();
            var mic = deviceManager?.Microphones?.FirstOrDefault();

            micStream = new LocalOutgoingAudioStream();

            var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);

            var callAgentOptions = new CallAgentOptions()
            {
                DisplayName = $"{Environment.MachineName}/{Environment.UserName}",
            };

            this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);

            this.callAgent.IncomingCallReceived += OnIncomingCallAsync;
        }

Commencer l’appel

Une fois qu’un objet StartCallOptions est obtenu, CallAgent peut être utilisé pour lancer l’appel Azure Communication Services :

        private async Task<CommunicationCall> StartCallAsync(string acsCallee)
        {
            var options = new StartCallOptions();
            var call = await this.callAgent.StartCallAsync( new [] { new MicrosoftTeamsAppCallIdentifier(acsCallee) }, options);
            return call;
        }

Terminer un appel

Terminez l’appel en cours quand l’utilisateur clique sur le bouton Hang up. Ajoutez l’implémentation à l’HangupButton_Click pour mettre fin à un appel et arrêter les flux d’aperçu et de vidéo.

        private async void HangupButton_Click(object sender, RoutedEventArgs e)
        {
            var call = this.callAgent?.Calls?.FirstOrDefault();
            if (call != null)
            {
                await call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
            }
        }

Activer/désactiver le son

Désactivez le son sortant lorsque vous cliquez sur le Mute bouton. Ajoutez l’implémentation à la MuteLocal_Click pour désactiver l’appel.

        private async void MuteLocal_Click(object sender, RoutedEventArgs e)
        {
            var muteCheckbox = sender as CheckBox;

            if (muteCheckbox != null)
            {
                var call = this.callAgent?.Calls?.FirstOrDefault();

                if (call != null)
                {
                    if ((bool)muteCheckbox.IsChecked)
                    {
                        await call.MuteOutgoingAudioAsync();
                    }
                    else
                    {
                        await call.UnmuteOutgoingAudioAsync();
                    }
                }

                // Update the UI to reflect the state
            }
        }

Acceptation d’un appel entrant

IncomingCallReceived le récepteur d’événements est configuré dans l’assistance InitCallAgentAndDeviceManagerAsyncd’amorçage du KIT de développement logiciel (SDK).

    this.callAgent.IncomingCallReceived += OnIncomingCallAsync;

L’application a la possibilité de configurer la façon dont l’appel entrant doit être accepté, comme les types de flux vidéo et audio.

        private async void OnIncomingCallAsync(object sender, IncomingCallReceivedEventArgs args)
        {
            var incomingCall = args.IncomingCall;

            var acceptCallOptions = new AcceptCallOptions() { };

            call = await incomingCall.AcceptAsync(acceptCallOptions);
            call.StateChanged += OnStateChangedAsync;
        }

Surveiller et répondre à l’événement de changement d’état d’appel

L’événement StateChanged sur l’objet CommunicationCall est déclenché lorsqu’un appel en cours de transactions d’un état à un autre. L’application a la possibilité de refléter les changements d’état sur l’interface utilisateur ou d’insérer des logiques métier.

        private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
        {
            var call = sender as CommunicationCall;

            if (call != null)
            {
                var state = call.State;

                // Update the UI

                switch (state)
                {
                    case CallState.Connected:
                        {
                            await call.StartAudioAsync(micStream);

                            break;
                        }
                    case CallState.Disconnected:
                        {
                            call.StateChanged -= OnStateChangedAsync;

                            call.Dispose();

                            break;
                        }
                    default: break;
                }
            }
        }

Faire fonctionner le bouton d’appel

Une fois que le Callee ID n’est pas nul ou vide, vous pouvez démarrer un appel.

L’état de l’appel doit être changé à l’aide de l’action OnStateChangedAsync.


    private async void CallButton_Click(object sender, RoutedEventArgs e)
    {
        var callString = CalleeTextBox.Text.Trim();

        if (!string.IsNullOrEmpty(callString))
        {
            call = await StartCallAsync(callString);

            call.StateChanged += OnStateChangedAsync;
        }
    
        
    }

Exécuter le code

Vous pouvez générer et exécuter le code sur Visual Studio. Les plateformes de solutions que nous prenons en charge sont ARM64, x64 et x86.

Étapes manuelles pour configurer l’appel :

  1. Lancement de l’application à l’aide de Visual Studio.
  2. Entrez l’ID d’objet du standard automatique (avec préfixe), puis sélectionnez le bouton « Démarrer l’appel ». L’application démarre l’appel sortant vers le standard automatique avec l’ID d’objet donné.
  3. L’appel est connecté au standard automatique.
  4. L’utilisateur Communication Services est routé via le standard automatique selon sa configuration.

Nettoyer les ressources

Si vous voulez nettoyer et supprimer un abonnement Communication Services, vous pouvez supprimer la ressource ou le groupe de ressources. La suppression du groupe de ressources efface également les autres ressources qui y sont associées. Apprenez-en davantage sur le nettoyage des ressources.

Étapes suivantes

Pour plus d’informations, consultez les articles suivants :