Share via


Démarrage rapide : Joindre votre application de conversation à une réunion Teams

Démarrez avec Azure Communication Services en connectant votre solution de conversation à Microsoft Teams.

Dans ce guide de démarrage rapide, vous allez découvrir comment rejoindre une conversation dans une réunion Teams à l’aide du kit SDK Conversation Azure Communication Services pour JavaScript.

Exemple de code

Vous trouverez le code finalisé pour ce guide de démarrage rapide sur GitHub.

Prérequis

Participation à la conversation d’une réunion

Un utilisateur de Communication Services peut participer à une réunion Teams en tant qu’utilisateur anonyme à l’aide du kit de développement logiciel (SDK) Appel. En rejoignant la réunion, il est également ajouté comme participant à la conversation de la réunion, où il peut échanger des messages avec d’autres utilisateurs connectés. L’utilisateur n’aura pas accès aux messages de la conversation envoyés avant qu’il rejoigne la réunion. Il ne pourra pas non plus envoyer ni recevoir des messages une fois la réunion terminée. Pour participer à la réunion et commencer à converser, vous pouvez suivre les étapes suivantes.

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 chat-interop-quickstart && cd chat-interop-quickstart

Exécutez npm init -y pour créer un fichier package.json avec les paramètres par défaut.

npm init -y

Installer les packages de chat

Utilisez la commande npm install pour installer les kits de développement logiciel (SDK) Communication Services pour JavaScript nécessaires.

npm install @azure/communication-common --save

npm install @azure/communication-identity --save

npm install @azure/communication-chat --save

npm install @azure/communication-calling --save

L’option --save liste la bibliothèque comme dépendance dans votre fichier package.json.

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 webpack@5.89.0 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 utilisons ce fichier pour configurer une disposition de base qui permettra à l’utilisateur de participer à une réunion et de démarrer une conversation.

Ajouter les contrôles d’interface utilisateur de Teams

Remplacez le code dans index.html par l’extrait de code suivant. La zone de texte en haut de la page sera utilisée pour entrer le contexte de la réunion Teams. Le bouton « Participer à la réunion Teams » est utilisé pour rejoindre la réunion spécifiée. Une fenêtre de conversation contextuelle s’affiche au bas de la page. Elle permet d’envoyer des messages sur le thread de la réunion et affiche en temps réel tous les messages envoyés sur ce thread tant que l’utilisateur Communication Services en est membre.

<!DOCTYPE html>
<html>
   <head>
      <title>Communication Client - Calling and Chat Sample</title>
      <style>
         body {box-sizing: border-box;}
         /* The popup chat - hidden by default */
         .chat-popup {
         display: none;
         position: fixed;
         bottom: 0;
         left: 15px;
         border: 3px solid #f1f1f1;
         z-index: 9;
         }
         .message-box {
         display: none;
         position: fixed;
         bottom: 0;
         left: 15px;
         border: 3px solid #FFFACD;
         z-index: 9;
         }
         .form-container {
         max-width: 300px;
         padding: 10px;
         background-color: white;
         }
         .form-container textarea {
         width: 90%;
         padding: 15px;
         margin: 5px 0 22px 0;
         border: none;
         background: #e1e1e1;
         resize: none;
         min-height: 50px;
         }
         .form-container .btn {
         background-color: #4CAF40;
         color: white;
         padding: 14px 18px;
         margin-bottom:10px;
         opacity: 0.6;
         border: none;
         cursor: pointer;
         width: 100%;
         }
         .container {
         border: 1px solid #dedede;
         background-color: #F1F1F1;
         border-radius: 3px;
         padding: 8px;
         margin: 8px 0;
         }
         .darker {
         border-color: #ccc;
         background-color: #ffdab9;
         margin-left: 25px;
         margin-right: 3px;
         }
         .lighter {
         margin-right: 20px;
         margin-left: 3px;
         }
         .container::after {
         content: "";
         clear: both;
         display: table;
         }
      </style>
   </head>
   <body>
      <h4>Azure Communication Services</h4>
      <h1>Calling and Chat Quickstart</h1>
          <input id="teams-link-input" type="text" placeholder="Teams meeting link"
        style="margin-bottom:1em; width: 400px;" />
        <p>Call state <span style="font-weight: bold" id="call-state">-</span></p>
      <div>
        <button id="join-meeting-button" type="button">
            Join Teams Meeting
        </button>
        <button id="hang-up-button" type="button" disabled="true">
            Hang Up
        </button>
      </div>
      <div class="chat-popup" id="chat-box">
         <div id="messages-container"></div>
         <form class="form-container">
            <textarea placeholder="Type message.." name="msg" id="message-box" required></textarea>
            <button type="button" class="btn" id="send-message">Send</button>
         </form>
      </div>
      <script src="./bundle.js"></script>
   </body>
</html>

Activer les contrôles d’interface utilisateur de Teams

Remplacez le contenu du fichier client.js par l’extrait de code suivant.

Dans l’extrait de code, remplacez :

  • SECRET_CONNECTION_STRING par la chaîne de connexion de votre service de communication ;
import { CallClient } from "@azure/communication-calling";
import { AzureCommunicationTokenCredential } from "@azure/communication-common";
import { CommunicationIdentityClient } from "@azure/communication-identity";
import { ChatClient } from "@azure/communication-chat";

let call;
let callAgent;
let chatClient;
let chatThreadClient;

const meetingLinkInput = document.getElementById("teams-link-input");
const callButton = document.getElementById("join-meeting-button");
const hangUpButton = document.getElementById("hang-up-button");
const callStateElement = document.getElementById("call-state");

const messagesContainer = document.getElementById("messages-container");
const chatBox = document.getElementById("chat-box");
const sendMessageButton = document.getElementById("send-message");
const messageBox = document.getElementById("message-box");

var userId = "";
var messages = "";
var chatThreadId = "";

