Démarrage rapide : Joindre votre application d’appels à une file d’attente d’appels Teams
Dans ce guide de démarrage rapide, vous allez apprendre à démarrer un appel d’un utilisateur Azure Communication Services vers la file d’attente des appels Teams. Vous allez y parvenir en procédant comme suit :
- Activez la fédération de la ressource Azure Communication Services ressource avec le locataire Teams.
- Sélectionnez ou créez une file d’attente d’appels Teams via le centre d’administration Teams.
- Obtenez l’adresse e-mail de la file d’attente d’appels via le centre d’administration Teams.
- Obtenez l’ID d’objet de la file d’attente d’appels via l’API Graph.
- 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 MicrosftTeams 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 une file d’attente d’appels Teams
Une file d’attente d’appels Teams est une fonctionnalité de Microsoft Teams qui distribue efficacement les appels entrants entre un groupe d’utilisateurs ou d’agents désignés. Il est utile pour les scénarios de support client ou de centre d’appels. Les appels sont placés dans une file d’attente et attribués à l’agent disponible suivant selon une méthode de routage prédéterminée. Les agents reçoivent des notifications et peuvent gérer les appels à l’aide des contrôles d’appel de Teams. La fonctionnalité offre des rapports et des analyses de suivi des performances. Elle simplifie la gestion des appels, garantit une expérience client cohérente et optimise la productivité des agents. Vous pouvez sélectionner une file d’attente d’appels existante ou en créer une via le centre d’administration Teams.
Découvrez comment créer une file d’attente d’appels à l’aide du centre d’administration Teams ici.
Rechercher l’ID d’objet de la file d’attente d’appels
Une fois la file d’attente d’appels créée, 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é à la file d’attente d’appels. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail. 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
- Obtenez un compte Azure avec un abonnement actif. Créez un compte gratuitement.
- Node.js, Active LTS et Maintenance LTS (version 8.11.1 et 10.14.1).
- Créez une ressource Communication Services active. Créez une ressource Communication Services.
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 callee's Teams user 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 callQueueId = 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 a Teams Call Queue
* 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: callQueueId.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 udpates.
subscribeToCall = (call) => {
try {
// Inspect the initial call.id value.
console.log(`Call Id: ${call.id}`);
//Subsribe 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.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();
});
});
call.on('isLocalVideoStartedChanged', () => {
console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
});
console.log(`isLocalVideoStarted: ${call.isLocalVideoStarted}`);
// 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 udpates.
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 remoteParticiapant 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 :
- Ouvrez votre navigateur et accédez à l’adresse http://localhost:8080/..
- 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.
- Cliquez sur les boutons « Initialiser l’agent d’appel ».
- Entrez l’ID d’objet de la file d’attente d’appels, puis sélectionnez le bouton « Démarrer l’appel ». L’application démarre l’appel sortant vers la file d’attente d’appels avec l’ID d’objet donné.
- L’appel est connecté à la file d’attente d’appels.
- L’utilisateur Communication Services est routé via la file d’attente d’appels 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 une file d’attente d’appels Teams. Vous allez y parvenir en procédant comme suit :
- Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
- Sélectionnez ou créez une file d’attente d’appels Teams via le centre d’administration Teams.
- Obtenez l’adresse e-mail de la file d’attente d’appels via le centre d’administration Teams.
- Obtenez l’ID d’objet de la file d’attente d’appels via l’API Graph.
- 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 MicrosftTeams 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 une file d’attente d’appels Teams
Une file d’attente d’appels Teams est une fonctionnalité de Microsoft Teams qui distribue efficacement les appels entrants entre un groupe d’utilisateurs ou d’agents désignés. Il est utile pour les scénarios de support client ou de centre d’appels. Les appels sont placés dans une file d’attente et attribués à l’agent disponible suivant selon une méthode de routage prédéterminée. Les agents reçoivent des notifications et peuvent gérer les appels à l’aide des contrôles d’appel de Teams. La fonctionnalité offre des rapports et des analyses de suivi des performances. Elle simplifie la gestion des appels, garantit une expérience client cohérente et optimise la productivité des agents. Vous pouvez sélectionner une file d’attente d’appels existante ou en créer une via le centre d’administration Teams.
Découvrez comment créer une file d’attente d’appels à l’aide du centre d’administration Teams ici.
Rechercher l’ID d’objet de la file d’attente d’appels
Une fois la file d’attente d’appels créée, 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é à la file d’attente des appels. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail. 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 :
- File d’attente d’appels cloud (public) :
28:orgid:<id>
- File d’attente d’appels cloud (gouvernement) :
28:gcch:<id>
Prérequis
Compte Azure avec un abonnement actif. Créez un compte gratuitement.
Android Studio, pour la création de votre application Android
Une ressource Communication Services déployée. Créez une ressource Communication Services.
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.12.0-beta.1
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).
Sélectionnez le modèle de projet « Empty Views Activity » sous « Phone and Tablet ».
Sélectionnez le kit de développement logiciel (SDK) minimal « API 26 : Android 8.0 (Oreo) » ou version ultérieure.
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 :
- Lancez l’application à l’aide d’Android Studio.
- Entrez l’ID d’objet de la file d’attente des appels, puis sélectionnez le bouton Démarrer l’appel. L’application démarre l’appel sortant vers la file d’attente des appels avec l’ID d’objet donné.
- L’appel est connecté à la file d’attente d’appels.
- L’utilisateur Communication Services est routé via la file d’attente d’appels 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 une file d’attente d’appels Teams. Vous allez y parvenir en procédant comme suit :
- Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
- Sélectionnez ou créez une file d’attente d’appels Teams via le centre d’administration Teams.
- Obtenez l’adresse e-mail de la file d’attente d’appels via le centre d’administration Teams.
- Obtenez l’ID d’objet de la file d’attente d’appels via l’API Graph.
- 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 MicrosftTeams 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 une file d’attente d’appels Teams
Une file d’attente d’appels Teams est une fonctionnalité de Microsoft Teams qui distribue efficacement les appels entrants entre un groupe d’utilisateurs ou d’agents désignés. Il est utile pour les scénarios de support client ou de centre d’appels. Les appels sont placés dans une file d’attente et attribués à l’agent disponible suivant selon une méthode de routage prédéterminée. Les agents reçoivent des notifications et peuvent gérer les appels à l’aide des contrôles d’appel de Teams. La fonctionnalité offre des rapports et des analyses de suivi des performances. Elle simplifie la gestion des appels, garantit une expérience client cohérente et optimise la productivité des agents. Vous pouvez sélectionner une file d’attente d’appels existante ou en créer une via le centre d’administration Teams.
Découvrez comment créer une file d’attente d’appels à l’aide du centre d’administration Teams ici.
Rechercher l’ID d’objet de la file d’attente d’appels
Une fois la file d’attente d’appels créée, 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é à la file d’attente des appels. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail. 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 :
- File d’attente d’appels cloud (public) :
28:orgid:<id>
- File d’attente d’appels cloud (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.
Installer le package et les dépendances avec CocoaPods
Afin de créer un Podfile pour votre application, ouvrez le terminal, accédez au dossier du projet, puis exécutez :
pod init
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
Exécutez
pod install
.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 :
- Lancer l’application à l’aide de Xcode
- Entrez l’ID d’objet de la file d’attente des appels, puis sélectionnez le bouton Démarrer l’appel. L’application démarre l’appel sortant vers la file d’attente des appels avec l’ID d’objet donné.
- L’appel est connecté à la file d’attente d’appels.
- L’utilisateur Communication Services est routé via la file d’attente d’appels 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 une file d’attente d’appels Teams. Vous allez y parvenir en procédant comme suit :
- Activez la fédération de la ressource Azure Communication Services avec le locataire Teams.
- Sélectionnez ou créez une file d’attente d’appels Teams via le centre d’administration Teams.
- Obtenez l’adresse e-mail de la file d’attente d’appels via le centre d’administration Teams.
- Obtenez l’ID d’objet de la file d’attente d’appels via l’API Graph.
- 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 MicrosftTeams 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 une file d’attente d’appels Teams
Une file d’attente d’appels Teams est une fonctionnalité de Microsoft Teams qui distribue efficacement les appels entrants entre un groupe d’utilisateurs ou d’agents désignés. Il est utile pour les scénarios de support client ou de centre d’appels. Les appels sont placés dans une file d’attente et attribués à l’agent disponible suivant selon une méthode de routage prédéterminée. Les agents reçoivent des notifications et peuvent gérer les appels à l’aide des contrôles d’appel de Teams. La fonctionnalité offre des rapports et des analyses de suivi des performances. Elle simplifie la gestion des appels, garantit une expérience client cohérente et optimise la productivité des agents. Vous pouvez sélectionner une file d’attente d’appels existante ou en créer une via le centre d’administration Teams.
Découvrez comment créer une file d’attente d’appels à l’aide du centre d’administration Teams ici.
Rechercher l’ID d’objet de la file d’attente d’appels
Une fois la file d’attente d’appels créée, 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é à la file d’attente des appels. Ouvrez l’onglet Comptes de ressource dans l’administration Teams et recherchez l’e-mail. 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 :
- File d’attente d’appels cloud (public) :
28:orgid:<id>
- File d’attente d’appels cloud (gouvernement) :
28:gcch:<id>
Prérequis
Pour effectuer ce didacticiel, vous avez besoin de ce qui suit :
Compte Azure avec un abonnement actif. Créez un compte gratuitement.
Installez Visual Studio 2022 avec la charge de travail de développement pour la plateforme Windows universelle.
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 : 1.10.0-beta.1
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.
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.
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 InitCallAgentAndDeviceManagerAsync
d’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 :
- Lancez l’application à l’aide de Visual Studio.
- Entrez l’ID d’objet de la file d’attente des appels, puis sélectionnez le bouton Démarrer l’appel. L’application démarre l’appel sortant vers la file d’attente des appels avec l’ID d’objet donné.
- L’appel est connecté à la file d’attente d’appels.
- L’utilisateur Communication Services est routé via la file d’attente d’appels 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 :
- Démarrage des Appels UI vers les applications vocales Teams
- Apprenez-en davantage sur les fonctionnalités du SDK Calling
- Apprenez-en davantage sur le fonctionnement des appels