async function init() {
  const connectionString = "<SECRET_CONNECTION_STRING>";
  const endpointUrl = connectionString.split(";")[0].replace("endpoint=", "");

  const identityClient = new CommunicationIdentityClient(connectionString);

  let identityResponse = await identityClient.createUser();
  userId = identityResponse.communicationUserId;
  console.log(`\nCreated an identity with ID: ${identityResponse.communicationUserId}`);

  let tokenResponse = await identityClient.getToken(identityResponse, ["voip", "chat"]);

  const { token, expiresOn } = tokenResponse;
  console.log(`\nIssued an access token that expires at: ${expiresOn}`);
  console.log(token);

  const callClient = new CallClient();
  const tokenCredential = new AzureCommunicationTokenCredential(token);

  callAgent = await callClient.createCallAgent(tokenCredential);
  callButton.disabled = false;
  chatClient = new ChatClient(endpointUrl, new AzureCommunicationTokenCredential(token));

  console.log("Azure Communication Chat client created!");
}

init();

const joinCall = (urlString, callAgent) => {
  const url = new URL(urlString);
  console.log(url);
  if (url.pathname.startsWith("/meet")) {
    // Short teams URL, so for now call meetingID and pass code API
    return callAgent.join({
      meetingId: url.pathname.split("/").pop(),
      passcode: url.searchParams.get("p"),
    });
  } else {
    return callAgent.join({ meetingLink: urlString }, {});
  }
};

callButton.addEventListener("click", async () => {
  // join with meeting link
  try {
    call = joinCall(meetingLinkInput.value, callAgent);
  } catch {
    throw new Error("Could not join meeting - have you set your connection string?");
  }

  // Chat thread ID is provided from the call info, after connection.
  call.on("stateChanged", async () => {
    callStateElement.innerText = call.state;

    if (call.state === "Connected" && !chatThreadClient) {
      chatThreadId = call.info?.threadId;
      chatThreadClient = chatClient.getChatThreadClient(chatThreadId);

      chatBox.style.display = "block";
      messagesContainer.innerHTML = messages;

      // open notifications channel
      await chatClient.startRealtimeNotifications();

      // subscribe to new message notifications
      chatClient.on("chatMessageReceived", (e) => {
        console.log("Notification chatMessageReceived!");

        // check whether the notification is intended for the current thread
        if (chatThreadId != e.threadId) {
          return;
        }

        if (e.sender.communicationUserId != userId) {
          renderReceivedMessage(e.message);
        } else {
          renderSentMessage(e.message);
        }
      });
    }
  });

  // toggle button and chat box states
  hangUpButton.disabled = false;
  callButton.disabled = true;

  console.log(call);
});

async function renderReceivedMessage(message) {
  messages += '<div class="container lighter">' + message + "</div>";
  messagesContainer.innerHTML = messages;
}

async function renderSentMessage(message) {
  messages += '<div class="container darker">' + message + "</div>";
  messagesContainer.innerHTML = messages;
}

hangUpButton.addEventListener("click", async () => {
  // end the current call
  await call.hangUp();
  // Stop notifications
  chatClient.stopRealtimeNotifications();

  // toggle button states
  hangUpButton.disabled = true;
  callButton.disabled = false;
  callStateElement.innerText = "-";

  // toggle chat states
  chatBox.style.display = "none";
  messages = "";
  // Remove local ref
  chatThreadClient = undefined;
});

sendMessageButton.addEventListener("click", async () => {
  let message = messageBox.value;

  let sendMessageRequest = { content: message };
  let sendMessageOptions = { senderDisplayName: "Jack" };
  let sendChatMessageResult = await chatThreadClient.sendMessage(
    sendMessageRequest,
    sendMessageOptions
  );
  let messageId = sendChatMessageResult.id;

  messageBox.value = "";
  console.log(`Message sent!, message id:${messageId}`);
});

Les noms d’affichage des participants aux conversations ne sont pas définis par le client Teams. La valeur Null est renvoyée dans l’API pour la liste des participants, dans l’événement participantsAdded et dans l’événement participantsRemoved. Les noms d’affichage des participants à la conversation peuvent être récupérés dans le champ remoteParticipants de l’objet call. Lorsque vous recevez une notification concernant une modification de la liste, vous pouvez utiliser ce code pour récupérer le nom de l’utilisateur qui a été ajouté ou supprimé :

var displayName = call.remoteParticipants.find(p => p.identifier.communicationUserId == '<REMOTE_USER_ID>').displayName;

Exécuter le code

Les utilisateurs de Webpack peuvent utiliser webpack-dev-server pour générer et exécuter votre application. Exécutez la commande suivante pour créer un bundle de votre application hôte sur un serveur web local :

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

Ouvrez votre navigateur et accédez à http://localhost:8080/. Vous devriez voir l’application lancée, comme illustré dans la capture d’écran suivante :

Capture d’écran de l’application JavaScript terminée.

Insérez le lien de la réunion Teams dans la zone de texte. Appuyez sur Participer à une réunion Teams pour participer à la réunion Teams. Une fois que l’utilisateur Communication Services est admis à la réunion, vous pouvez converser à partir de votre application Azure Communication Services. Accédez à la zone en bas de la page pour commencer la conversation. Par souci de simplicité, l’application n’affiche que les deux derniers messages de la conversation.

Notes

Certaines fonctionnalités ne sont actuellement pas prises en charge pour les scénarios d’interopérabilité avec Teams. Pour en savoir plus sur les fonctionnalités prises en charge, consultez Fonctionnalités de réunion Teams pour les utilisateurs Teams externes.

Dans ce guide de démarrage rapide, vous allez découvrir comment rejoindre une conversation dans une réunion Teams à l’aide du kit SDK Conversation Azure Communication Services pour iOS.

Exemple de code

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

Prérequis

  • 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
  • Un déploiement de Teams
  • 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.

Configuration

Création du projet Xcode

Dans Xcode, créez un projet iOS et sélectionnez le modèle Single View 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.

Installation de CocoaPods

Utilisez ce guide pour installer CocoaPods sur votre Mac.

Installer le package et les dépendances avec CocoaPods

  1. Pour créer un Podfile pour votre application, ouvrez le terminal et accédez au dossier du projet, puis exécutez pod init.

  2. Ajoutez le code suivant au Podfile sous la cible, puis enregistrez-le.

target 'Chat Teams Interop' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Chat Teams Interop
  pod 'AzureCommunicationCalling'
  pod 'AzureCommunicationChat'
  
end
  1. Exécutez pod install.

  2. Ouvrez le fichier .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.

Sous la cible, sélectionnez l’onglet Info et ajoutez une chaîne pour « Confidentialité – Description de l’utilisation du microphone ».

Capture d’écran montrant l’ajout de l’utilisation du microphone dans Xcode.

Désactiver le bac à sable de script utilisateur

Certains des scripts dans les bibliothèques liées écrivent des fichiers pendant le processus de génération. Pour autoriser cela, désactivez le bac à sable de script utilisateur dans Xcode. Sous les paramètres de génération, recherchez sandbox et affectez la valeur No à User Script Sandboxing.

Capture d’écran montrant la désactivation du bac à sable de script utilisateur dans Xcode.

Participation à la conversation d’une réunion

Un utilisateur de Communication Services peut participer à une réunion Teams en tant qu’utilisateur anonyme à l’aide du kit de développement logiciel (SDK) Appel. Une fois qu’un utilisateur a rejoint la réunion Teams, il peut envoyer et recevoir des messages avec d’autres participants à la réunion. L’utilisateur n’aura pas accès aux messages de conversation envoyés avant qu’il n’ait rejoint la réunion, et ne pourra pas non plus envoyer ou recevoir de messages lorsqu’il ne fera plus partie de la réunion. Pour participer à la réunion et commencer à converser, vous pouvez suivre les étapes suivantes.

Configurer le framework d’application

Importez le package Azure Communication dans ContentView.swift en ajoutant l’extrait de code suivant :

import AVFoundation
import SwiftUI

import AzureCommunicationCalling
import AzureCommunicationChat

Dans ContentView.swift, ajoutez l’extrait de code suivant, juste au-dessus de la déclaration struct ContentView: View :

let endpoint = "<ADD_YOUR_ENDPOINT_URL_HERE>"
let token = "<ADD_YOUR_USER_TOKEN_HERE>"
let displayName: String = "Quickstart User"

Remplacez <ADD_YOUR_ENDPOINT_URL_HERE> par le point de terminaison de votre ressource Communication Services. Remplacez <ADD_YOUR_USER_TOKEN_HERE> par le jeton généré ci-dessus, via la ligne de commande du client Azure. En découvrir plus sur les jetons d’accès utilisateur : Jeton d’accès utilisateur

Remplacez Quickstart User par le nom complet à utiliser dans la conversation.

Pour stocker l’état, ajoutez les variables suivantes au struct ContentView :

  @State var message: String = ""
  @State var meetingLink: String = ""
  @State var chatThreadId: String = ""

  // Calling state
  @State var callClient: CallClient?
  @State var callObserver: CallDelegate?
  @State var callAgent: CallAgent?
  @State var call: Call?

  // Chat state
  @State var chatClient: ChatClient?
  @State var chatThreadClient: ChatThreadClient?
  @State var chatMessage: String = ""
  @State var meetingMessages: [MeetingMessage] = []

Nous allons maintenant ajouter la variable du corps principal pour stocker les éléments de l’interface utilisateur. Dans ce démarrage rapide, nous allons attacher une logique métier à ces contrôles. Ajoutez le code suivant au struct ContentView :

var body: some View {
    NavigationView {
      Form {
        Section {
          TextField("Teams Meeting URL", text: $meetingLink)
            .onChange(of: self.meetingLink, perform: { value in
              if let threadIdFromMeetingLink = getThreadId(from: value) {
                self.chatThreadId = threadIdFromMeetingLink
              }
            })
          TextField("Chat thread ID", text: $chatThreadId)
        }
        Section {
          HStack {
            Button(action: joinMeeting) {
              Text("Join Meeting")
            }.disabled(
              chatThreadId.isEmpty || callAgent == nil || call != nil
            )
            Spacer()
            Button(action: leaveMeeting) {
              Text("Leave Meeting")
            }.disabled(call == nil)
          }
          Text(message)
        }
        Section {
          ForEach(meetingMessages, id: \.id) { message in
            let currentUser: Bool = (message.displayName == displayName)
            let foregroundColor = currentUser ? Color.white : Color.black
            let background = currentUser ? Color.blue : Color(.systemGray6)
            let alignment = currentUser ? HorizontalAlignment.trailing : .leading
            
            HStack {
              if currentUser {
                Spacer()
              }
              VStack(alignment: alignment) {
                Text(message.displayName).font(Font.system(size: 10))
                Text(message.content)
                  .frame(maxWidth: 200)
              }

              .padding(8)
              .foregroundColor(foregroundColor)
              .background(background)
              .cornerRadius(8)

              if !currentUser {
                Spacer()
              }
            }
          }
          .frame(maxWidth: .infinity)
        }

        TextField("Enter your message...", text: $chatMessage)
        Button(action: sendMessage) {
          Text("Send Message")
        }.disabled(chatThreadClient == nil)
      }

      .navigationBarTitle("Teams Chat Interop")
    }

    .onAppear {
      // Handle initialization of the call and chat clients
    }
  }

Initialiser le ChatClient

Instanciez le ChatClient et activez les messages de notification. Nous utilisons des notifications en temps réel pour la réception des messages de conversation.

Le corps principal étant configuré, nous allons maintenant ajouter les fonctions pour gérer la configuration des clients d’appel et de conversation.

Dans la fonction onAppear, ajoutez le code suivant pour initialiser CallClient et ChatClient :

  if let threadIdFromMeetingLink = getThreadId(from: self.meetingLink) {
    self.chatThreadId = threadIdFromMeetingLink
  }
  // Authenticate
  do {
    let credentials = try CommunicationTokenCredential(token: token)
    self.callClient = CallClient()
    self.callClient?.createCallAgent(
      userCredential: credentials
    ) { agent, error in
      if let e = error {
        self.message = "ERROR: It was not possible to create a call agent."
        print(e)
        return
      } else {
        self.callAgent = agent
      }
    }
  
    // Start the chat client
    self.chatClient = try ChatClient(
      endpoint: endpoint,
      credential: credentials,
      withOptions: AzureCommunicationChatClientOptions()
    )
    // Register for real-time notifications
    self.chatClient?.startRealTimeNotifications { result in
      switch result {
      case .success:
        self.chatClient?.register(
          event: .chatMessageReceived,
          handler: receiveMessage
      )
      case let .failure(error):
        self.message = "Could not register for message notifications: " + error.localizedDescription
        print(error)
      }
    }
  } catch {
    print(error)
    self.message = error.localizedDescription
  }

Ajouter une fonction de participation à une réunion

Ajoutez la fonction suivante au struct ContentView pour gérer la participation à la réunion.

  func joinMeeting() {
    // Ask permissions
    AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
      if granted {
        let teamsMeetingLink = TeamsMeetingLinkLocator(
          meetingLink: self.meetingLink
        )
        self.callAgent?.join(
          with: teamsMeetingLink,
          joinCallOptions: JoinCallOptions()
        ) {(call, error) in
          if let e = error {
            self.message = "Failed to join call: " + e.localizedDescription
            print(e.localizedDescription)
            return
          }

          self.call = call
          self.callObserver = CallObserver(self)
          self.call?.delegate = self.callObserver
          self.message = "Teams meeting joined successfully"
        }
      } else {
        self.message = "Not authorized to use mic"
      }
    }
  }

Initialiser le ChatThreadClient

Nous initialiserons le ChatThreadClient une fois que l’utilisateur aura rejoint la réunion. Cela nous oblige à vérifier l’état de la réunion à partir du délégué, puis à initialiser le ChatThreadClient avec le threadId une fois la réunion rejointe.

Créez la fonction connectChat() avec le code suivant :

  func connectChat() {
    do {
      self.chatThreadClient = try chatClient?.createClient(
        forThread: self.chatThreadId
      )
      self.message = "Joined meeting chat successfully"
    } catch {
      self.message = "Failed to join the chat thread: " + error.localizedDescription
    }
  }

Ajoutez la fonction d’assistance suivante au ContentView, utilisée pour analyser l’ID de thread de conversation à partir du lien de réunion de l’équipe, si possible. Dans le cas où cette extraction échoue, l’utilisateur doit entrer manuellement l’ID de thread de conversation à l’aide des API Graph pour récupérer l’ID de thread.

 func getThreadId(from teamsMeetingLink: String) -> String? {
  if let range = teamsMeetingLink.range(of: "meetup-join/") {
    let thread = teamsMeetingLink[range.upperBound...]
    if let endRange = thread.range(of: "/")?.lowerBound {
      return String(thread.prefix(upTo: endRange))
    }
  }
  return nil
}

Activer l’envoi des messages

Ajoutez la fonction sendMessage() à ContentView. Cette fonction utilise ChatThreadClient pour envoyer les messages de l’utilisateur.

func sendMessage() {
  let message = SendChatMessageRequest(
    content: self.chatMessage,
    senderDisplayName: displayName,
    type: .text
  )

  self.chatThreadClient?.send(message: message) { result, _ in
    switch result {
    case .success:
    print("Chat message sent")
    self.chatMessage = ""

    case let .failure(error):
    self.message = "Failed to send message: " + error.localizedDescription + "\n Has your token expired?"
    }
  }
}

Activer la réception des messages

Pour recevoir des messages, nous devons implémenter le gestionnaire des événements ChatMessageReceived. Quand de nouveaux messages sont envoyés au thread, ce gestionnaire ajoute les messages à la variable meetingMessages afin qu’ils puissent être affichés dans l’interface utilisateur.

Tout d’abord, ajoutez le struct suivant à ContentView.swift. L’interface utilisateur utilise les données du struct pour afficher les messages de conversation.

struct MeetingMessage: Identifiable {
  let id: String
  let date: Date
  let content: String
  let displayName: String

  static func fromTrouter(event: ChatMessageReceivedEvent) -> MeetingMessage {
    let displayName: String = event.senderDisplayName ?? "Unknown User"
    let content: String = event.message.replacingOccurrences(
      of: "<[^>]+>", with: "",
      options: String.CompareOptions.regularExpression
    )
    return MeetingMessage(
      id: event.id,
      date: event.createdOn?.value ?? Date(),
      content: content,
      displayName: displayName
    )
  }
}

Ensuite, ajoutez la fonction receiveMessage() à ContentView. Cet appel a lieu lorsqu’un événement de messagerie se produit. Notez que vous devez vous inscrire à tous les événements que vous souhaitez gérer dans l’instruction switch via la méthode chatClient?.register().

  func receiveMessage(event: TrouterEvent) -> Void {
    switch event {
    case let .chatMessageReceivedEvent(messageEvent):
      let message = MeetingMessage.fromTrouter(event: messageEvent)
      self.meetingMessages.append(message)

      /// OTHER EVENTS
      //    case .realTimeNotificationConnected:
      //    case .realTimeNotificationDisconnected:
      //    case .typingIndicatorReceived(_):
      //    case .readReceiptReceived(_):
      //    case .chatMessageEdited(_):
      //    case .chatMessageDeleted(_):
      //    case .chatThreadCreated(_):
      //    case .chatThreadPropertiesUpdated(_):
      //    case .chatThreadDeleted(_):
      //    case .participantsAdded(_):
      //    case .participantsRemoved(_):

    default:
      break
    }
  }

Pour finir, nous devons implémenter le gestionnaire de délégués pour le client d’appel. Ce gestionnaire est utilisé pour vérifier l’état de l’appel et initialiser le client de conversation lorsque l’utilisateur rejoint la réunion.

class CallObserver : NSObject, CallDelegate {
  private var owner: ContentView

  init(_ view: ContentView) {
    owner = view
  }

  func call(
    _ call: Call,
    didChangeState args: PropertyChangedEventArgs
  ) {
    owner.message = CallObserver.callStateToString(state: call.state)
    if call.state == .disconnected {
      owner.call = nil
      owner.message = "Left Meeting"
    } else if call.state == .inLobby {
      owner.message = "Waiting in lobby (go let them in!)"
    } else if call.state == .connected {
      owner.message = "Connected"
      owner.connectChat()
    }
  }

  private static func callStateToString(state: CallState) -> String {
    switch state {
    case .connected: return "Connected"
    case .connecting: return "Connecting"
    case .disconnected: return "Disconnected"
    case .disconnecting: return "Disconnecting"
    case .earlyMedia: return "EarlyMedia"
    case .none: return "None"
    case .ringing: return "Ringing"
    case .inLobby: return "InLobby"
    default: return "Unknown"
    }
  }
}

Quitter la conversation

Lorsque l’utilisateur quitte la réunion de l’équipe, nous effaçons les messages de conversation de l’interface utilisateur et mettons fin à l’appel. Le code complet est indiqué ci-dessous.

  func leaveMeeting() {
    if let call = self.call {
      self.chatClient?.unregister(event: .chatMessageReceived)
      self.chatClient?.stopRealTimeNotifications()

      call.hangUp(options: nil) { (error) in
        if let e = error {
          self.message = "Leaving Teams meeting failed: " + e.localizedDescription
        } else {
          self.message = "Leaving Teams meeting was successful"
        }
      }
      self.meetingMessages.removeAll()
    } else {
      self.message = "No active call to hangup"
    }
  }

Obtenir le fil de conversation d’une réunion Teams pour un utilisateur Communication Services

Il est possible de récupérer les détails de la réunion Teams à l’aide d’API Graph décrites dans la Documentation Graph. Le kit SDK Communication Services Calling accepte un lien de réunion Teams complet ou un ID de réunion. Ces informations sont retournées dans le cadre de la ressource onlineMeeting, accessible sous la propriété joinWebUrl.

Avec les API Graph, vous pouvez également obtenir la valeur threadID. La réponse a un objet chatInfo qui contient le threadID.

Exécuter le code

Exécutez l'application.

Pour rejoindre la réunion Teams, saisissez le lien de réunion de votre équipe dans l’interface utilisateur.

Une fois que vous avez rejoint la réunion de l’équipe, vous devez autoriser l’utilisateur à participer à la réunion dans le client de votre équipe. Une fois que l’utilisateur est admis et a rejoint la conversation, vous pouvez envoyer et recevoir des messages.

Capture d’écran de l’application iOS terminée.

Notes

Certaines fonctionnalités ne sont actuellement pas prises en charge pour les scénarios d’interopérabilité avec Teams. Pour en savoir plus sur les fonctionnalités prises en charge, consultez Fonctionnalités de réunion Teams pour les utilisateurs Teams externes.

Dans ce démarrage rapide, vous allez découvrir comment rejoindre une conversation dans une réunion Teams à l’aide du Kit de développement logiciel (SDK) Conversation Azure Communication Services pour Android.

Exemple de code

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

Prérequis

Activer l’interopérabilité de Teams

Un utilisateur Communication Services qui rejoint une réunion Teams en tant qu’utilisateur invité ne peut accéder à la conversation de la réunion qu’après avoir rejoint l’appel de réunion Teams. Consultez la documentation Interopérabilité de Teams pour savoir comment ajouter un utilisateur Communication Services à un appel de réunion Teams.

Vous devez être membre de l’organisation propriétaire des deux entités pour pouvoir utiliser cette fonctionnalité.

Participation à la conversation d’une réunion

Une fois l’interopérabilité de Teams activée, un utilisateur de Communication Services peut rejoindre l’appel Teams en tant qu’utilisateur externe à l’aide du kit de développement logiciel (SDK) Calling. En rejoignant l’appel, il est également ajouté comme participant à la conversation de la réunion, où il peut échanger des messages avec d’autres utilisateurs lors de l’appel. L’utilisateur n’a pas accès aux messages de conversation qui ont été envoyés avant qu’il ne rejoigne l’appel. Pour participer à la réunion et commencer à converser, vous pouvez suivre les étapes suivantes.

Ajouter la conversation à l’application d’appel Teams

Dans votre fichier build.gradle au niveau du module, ajoutez la dépendance au kit de développement logiciel (SDK) de conversation.

Important

Problème connu : lors de l’utilisation conjointe du chat Android et du Kit de développement logiciel (SDK) d’appel dans la même application, la fonctionnalité de notifications en temps réel du SDK de conversation ne fonctionne pas. Vous obtiendrez un problème de résolution de dépendance. Pendant que nous travaillons sur une solution, vous pouvez désactiver la fonctionnalité de notifications en temps réel en ajoutant les exclusions suivantes à la dépendance du Kit de développement logiciel (SDK) de conversation dans le fichier build.gradle de l’application :

implementation ("com.azure.android:azure-communication-chat:2.0.3") {
    exclude group: 'com.microsoft', module: 'trouter-client-android'
}

Ajouter la disposition de l’interface utilisateur Teams

Remplacez le code dans activity_main.xml par l’extrait de code suivant. Il ajoute des entrées pour l’ID de thread et pour l’envoi de messages, un bouton pour envoyer le message saisi et une disposition de base pour le chat.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/teams_meeting_thread_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="128dp"
        android:ems="10"
        android:hint="Meeting Thread Id"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/teams_meeting_link"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="64dp"
        android:ems="10"
        android:hint="Teams meeting link"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/button_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/teams_meeting_thread_id">

        <Button
            android:id="@+id/join_meeting_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Join Meeting" />

        <Button
            android:id="@+id/hangup_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hangup" />

    </LinearLayout>

    <TextView
        android:id="@+id/call_status_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/recording_status_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <ScrollView
        android:id="@+id/chat_box"
        android:layout_width="374dp"
        android:layout_height="294dp"
        android:layout_marginTop="40dp"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toTopOf="@+id/send_message_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button_layout"
        android:orientation="vertical"
        android:gravity="bottom"
        android:layout_gravity="bottom"
        android:fillViewport="true">

        <LinearLayout
            android:id="@+id/chat_box_layout"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="bottom"
            android:layout_gravity="top"
            android:layout_alignParentBottom="true"/>
    </ScrollView>

    <EditText
        android:id="@+id/message_body"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="588dp"
        android:ems="10"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Type your message here..."
        tools:visibility="invisible" />

    <Button
        android:id="@+id/send_message_button"
        android:layout_width="138dp"
        android:layout_height="45dp"
        android:layout_marginStart="133dp"
        android:layout_marginTop="48dp"
        android:layout_marginEnd="133dp"
        android:text="Send Message"
        android:visibility="invisible"
        app:layout_constraintBottom_toTopOf="@+id/recording_status_bar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.428"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chat_box" />

</androidx.constraintlayout.widget.ConstraintLayout>

Activer les contrôles d’interface utilisateur de Teams

Importer des packages et définir des variables d’état

Ajoutez les importations suivantes au contenu de MainActivity.java :

import android.graphics.Typeface;
import android.graphics.Color;
import android.text.Html;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.List;
import com.azure.android.communication.chat.ChatThreadAsyncClient;
import com.azure.android.communication.chat.ChatThreadClientBuilder;
import com.azure.android.communication.chat.models.ChatMessage;
import com.azure.android.communication.chat.models.ChatMessageType;
import com.azure.android.communication.chat.models.ChatParticipant;
import com.azure.android.communication.chat.models.ListChatMessagesOptions;
import com.azure.android.communication.chat.models.SendChatMessageOptions;
import com.azure.android.communication.common.CommunicationIdentifier;
import com.azure.android.communication.common.CommunicationUserIdentifier;
import com.azure.android.core.rest.util.paging.PagedAsyncStream;
import com.azure.android.core.util.AsyncStreamHandler;

Ajoutez les variables suivantes à la classe MainActivity :

    // InitiatorId is used to differentiate incoming messages from outgoing messages
    private static final String InitiatorId = "<USER_ID>";
    private static final String ResourceUrl = "<COMMUNICATION_SERVICES_RESOURCE_ENDPOINT>";
    private String threadId;
    private ChatThreadAsyncClient chatThreadAsyncClient;
    
    // The list of ids corresponsding to messages which have already been processed
    ArrayList<String> chatMessages = new ArrayList<>();

Remplacez <USER_ID> par l’ID de l’utilisateur qui lance la conversation. Remplacez <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT> par le point de terminaison de votre ressource Communication Services.

Initialiser le ChatThreadClient

Après avoir rejoint la réunion, instanciez le ChatThreadClient et rendez visibles les composants du chat.

Mettez à jour la fin de la méthode MainActivity.joinTeamsMeeting() avec le code ci-dessous :

    private void joinTeamsMeeting() {
        ...
        EditText threadIdView = findViewById(R.id.teams_meeting_thread_id);
        threadId = threadIdView.getText().toString();
        // Initialize Chat Thread Client
        chatThreadAsyncClient = new ChatThreadClientBuilder()
                .endpoint(ResourceUrl)
                .credential(new CommunicationTokenCredential(UserToken))
                .chatThreadId(threadId)
                .buildAsyncClient();
        Button sendMessageButton = findViewById(R.id.send_message_button);
        EditText messageBody = findViewById(R.id.message_body);
        // Register the method for sending messages and toggle the visibility of chat components
        sendMessageButton.setOnClickListener(l -> sendMessage());
        sendMessageButton.setVisibility(View.VISIBLE);
        messageBody.setVisibility(View.VISIBLE);
        
        // Start the polling for chat messages immediately
        handler.post(runnable);
    }

Activer l’envoi des messages

Ajoutez la méthode sendMessage() à MainActivity. Elle utilise le ChatThreadClient pour envoyer des messages au nom de l’utilisateur.

    private void sendMessage() {
        // Retrieve the typed message content
        EditText messageBody = findViewById(R.id.message_body);
        // Set request options and send message
        SendChatMessageOptions options = new SendChatMessageOptions();
        options.setContent(messageBody.getText().toString());
        options.setSenderDisplayName("Test User");
        chatThreadAsyncClient.sendMessage(options);
        // Clear the text box
        messageBody.setText("");
    }

Activer l’interrogation des messages et leur rendu dans l’application

Important

Problème connu : Dans la mesure où la fonctionnalité de notifications en temps réel du Kit de développement logiciel (SDK) de conversation ne fonctionne pas avec le SDK d’appel, nous devons interroger l’API GetMessages à des intervalles prédéfinis. Dans notre exemple, nous allons utiliser des intervalles de trois secondes.

Nous pouvons obtenir les données suivantes à partir de la liste des messages renvoyée par l’API GetMessages :

  • Les messages text et html sur la conversation depuis qu’elle a été rejointe
  • Les modifications apportées à la liste des participants à la conversation
  • Les mises à jour du sujet de la conversation

Ajoutez à la classe MainActivity un gestionnaire et une tâche exécutable qui seront exécutés à intervalles de trois secondes :

    private Handler handler = new Handler();
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                retrieveMessages();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // Repeat every 3 seconds
            handler.postDelayed(runnable, 3000);
        }
    };

Notez que la tâche a déjà été démarrée à la fin de la méthode MainActivity.joinTeamsMeeting() mise à jour dans l’étape d’initialisation.

Enfin, nous devons ajouter la méthode permettant d’interroger tous les messages accessibles sur la conversation, de les analyser par type de message et d’afficher les messages html et text :

    private void retrieveMessages() throws InterruptedException {
        // Initialize the list of messages not yet processed
        ArrayList<ChatMessage> newChatMessages = new ArrayList<>();
        
        // Retrieve all messages accessible to the user
        PagedAsyncStream<ChatMessage> messagePagedAsyncStream
                = this.chatThreadAsyncClient.listMessages(new ListChatMessagesOptions(), null);
        // Set up a lock to wait until all returned messages have been inspected
        CountDownLatch latch = new CountDownLatch(1);
        // Traverse the returned messages
        messagePagedAsyncStream.forEach(new AsyncStreamHandler<ChatMessage>() {
            @Override
            public void onNext(ChatMessage message) {
                // Messages that should be displayed in the chat
                if ((message.getType().equals(ChatMessageType.TEXT)
                    || message.getType().equals(ChatMessageType.HTML))
                    && !chatMessages.contains(message.getId())) {
                    newChatMessages.add(message);
                    chatMessages.add(message.getId());
                }
                if (message.getType().equals(ChatMessageType.PARTICIPANT_ADDED)) {
                    // Handle participants added to chat operation
                    List<ChatParticipant> participantsAdded = message.getContent().getParticipants();
                    CommunicationIdentifier participantsAddedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
                if (message.getType().equals(ChatMessageType.PARTICIPANT_REMOVED)) {
                    // Handle participants removed from chat operation
                    List<ChatParticipant> participantsRemoved = message.getContent().getParticipants();
                    CommunicationIdentifier participantsRemovedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
                if (message.getType().equals(ChatMessageType.TOPIC_UPDATED)) {
                    // Handle topic updated
                    String newTopic = message.getContent().getTopic();
                    CommunicationIdentifier topicUpdatedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
            }
            @Override
            public void onError(Throwable throwable) {
                latch.countDown();
            }
            @Override
            public void onComplete() {
                latch.countDown();
            }
        });
        // Wait until the operation completes
        latch.await(1, TimeUnit.MINUTES);
        // Returned messages should be ordered by the createdOn field to be guaranteed a proper chronological order
        // For the purpose of this demo we will just reverse the list of returned messages
        Collections.reverse(newChatMessages);
        for (ChatMessage chatMessage : newChatMessages)
        {
            LinearLayout chatBoxLayout = findViewById(R.id.chat_box_layout);
            // For the purpose of this demo UI, we don't need to use HTML formatting for displaying messages
            // The Teams client always sends html messages in meeting chats 
            String message = Html.fromHtml(chatMessage.getContent().getMessage(), Html.FROM_HTML_MODE_LEGACY).toString().trim();
            TextView messageView = new TextView(this);
            messageView.setText(message);
            // Compare with sender identifier and align LEFT/RIGHT accordingly
            // Azure Communication Services users are of type CommunicationUserIdentifier
            CommunicationIdentifier senderId = chatMessage.getSenderCommunicationIdentifier();
            if (senderId instanceof CommunicationUserIdentifier
                && InitiatorId.equals(((CommunicationUserIdentifier) senderId).getId())) {
                messageView.setTextColor(Color.GREEN);
                messageView.setGravity(Gravity.RIGHT);
            } else {
                messageView.setTextColor(Color.BLUE);
                messageView.setGravity(Gravity.LEFT);
            }
            // Note: messages with the deletedOn property set to a timestamp, should be marked as deleted
            // Note: messages with the editedOn property set to a timestamp, should be marked as edited
            messageView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
            chatBoxLayout.addView(messageView);
        }
    }

Les noms d’affichage des participants aux conversations ne sont pas définis par le client Teams. La valeur Null est renvoyée dans l’API pour la liste des participants, dans l’événement participantsAdded et dans l’événement participantsRemoved. Les noms d’affichage des participants à la conversation peuvent être récupérés dans le champ remoteParticipants de l’objet call.

Obtenir le fil de conversation d’une réunion Teams pour un utilisateur Communication Services

Il est possible de récupérer les détails de la réunion Teams à l’aide d’API Graph décrites dans la Documentation Graph. Le kit SDK Communication Services Calling accepte un lien de réunion Teams complet ou un ID de réunion. Ces informations sont retournées dans le cadre de la ressource onlineMeeting, accessible sous la propriété joinWebUrl.

Avec les API Graph, vous pouvez également obtenir la valeur threadID. La réponse a un objet chatInfo qui contient le threadID.

Exécuter le code

L’application peut maintenant être lancée à l’aide du bouton « Run App » de la barre d’outils (Maj+F10).

Pour rejoindre la conversation et la réunion Teams, entrez le lien de réunion et l’ID de conversation de votre équipe dans l’interface utilisateur.

Une fois que vous avez rejoint la réunion de l’équipe, vous devez autoriser l’utilisateur à participer à la réunion dans le client de votre équipe. Une fois que l’utilisateur est admis et a rejoint la conversation, vous pouvez envoyer et recevoir des messages.

Capture d’écran de l’application Android terminée.

Notes

Certaines fonctionnalités ne sont actuellement pas prises en charge pour les scénarios d’interopérabilité avec Teams. Pour en savoir plus sur les fonctionnalités prises en charge, consultez Fonctionnalités de réunion Teams pour les utilisateurs Teams externes.

Dans ce démarrage rapide, vous découvrez comment rejoindre une conversation dans une réunion Teams à l’aide du Kit de développement logiciel (SDK) Conversation d'Azure Communication Services pour C#.

Exemple de code

Retrouvez le code ce démarrage rapide sur GitHub.

Prérequis

Participation à la conversation d’une réunion

Un utilisateur de Communication Services peut participer à une réunion Teams en tant qu’utilisateur anonyme à l’aide du kit de développement logiciel (SDK) Appel. En rejoignant la réunion, il est également ajouté comme participant à la conversation de la réunion, où il peut échanger des messages avec d’autres utilisateurs connectés. L’utilisateur n’aura pas accès aux messages de la conversation envoyés avant qu’il rejoigne la réunion, et il ne pourra pas non plus envoyer ni recevoir des messages une fois la réunion terminée. Pour participer à la réunion et commencer à converser, vous pouvez suivre les étapes suivantes.

Exécuter le code

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

  1. Ouvrez une instance de PowerShell, de Terminal Windows, une invite de commandes, ou équivalent, puis accédez au répertoire dans lequel vous souhaitez cloner l’exemple.
  2. git clone https://github.com/Azure-Samples/Communication-Services-dotnet-quickstarts.git
  3. Ouvrez le projet ChatTeamsInteropQuickStart/ChatTeamsInteropQuickStart.csproj dans Visual Studio.
  4. Installez les versions de packages NuGet suivantes (ou ultérieures) :
Install-Package Azure.Communication.Calling -Version 1.0.0-beta.29
Install-Package Azure.Communication.Chat -Version 1.1.0
Install-Package Azure.Communication.Common -Version 1.0.1
Install-Package Azure.Communication.Identity -Version 1.0.1

  1. À l’aide de la ressource Communication Services obtenue dans les prérequis, ajoutez la chaîne de connexion au fichier ChatTeamsInteropQuickStart/MainPage.xaml.cs.
//Azure Communication Services resource connection string, i.e., = "endpoint=https://your-resource.communication.azure.net/;accesskey=your-access-key";
private const string connectionString_ = "";

Important

  • Sélectionnez la plateforme appropriée dans la liste déroulante « Plateformes de solution » dans Visual Studio avant d’exécuter le code, par exemple, x64
  • assurez-vous que le « mode développeur » est activé dans Windows 10 (Paramètres du développeur)

Les étapes suivantes ne fonctionnent pas si cette configuration n’est pas correcte.

  1. Appuyez sur la touche F5 pour démarrer le projet en mode débogage.
  2. Collez un lien de réunion Teams valide dans la zone « Lien de réunion Teams » (voir la section suivante).
  3. Appuyez sur « Rejoindre la réunion Teams » pour commencer la conversation instantanée.

Important

Une fois que le Kit de développement logiciel (SDK) appelant a établi la connexion avec la réunion Teams (voir Communication Services appelant une application Windows ), les fonctions clés pour gérer les opérations de conversation sont : StartPollingForChatMessages et SendMessageButton_Click. Les deux extraits de code se trouvent sous ChatTeamsInteropQuickStart\MainPage.xaml.cs.

        /// <summary>
        /// Background task that keeps polling for chat messages while the call connection is stablished
        /// </summary>
        private async Task StartPollingForChatMessages()
        {
            CommunicationTokenCredential communicationTokenCredential = new(user_token_);
            chatClient_ = new ChatClient(EndPointFromConnectionString(), communicationTokenCredential);
            await Task.Run(async () =>
            {
                keepPolling_ = true;

                ChatThreadClient chatThreadClient = chatClient_.GetChatThreadClient(thread_Id_);
                int previousTextMessages = 0;
                while (keepPolling_)
                {
                    try
                    {
                        CommunicationUserIdentifier currentUser = new(user_Id_);
                        AsyncPageable<ChatMessage> allMessages = chatThreadClient.GetMessagesAsync();
                        SortedDictionary<long, string> messageList = new();
                        int textMessages = 0;
                        string userPrefix;
                        await foreach (ChatMessage message in allMessages)
                        {
                            if (message.Type == ChatMessageType.Html || message.Type == ChatMessageType.Text)
                            {
                                textMessages++;
                                userPrefix = message.Sender.Equals(currentUser) ? "[you]:" : "";
                                messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{StripHtml(message.Content.Message)}");
                            }
                        }

                        //Update UI just when there are new messages
                        if (textMessages > previousTextMessages)
                        {
                            previousTextMessages = textMessages;
                            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                            {
                                TxtChat.Text = string.Join(Environment.NewLine, messageList.Values.ToList());
                            });

                        }
                        if (!keepPolling_)
                        {
                            return;
                        }

                        await SetInCallState(true);
                        await Task.Delay(3000);
                    }
                    catch (Exception e)
                    {
                        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            _ = new MessageDialog($"An error occurred while fetching messages in PollingChatMessagesAsync(). The application will shutdown. Details : {e.Message}").ShowAsync();
                            throw e;
                        });
                        await SetInCallState(false);
                    }
                }
            });
        }
        private async void SendMessageButton_Click(object sender, RoutedEventArgs e)
        {
            SendMessageButton.IsEnabled = false;
            ChatThreadClient chatThreadClient = chatClient_.GetChatThreadClient(thread_Id_);
            _ = await chatThreadClient.SendMessageAsync(TxtMessage.Text);
            
            TxtMessage.Text = "";
            SendMessageButton.IsEnabled = true;
        }

Il est possible de récupérer le lien de réunion Teams à l’aide d’API Graph décrites dans la documentation de Graph. Ce lien est retourné dans le cadre de la ressource onlineMeeting, accessible sous la propriété joinWebUrl.

Vous pouvez également récupérer le lien de réunion requis à partir de l’URL Rejoindre la réunion disponible dans l’invitation à la réunion Teams elle-même. Un lien de réunion Teams ressemble à ceci : https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. Si le lien de votre équipe a un format différent, vous devez récupérer l’identifiant de la conversation à l’aide de l’API Graph.

Capture d’écran de l’application csharp terminée.

Notes

Certaines fonctionnalités ne sont actuellement pas prises en charge pour les scénarios d’interopérabilité avec Teams. Pour en savoir plus sur les fonctionnalités prises en charge, consultez Fonctionnalités de réunion Teams pour les utilisateurs Teams externes.

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 :