Freigeben über


Erste Schritte mit dem Hero-Beispiel für Anrufe

Das Hero-Beispiel für Gruppenanrufe von Azure Communication Services veranschaulicht, wie das Communication Services Calling Web-SDK für Anrufe verwendet werden kann, um eine Benutzeroberfläche für Gruppenanrufe zu erstellen.

In diesem Beispielschnellstart erfahren Sie, wie das Beispiel funktioniert, bevor Sie es auf Ihrem lokalen Computer ausführen und dann mithilfe Ihrer eigenen Azure Communication Services-Ressourcen in Azure bereitstellen.

Code herunterladen

Suchen Sie das Projekt für dieses Beispiel auf GitHub. Eine Version des Beispiels mit Features, die sich derzeit in der Public Preview befinden, z. B. Teams Interoperabilität und Anrufaufzeichnung, finden Sie in einem separaten Branch.

Bereitstellung in Azure

Übersicht

Das Beispiel verfügt sowohl über eine clientseitige als auch eine serverseitige Anwendung. Die clientseitige Anwendung ist eine React/Redux-Webanwendung, für die das Fluent-UI-Framework von Microsoft verwendet wird. Diese Anwendung sendet Anforderungen an eine serverseitige ASP.NET Core-Anwendung, die für die clientseitige Anwendung die Verbindungsherstellung mit Azure ermöglicht.

Das Beispiel sieht wie folgt aus:

Screenshot: Landing Page der Beispielanwendung

Wenn Sie auf die Schaltfläche „Start a call“ (Anruf starten) klicken, ruft die Webanwendung ein Benutzerzugriffstoken aus der serverseitigen Anwendung ab. Dieses Token wird dann verwendet, um die Client-App mit Azure Communication Services zu verbinden. Nach dem Abrufen des Tokens werden Sie aufgefordert, die gewünschte Kamera und das Mikrofon anzugeben. Sie können Ihre Geräte mit den entsprechenden Umschaltern deaktivieren und aktivieren:

Screenshot: Bildschirm zur Vorbereitung von Anrufen in der Beispielanwendung

Nachdem Sie Ihren Anzeigenamen und Ihre Geräte konfiguriert haben, können Sie der Anrufsitzung beitreten. Der Hauptbereich für Anrufe, der die zentrale Anrufbenutzeroberfläche enthält, wird angezeigt.

Screenshot: Hauptbildschirm der Beispielanwendung

Komponenten des Hauptbildschirms für Anrufe:

  • Medienkatalog: Der Hauptbereich, in dem die Teilnehmer angezeigt werden. Wenn ein Teilnehmer seine Kamera aktiviert hat, wird der Videofeed hier angezeigt. Jeder Teilnehmer verfügt über eine individuelle Kachel, auf der sein Anzeigename und der Videostream (falls vorhanden) angezeigt werden.
  • Header: Hier befinden sich die wichtigsten Anrufsteuerelemente zum Umschalten der Seitenleiste für Einstellungen und Teilnehmer, Aktivieren/Deaktivieren von Videos und der Mischung, Freigeben des Bildschirms und Beenden des Anrufs.
  • Seitenleiste: Hier werden die Informationen zu den Teilnehmern und Einstellungen angezeigt, wenn der entsprechende Umschalter im Headerbereich verwendet wird. Die Komponente kann mit dem „X“ oben rechts geschlossen werden. Auf der Randleiste für die Teilnehmenden werden eine Liste mit Teilnehmenden und ein Link zum Einladen von weiteren Benutzer*innen zum Chat angezeigt. In der Seitenleiste für die Einstellungen können Sie die Mikrofon- und Kameraeinstellungen konfigurieren.

Weiter unten finden Sie weitere Informationen zu den Voraussetzungen und Schritten zum Einrichten des Beispiels.

Voraussetzungen

Vor dem erstmaligen Ausführen des Beispiels

  1. Öffnen Sie eine Instanz von PowerShell, des Windows-Terminals, einer Eingabeaufforderung oder eines gleichwertigen Tools, und navigieren Sie zu dem Verzeichnis, in dem Sie das Beispiel klonen möchten.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Rufen Sie die Connection String aus dem Azure-Portal oder mithilfe der Azure CLI ab.

    az communication list-key --name "<acsResourceName>" --resource-group "<resourceGroup>"
    

    Weitere Informationen zu Verbindungszeichenfolgen finden Sie unter Erstellen einer Azure Communication Services-Ressource.

  3. Sobald Sie die erhalten habenConnection String, fügen Sie die Verbindungszeichenfolge in die Datei samples/Server/appsetting.json ein. Geben Sie Ihre Verbindungszeichenfolge in die Variable ein: ResourceConnectionString.

  4. Rufen Sie die Endpoint string aus dem Azure-Portal oder mithilfe der Azure CLI ab.

    az communication list-key --name "<acsResourceName>" --resource-group "<resourceGroup>"
    

    Weitere Informationen zu Endpunkt-Strings finden Sie unter Erstellen einer Azure Communication-Ressource

  5. Sobald Sie die erhalten habenEndpoint String, fügen Sie die Endpunktzeichenfolge in die Datei samples/Server/appsetting.json ein. Geben Sie Ihre Endpunktzeichenfolge in die Variable ein: EndpointUrl.

Lokaler Testlauf

  1. Installieren von Abhängigkeiten

    npm run setup
    
  2. Aufruf-App starten

    npm run start
    

    Dadurch wird ein Clientserver für die Websitedateien auf Port 3000 geöffnet sowie ein API-Server auf Port 8080, der Funktionen wie Mintingtoken für Anrufteilnehmende ausführt.

Problembehandlung

  • Die App zeigt einen Bildschirm "Nicht unterstützter Browser", aber ich bin auf einem unterstützten Browser.

    Wenn Ihre App über einen anderen Hostnamen als localhost bereitgestellt wird, müssen Sie den Datenverkehr über https und nicht http bereitstellen.

Veröffentlichen in Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. Verwenden der Azure-Erweiterung und Bereitstellen des Anruf-/Dist-Verzeichnisses für Ihren App-Dienst

Bereinigen von Ressourcen

Wenn Sie ein Communication Services-Abonnement bereinigen und entfernen möchten, können Sie die Ressource oder die Ressourcengruppe löschen. Wenn Sie die Ressourcengruppe löschen, werden auch alle anderen Ressourcen gelöscht, die ihr zugeordnet sind. Weitere Informationen zum Bereinigen von Ressourcen finden Sie hier.

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Artikeln:

Zusätzliche Lektüre

  • Beispiele: In der Übersicht über Beispiele finden Sie weitere Beispiele.
  • Redux: Clientseitige Zustandsverwaltung
  • Fluent-UI: UI-Bibliothek von Microsoft
  • React: Bibliothek zum Erstellen von Benutzeroberflächen
  • ASP.NET Core: Framework für die Erstellung von Webanwendungen

Das Hero-Beispiel für Gruppenanrufe für iOS von Azure Communication Services veranschaulicht, wie das Calling iOS SDK von Communication Services verwendet werden kann, um eine Benutzeroberfläche für Gruppenanrufe mit Sprach- und Videofunktion zu erstellen. In dieser Beispiel-Schnellstartanleitung wird beschrieben, wie Sie das Beispiel einrichten und ausführen. Es ist auch eine Übersicht über das Beispiel vorhanden, um Informationen zum Kontext bereitzustellen.

Code herunterladen

Suchen Sie das Projekt für dieses Beispiel auf GitHub.

Übersicht

Beim diesem Beispiel handelt es sich um eine native iOS-Anwendung, für die die iOS-SDKs von Azure Communication Services zum Entwickeln einer Benutzeroberfläche für Anrufe mit Sprach- und Videofunktion verwendet werden. In der Anwendung wird eine serverseitige Komponente verwendet, um Zugriffstoken bereitzustellen, die dann zum Initialisieren des Azure Communication Services-SDK genutzt werden. Informationen zum Konfigurieren dieser serverseitigen Komponente finden Sie im Tutorial Erstellen eines vertrauenswürdigen Authentifizierungsdiensts mithilfe von Azure Functions.

Das Beispiel sieht wie folgt aus:

Screenshot: Landing Page der Beispielanwendung

Wenn Sie auf die Schaltfläche „Neuen Anruf starten“ klicken, fordert die iOS-Anwendung Sie auf, Ihren Anzeigenamen für den Anruf einzugeben.

Screenshot: Bildschirm zur Vorbereitung von Anrufen in der Beispielanwendung

Nachdem Sie auf dem Bildschirm „Anruf starten“ auf „Weiter“ getippt haben, können Sie die Gruppen-ID des Anrufs über das iOS-Freigabeblatt freigeben.

Screenshot: Bildschirm zum Freigeben der Gruppen-ID in der Beispielanwendung

Darüber hinaus ermöglicht die Anwendung es Ihnen, einem vorhandenen Azure Communication Services-Anruf beizutreten, indem Sie die ID des vorhandenen Anrufs oder einen Teams-ID-Link angeben.

Screenshot: Bildschirm zum Beitritt zu einem Anruf in der Beispielanwendung

Nachdem Sie einem Anruf beigetreten sind, werden Sie aufgefordert, der Anwendung die Berechtigung zum Zugriff auf Ihre Kamera und das Mikrofon zu gewähren (sofern nicht bereits geschehen). Denken Sie daran, dass (wie bei allen AVFoundation-basierten Apps) echte Audio- und Videofunktionen nur auf realer Hardware verfügbar sind.

Sobald Sie Ihren Anzeigenamen konfiguriert und dem Anruf beigetreten sind, wird der Hauptbereich für Anrufe angezeigt, der die zentrale Anrufbenutzeroberfläche enthält.

Screenshot: Hauptbildschirm der Beispielanwendung

Komponenten des Hauptbildschirms für Anrufe:

  • Medienkatalog: Der Hauptbereich, in dem die Teilnehmer angezeigt werden. Wenn ein Teilnehmer seine Kamera aktiviert hat, wird der Videofeed hier angezeigt. Jeder Teilnehmer verfügt über eine individuelle Kachel, auf der sein Anzeigename und der Videostream (falls vorhanden) angezeigt werden. Für den Medienkatalog wird die Anzeige von mehreren Teilnehmern unterstützt, und die Anzeige wird entsprechend aktualisiert, wenn Teilnehmer für den Anruf hinzugefügt oder entfernt werden.
  • Aktionsleiste: Diese Leiste enthält die wichtigsten Anrufsteuerelemente. Mit diesen Steuerelementen können Sie Kamera und Mikrofon ein- und ausschalten, Ihren Bildschirm freigeben und den Anruf verlassen.

Unten sind weitere Informationen zu den Voraussetzungen und Schritten zum Einrichten des Beispiels angegeben.

Voraussetzungen

Lokales Ausführen des Beispiels

Das Beispiel für Gruppenanrufe kann lokal mit Xcode ausgeführt werden. Entwickler können entweder ihr physisches Gerät oder einen Emulator verwenden, um die Anwendung zu testen.

Vor dem erstmaligen Ausführen des Beispiels

  1. Installieren Sie Abhängigkeiten, indem Sie pod install ausführen.
  2. Öffnen Sie AzureCalling.xcworkspace in Xcode.
  3. Erstellen Sie am Stamm eine Textdatei mit dem Namen AppSettings.xcconfig, und legen Sie den Wert fest:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Ausführen des Beispiels

Erstellen Sie das Beispiel in XCode, und führen Sie es mit dem AzureCalling-Ziel auf dem Simulator oder einem Gerät Ihrer Wahl aus.

(Optional) Schützen eines Authentifizierungsendpunkts

Zu Demonstrationszwecken wird in diesem Beispiel standardmäßig ein öffentlich zugänglicher Endpunkt verwendet, um ein Azure Communication Services-Zugriffstoken abzurufen. Für Produktionsszenarien empfehlen wir Ihnen, für die Bereitstellung eigener Token Ihren eigenen geschützten Endpunkt zu erstellen.

Wenn weitere Konfigurationsschritte ausgeführt werden, wird für dieses Beispiel die Verbindungsherstellung mit einem durch Microsoft Entra ID (Microsoft Entra ID) geschützten Endpunkt unterstützt. So kann erreicht werden, dass die Benutzeranmeldung für die App erfordert wird, um ein Azure Communication Services-Zugriffstoken abzurufen. Sehen Sie sich die folgenden Schritte an:

  1. Aktivieren Sie die Microsoft Entra-Authentifizierung in Ihrer App.
  2. Navigieren Sie in Microsoft Entra unter „App-Registrierungen“ zur Übersichtsseite Ihrer registrierten App. Notieren Sie sich die Werte für Application (client) ID, Directory (tenant) ID und Application ID URI.

Microsoft Entra-Konfiguration im Azure-Portal.

  1. Erstellen Sie eine Datei AppSettings.xcconfig am Stamm (sofern nicht bereits vorhanden), und fügen Sie die Werte hinzu:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Bereinigen von Ressourcen

Wenn Sie ein Communication Services-Abonnement bereinigen und entfernen möchten, können Sie die Ressource oder die Ressourcengruppe löschen. Wenn Sie die Ressourcengruppe löschen, werden auch alle anderen Ressourcen gelöscht, die ihr zugeordnet sind. Weitere Informationen zum Bereinigen von Ressourcen finden Sie hier.

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Artikeln:

Zusätzliche Lektüre

Das Hero-Beispiel für Gruppenanrufe für Android von Azure Communication Services veranschaulicht, wie das Calling Android SDK von Communication Services verwendet werden kann, um eine Benutzeroberfläche für Gruppenanrufe mit Sprach- und Videofunktion zu erstellen. In dieser Beispiel-Schnellstartanleitung wird beschrieben, wie Sie das Beispiel einrichten und ausführen. Es ist auch eine Übersicht über das Beispiel vorhanden, um Informationen zum Kontext bereitzustellen.

Code herunterladen

Suchen Sie das Projekt für dieses Beispiel auf GitHub.

Übersicht

Bei diesem Beispiel handelt es sich um eine native Android-Anwendung, die die Azure Communication Services-UI-Clientbibliothek für Android zur Entwicklung einer Anrufbenutzeroberfläche nutzt, die sowohl Sprach- als auch Videoanrufe ermöglicht. In der Anwendung wird eine serverseitige Komponente verwendet, um Zugriffstoken bereitzustellen, die dann zum Initialisieren des Azure Communication Services-SDK genutzt werden. Informationen zum Konfigurieren dieser serverseitigen Komponente finden Sie im Tutorial Erstellen eines vertrauenswürdigen Authentifizierungsdiensts mithilfe von Azure Functions.

Das Beispiel sieht wie folgt aus:

Screenshot: Landing Page der Beispielanwendung

Wenn Sie auf die Schaltfläche „Neuen Anruf starten“ klicken, fordert die Android-Anwendung Sie auf, Ihren Anzeigenamen für den Anruf einzugeben.

Screenshot: Bildschirm zur Vorbereitung von Anrufen in der Beispielanwendung

Nachdem Sie auf der Seite „Anruf starten“ auf „Weiter“ getippt haben, können Sie die Gruppen-ID freigeben.

Screenshot: Bildschirm zum Freigeben der Gruppen-Anruf-ID in der Beispielanwendung

Die Anwendung ermöglicht es Ihnen, einem vorhandenen Azure Communication Services-Anruf beizutreten, indem Sie die ID des vorhandenen Anrufs oder einen ID-Link für eine Teams-Besprechung angeben.

Screenshot: Bildschirm zum Beitritt zu einem Anruf in der Beispielanwendung

Nachdem Sie einem Anruf beigetreten sind, werden Sie aufgefordert, der Anwendung die Berechtigung zum Zugriff auf Ihre Kamera und das Mikrofon zu gewähren (sofern nicht bereits geschehen). Der Hauptbereich für Anrufe, der die zentrale Anrufbenutzeroberfläche enthält, wird angezeigt.

Screenshot: Hauptbildschirm der Beispielanwendung

Komponenten des Hauptbildschirms für Anrufe:

  • Medienkatalog: Der Hauptbereich, in dem die Teilnehmer angezeigt werden. Wenn ein Teilnehmer seine Kamera aktiviert hat, wird der Videofeed hier angezeigt. Jeder Teilnehmer verfügt über eine individuelle Kachel, auf der sein Anzeigename und der Videostream (falls vorhanden) angezeigt werden. Für den Medienkatalog wird die Anzeige von mehreren Teilnehmern unterstützt, und die Anzeige wird entsprechend aktualisiert, wenn Teilnehmer für den Anruf hinzugefügt oder entfernt werden.
  • Aktionsleiste: Diese Leiste enthält die wichtigsten Anrufsteuerelemente. Mit diesen Steuerelementen können Sie Kamera und Mikrofon ein- und ausschalten, Ihren Bildschirm freigeben und den Anruf verlassen.

Unten sind weitere Informationen zu den Voraussetzungen und Schritten zum Einrichten des Beispiels angegeben.

Voraussetzungen

Lokales Ausführen des Beispiels

Das Beispiel für Gruppenanrufe kann lokal mit Android Studio ausgeführt werden. Entwickler können entweder ihr physisches Gerät oder einen Emulator verwenden, um die Anwendung zu testen.

Vor dem erstmaligen Ausführen des Beispiels

  1. Öffnen Sie Android Studio, und wählen Sie Open an Existing Project
  2. Öffnen Sie den Ordner AzureCalling in der heruntergeladenen Version für das Beispiel.
  3. Erweitern Sie zu aktualisierende App/Assets appSettings.properties. Legen Sie als Voraussetzung den Wert für den communicationTokenFetchUrl-Schlüssel auf die URL für Ihren Authentifizierungsendpunkt fest.

Ausführen des Beispiels

Kompilieren Sie das Beispiel in Android Studio, und führen Sie es aus.

(Optional) Schützen eines Authentifizierungsendpunkts

Zu Demonstrationszwecken wird in diesem Beispiel standardmäßig ein öffentlich zugänglicher Endpunkt verwendet, um ein Azure Communication Services-Token abzurufen. Für Produktionsszenarien empfehlen wir Ihnen, für die Bereitstellung eigener Token Ihren eigenen geschützten Endpunkt zu erstellen.

Wenn weitere Konfigurationsschritte ausgeführt werden, wird für dieses Beispiel die Verbindungsherstellung mit einem durch Microsoft Entra ID (Microsoft Entra ID) geschützten Endpunkt unterstützt. So kann erreicht werden, dass die Benutzeranmeldung für die App erfordert wird, um ein Azure Communication Services-Token abzurufen. Sehen Sie sich die folgenden Schritte an:

  1. Aktivieren Sie die Microsoft Entra-Authentifizierung in Ihrer App.

  2. Navigieren Sie in Microsoft Entra unter „App-Registrierungen“ zur Übersichtsseite Ihrer registrierten App. Notieren Sie sich die Werte für Package name, Signature hash und MSAL Configutaion.

Microsoft Entra-Konfiguration im Azure-Portal.

  1. Bearbeiten Sie AzureCalling/app/src/main/res/raw/auth_config_single_account.json, und legen Sie isAADAuthEnabled fest, um Microsoft Entra ID zu aktivieren.

  2. Bearbeiten Sie AndroidManifest.xml, und legen Sie android:path auf einen Signaturhash fest. (Optional. Der aktuelle Wert verwendet einen Hash aus dem gebündelten debug.keystore. Wenn ein anderer Keystore verwendet wird, muss dieser aktualisiert werden.)

    <activity android:name="com.microsoft.identity.client.BrowserTabActivity">
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <data
                     android:host="com.azure.samples.communication.calling"
                     android:path="/Signature hash" <!-- do not remove /. The current hash in AndroidManifest.xml is for debug.keystore. -->
                     android:scheme="msauth" />
             </intent-filter>
         </activity>
    
  3. Kopieren Sie die MSAL Android-Konfiguration aus dem Azure-Portal, und fügen Sie es in AzureCalling/app/src/main/res/raw/auth_config_single_account.json ein. Schließen Sie „account_mode“ : „SINGLE“ ein:

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Bearbeiten Sie AzureCalling/app/src/main/res/raw/auth_config_single_account.json, und legen Sie den Wert für den Schlüssel communicationTokenFetchUrl auf die URL für Ihren Authentifizierungsendpunkt fest.

  5. Bearbeiten Sie AzureCalling/app/src/main/res/raw/auth_config_single_account.json, und legen Sie den Wert des Schlüssels aadScopes auf einen der Azure Active Directory-Bereiche unter Expose an API fest.

  6. Legen Sie den Wert für graphURL in AzureCalling/app/assets/appSettings.properties als Graph-API-Endpunkt zum Abrufen von Benutzerinformationen fest.

  7. Bearbeiten Sie AzureCalling/app/src/main/assets/appSettings.properties, und legen Sie den Wert für den Schlüssel tenant fest, um die automatische Anmeldung zu aktivieren. Auf diese Weise muss sich der Benutzer beim Neustart der Anwendung nicht immer wieder neu authentifizieren.

Bereinigen von Ressourcen

Wenn Sie ein Communication Services-Abonnement bereinigen und entfernen möchten, können Sie die Ressource oder die Ressourcengruppe löschen. Wenn Sie die Ressourcengruppe löschen, werden auch alle anderen Ressourcen gelöscht, die ihr zugeordnet sind. Weitere Informationen zum Bereinigen von Ressourcen finden Sie hier.

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Artikeln:

Zusätzliche Lektüre

Das Hero-Beispiel für Gruppenanrufe für Windows von Azure Communication Services veranschaulicht, wie das Calling Windows SDK von Communication Services verwendet werden kann, um eine Benutzeroberfläche für Gruppenanrufe mit Sprach- und Videofunktion zu erstellen. In diesem Beispiel erfahren Sie, wie Sie das Beispiel einrichten und ausführen. Es ist auch eine Übersicht über das Beispiel vorhanden, um Informationen zum Kontext bereitzustellen.

In dieser Schnellstartanleitung erfahren Sie, wie Sie einen 1:1-Videoanruf mithilfe des Calling SDK von Azure Communication Services für Windows starten.

UWP-Beispielcode

Voraussetzungen

Zum Durchführen dieses Tutorials benötigen Sie Folgendes:

Einrichten

Erstellen des Projekts

Erstellen Sie in Visual Studio ein neues Projekt mit der Vorlage Leere App (Universelle Windows-App) , um eine einseitige UWP-App (Universelle Windows-Plattform) einzurichten.

Screenshot des Fensters „Neues UWP Projekt“ in Visual Studio.

Installieren des Pakets

Klicken Sie mit der rechten Maustaste auf Ihr Projekt, und wechseln Sie zu Manage Nuget Packages, um Azure.Communication.Calling.WindowsClient1.2.0-beta.1 oder einer höhere Version zu installieren. Vergewissern Sie sich, dass „Vorabversion einbeziehen“ aktiviert ist.

Anfordern des Zugriffs

Wechseln Sie zu Package.appxmanifest, und klicken Sie auf Capabilities. Aktivieren Sie Internet (Client & Server), um ein- und ausgehenden Zugriff auf das Internet zu erhalten. Aktivieren Sie Microphone, um auf den Audiofeed des Mikrofons zuzugreifen. Aktivieren Sie WebCam, um auf die Kamera des Geräts zuzugreifen.

Fügen Sie ihrem Package.appxmanifest den folgenden Code hinzu, indem Sie mit einem Rechtsklick auf Ihrer Maus „Code anzeigen“ auswählen.

<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>

Einrichten des App-Frameworks

Wir müssen ein einfaches Layout konfigurieren, um unsere Logik anzufügen. Um einen ausgehenden Anruf zu tätigen, benötigen wir ein TextBox-Element, um die Benutzer-ID des Angerufenen bereitzustellen. Außerdem benötigen wir die Schaltflächen Start Call und Hang Up. Darüber hinaus müssen wir eine Vorschau des lokalen Videos anzeigen und das Remotevideo des anderen Teilnehmers rendern. Daher benötigen wir zwei Elemente zum Anzeigen der Videostreams.

Öffnen Sie in Ihrem Projekt MainPage.xaml, und ersetzen Sie den Inhalt durch folgende Implementierung.

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

    <Grid x:Name="MainGrid" HorizontalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="200*"/>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" x:Name="AppTitleBar" Background="LightSeaGreen">
            <!-- Width of the padding columns is set in LayoutMetricsChanged handler. -->
            <!-- Using padding columns instead of Margin ensures that the background paints the area under the caption control buttons (for transparent buttons). -->
            <TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="4,4,0,0"/>
        </Grid>

        <TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" />

        <Grid Grid.Row="2" Background="LightGray">
            <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" Margin="10">
                <TextBlock VerticalAlignment="Center">Cameras:</TextBlock>
                <ComboBox x:Name="CameraList" HorizontalAlignment="Left" Grid.Column="0" DisplayMemberPath="Name" SelectionChanged="CameraList_SelectionChanged" Margin="10"/>
            </StackPanel>
            <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"/>
                <CheckBox x:Name="BackgroundBlur" Content="Background blur" Width="142" Margin="10,0,0,0" Click="BackgroundBlur_Click"/>
            </StackPanel>
        </StackPanel>
        <TextBox Grid.Row="4" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
    </Grid>
</Page>

Öffnen Sie App.xaml.cs (mit einem Rechtsklick auf Ihrer Maus und „Code anzeigen“ auswählen), und fügen Sie oben diese Zeile hinzu:

using CallingQuickstart;

Öffnen der MainPage.xaml.cs (mit einem Rechtsklick auf Ihrer Maus und „Code anzeigen“ auswählen), und ersetzen Sie den Inhalt mit der folgenden Implementierung:

using Azure.Communication.Calling.WindowsClient;
using System;
using System.Collections.Generic;
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 = "<Azure Communication Services auth token>";
    
        private CallClient callClient;
        private CallTokenRefreshOptions callTokenRefreshOptions;
        private CallAgent callAgent;
        private CommunicationCall call = null;

        private LocalOutgoingAudioStream micStream;
        private LocalOutgoingVideoStream cameraStream;

        #region Page initialization
        public MainPage()
        {
            this.InitializeComponent();
            
            // Hide default title bar.
            var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
            coreTitleBar.ExtendViewIntoTitleBar = true;

            QuickstartTitle.Text = $"{Package.Current.DisplayName} - Ready";
            Window.Current.SetTitleBar(AppTitleBar);

            CallButton.IsEnabled = true;
            HangupButton.IsEnabled = !CallButton.IsEnabled;
            MuteLocal.IsChecked = MuteLocal.IsEnabled = !CallButton.IsEnabled;

            ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(800, 600);
            ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
        }

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

            base.OnNavigatedTo(e);
        }
#endregion

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            // Initialize call agent and Device Manager
        }

        private async void Agent_OnIncomingCallAsync(object sender, IncomingCall incomingCall)
        {
            // Accept an incoming call
        }

        private async void CallButton_Click(object sender, RoutedEventArgs e)
        {
            // Start a call with video
        }

        private async void HangupButton_Click(object sender, RoutedEventArgs e)
        {
            // End the current call
        }

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

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

                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    QuickstartTitle.Text = $"{Package.Current.DisplayName} - {state.ToString()}";
                    Window.Current.SetTitleBar(AppTitleBar);

                    HangupButton.IsEnabled = state == CallState.Connected || state == CallState.Ringing;
                    CallButton.IsEnabled = !HangupButton.IsEnabled;
                    MuteLocal.IsEnabled = !CallButton.IsEnabled;
                });

                switch (state)
                {
                    case CallState.Connected:
                        {
                            break;
                        }
                    case CallState.Disconnected:
                        {
                            break;
                        }
                    default: break;
                }
            }
        }
        
        private async void CameraList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Handle camera selection
        }
    }
}

Objektmodell

Die folgenden Klassen und Schnittstellen befassen sich mit einigen der wichtigsten Features des Azure Communication Services Calling SDK:

Name BESCHREIBUNG
CallClient CallClient ist der Haupteinstiegspunkt der Calling-Client-Bibliothek.
CallAgent CallAgent dient zum Starten von und Teilnehmen an Anrufen.
CommunicationCall CommunicationCall dient zum Verwalten von Anrufen, die getätigt wurden oder an denen teilgenommen wurde.
CallTokenCredential CallTokenCredential dient als tokengestützte Anmeldeinformation zum Instanziieren von CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier wird zur Darstellung der Identität des Benutzers verwendet, der eine der folgenden Optionen sein kann: CommunicationUserIdentifier, PhoneNumberIdentifier oder CallingApplication.

Authentifizieren des Clients

Zum Initialisieren eines CallAgent benötigen Sie ein Benutzerzugriffs-Token. In der Regel wird dieses Token von einem Dienst mit einer für die Anwendung spezifischen Authentifizierung generiert. Weitere Informationen zu Benutzerzugriffstoken finden Sie im Leitfaden zu Benutzerzugriffstoken.

Ersetzen Sie für den Schnellstart <AUTHENTICATION_TOKEN> durch ein Benutzerzugriffstoken, das für Ihre Azure Communication Service-Ressource generiert wurde.

Sobald Sie ein Token haben, initialisieren Sie damit eine CallAgent-Instanz, die es uns ermöglicht, Anrufe zu tätigen und zu empfangen. Um auf die Kameras auf dem Gerät zugreifen zu können, benötigen wir auch eine Geräte-Manager-Instanz.

Fügen Sie der Funktion InitCallAgentAndDeviceManagerAsync den folgenden Code hinzu:

this.callClient = new CallClient(new CallClientOptions() {
    Diagnostics = new CallDiagnosticsOptions() { 
        AppName = "CallingQuickstart",
        AppVersion="1.0",
        Tags = new[] { "Calling", "ACS", "Windows" }
        }
    });

// Set up local video stream using the first camera enumerated
var deviceManager = await this.callClient.GetDeviceManagerAsync();
var camera = deviceManager?.Cameras?.FirstOrDefault();
var mic = deviceManager?.Microphones?.FirstOrDefault();
micStream = new LocalOutgoingAudioStream();

CameraList.ItemsSource = deviceManager.Cameras.ToList();

if (camera != null)
{
    CameraList.SelectedIndex = 0;
}

callTokenRefreshOptions = new CallTokenRefreshOptions(false);
callTokenRefreshOptions.TokenRefreshRequested += OnTokenRefreshRequestedAsync;

var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);

var callAgentOptions = new CallAgentOptions()
{
    DisplayName = "Contoso",
    //https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes/blob/master/all/all.csv
    EmergencyCallOptions = new EmergencyCallOptions() { CountryCode = "840" }
};


try
{
    this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
    //await this.callAgent.RegisterForPushNotificationAsync(await this.RegisterWNS());
    this.callAgent.CallsUpdated += OnCallsUpdatedAsync;
    this.callAgent.IncomingCallReceived += OnIncomingCallAsync;

}
catch(Exception ex)
{
    if (ex.HResult == -2147024809)
    {
        // E_INVALIDARG
        // Handle possible invalid token
    }
}

Starten eines Anrufs mit Video

Fügen Sie die Implementierung zu CallButton_Click hinzu, um einen Anruf mit Video zu starten. Wir müssen die Kameras mit der Gerätemanager-Instanz aufzählen und LocalOutgoingVideoStream konstruieren. Wir müssen VideoOptions mit LocalVideoStream festlegen und mit startCallOptions übergeben, um die Anfangsoptionen für den Anruf festzulegen. Durch Anfügen von LocalOutgoingVideoStream an MediaElement können wir die Vorschau des lokalen Videos sehen.

var callString = CalleeTextBox.Text.Trim();

if (!string.IsNullOrEmpty(callString))
{
    if (callString.StartsWith("8:")) // 1:1 Azure Communication Services call
    {
        call = await StartAcsCallAsync(callString);
    }
    else if (callString.StartsWith("+")) // 1:1 phone call
    {
        call = await StartPhoneCallAsync(callString, "+12133947338");
    }
    else if (Guid.TryParse(callString, out Guid groupId))// Join group call by group guid
    {
        call = await JoinGroupCallByIdAsync(groupId);
    }
    else if (Uri.TryCreate(callString, UriKind.Absolute, out Uri teamsMeetinglink)) //Teams meeting link
    {
        call = await JoinTeamsMeetingByLinkAsync(teamsMeetinglink);
    }
}

if (call != null)
{
    call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
    call.StateChanged += OnStateChangedAsync;
}

Fügen Sie die Methoden hinzu, um die verschiedenen Arten von Anrufen zu starten oder ihnen beizutreten (1:1 ACS-Anruf, 1:1 Telefonanruf, ACS-Gruppenanruf, Beitritt zu einem Team-Meeting usw.).

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

private async Task<CommunicationCall> StartPhoneCallAsync(string acsCallee, string alternateCallerId)
{
    var options = await GetStartCallOptionsAsynnc();
    options.AlternateCallerId = new PhoneNumberCallIdentifier(alternateCallerId);

    var call = await this.callAgent.StartCallAsync( new [] { new PhoneNumberCallIdentifier(acsCallee) }, options);
    return call;
}

private async Task<CommunicationCall> JoinGroupCallByIdAsync(Guid groupId)
{
    var joinCallOptions = await GetJoinCallOptionsAsync();

    var groupCallLocator = new GroupCallLocator(groupId);
    var call = await this.callAgent.JoinAsync(groupCallLocator, joinCallOptions);
    return call;
}

private async Task<CommunicationCall> JoinTeamsMeetingByLinkAsync(Uri teamsCallLink)
{
    var joinCallOptions = await GetJoinCallOptionsAsync();

    var teamsMeetingLinkLocator = new TeamsMeetingLinkLocator(teamsCallLink.AbsoluteUri);
    var call = await callAgent.JoinAsync(teamsMeetingLinkLocator, joinCallOptions);
    return call;
}

private async Task<StartCallOptions> GetStartCallOptionsAsynnc()
{
    return new StartCallOptions() {
        OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true, OutgoingAudioStream = micStream  },
        OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
    };
}

private async Task<JoinCallOptions> GetJoinCallOptionsAsync()
{
    return new JoinCallOptions() {
        OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true },
        OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
    };
}

Fügen Sie den Code zum Erstellen von LocalVideoStream in Abhängigkeit von der gewählten Kamera in der Methode CameraList_SelectionChanged hinzu.

var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamerea);

 var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
    LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});

if (call != null)
{
    await call?.StartVideoAsync(cameraStream);
}

Annehmen eines eingehenden Anrufs

Fügen Sie die Implementierung zu OnIncomingCallAsync hinzu, um einen eingehenden Anruf mit Video zu beantworten, und übergeben Sie den LocalVideoStream an acceptCallOptions.

var incomingCall = args.IncomingCall;

var acceptCallOptions = new AcceptCallOptions() { 
    IncomingVideoOptions = new IncomingVideoOptions()
    {
        IncomingVideoStreamKind = VideoStreamKind.RemoteIncoming
    } 
};

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Remote-Teilnehmer- und -Videostreams

Alle Remoteteilnehmer sind über die RemoteParticipants-Sammlung für eine Anrufinstanz verfügbar. Sobald der Anruf verbunden ist, können wir auf die Remote-Teilnehmer des Anrufs zugreifen und die Remote-Video-Streams verarbeiten.


private async void Call_OnVideoStreamsUpdatedAsync(object sender, RemoteVideoStreamsEventArgs args)
{
    foreach (var remoteVideoStream in args.AddedRemoteVideoStreams)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
        {
            RemoteVideo.Source = await remoteVideoStream.Start();
        });
    }

    foreach (var remoteVideoStream in args.RemovedRemoteVideoStreams)
    {
        remoteVideoStream.Stop();
    }
}

private async void Agent_OnCallsUpdatedAsync(object sender, CallsUpdatedEventArgs args)
{
    var removedParticipants = new List<RemoteParticipant>();
    var addedParticipants = new List<RemoteParticipant>();

    foreach(var call in args.RemovedCalls)
    {
        removedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
    }

    foreach (var call in args.AddedCalls)
    {
        addedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
    }

    await OnParticipantChangedAsync(removedParticipants, addedParticipants);
}

private async Task OnParticipantChangedAsync(IEnumerable<RemoteParticipant> removedParticipants, IEnumerable<RemoteParticipant> addedParticipants)
{
    foreach (var participant in removedParticipants)
    {
        foreach(var incomingVideoStream in  participant.IncomingVideoStreams)
        {
            var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
            if (remoteVideoStream != null)
            {
                await remoteVideoStream.StopPreviewAsync();
            }
        }
        participant.VideoStreamStateChanged -= OnVideoStreamStateChanged;
    }

    foreach (var participant in addedParticipants)
    {
        participant.VideoStreamStateChanged += OnVideoStreamStateChanged;
    }
}

private void OnVideoStreamStateChanged(object sender, VideoStreamStateChangedEventArgs e)
{
    CallVideoStream callVideoStream = e.CallVideoStream;

    switch (callVideoStream.StreamDirection)
    {
        case StreamDirection.Outgoing:
            OnOutgoingVideoStreamStateChanged(callVideoStream as OutgoingVideoStream);
            break;
        case StreamDirection.Incoming:
            OnIncomingVideoStreamStateChanged(callVideoStream as IncomingVideoStream);
            break;
    }
}

private async void OnIncomingVideoStreamStateChanged(IncomingVideoStream incomingVideoStream)
{
    switch (incomingVideoStream.State)
    {
        case VideoStreamState.Available:
        {
            switch (incomingVideoStream.Kind)
            {
                case VideoStreamKind.RemoteIncoming:
                    var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
                    var uri = await remoteVideoStream.StartPreviewAsync();

                    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        RemoteVideo.Source = MediaSource.CreateFromUri(uri);
                    });
                    break;

                case VideoStreamKind.RawIncoming:
                    break;
            }
            break;
        }
        case VideoStreamState.Started:
            break;
        case VideoStreamState.Stopping:
            break;
        case VideoStreamState.Stopped:
            if (incomingVideoStream.Kind == VideoStreamKind.RemoteIncoming)
            {
                var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
                await remoteVideoStream.StopPreviewAsync();
            }
            break;
        case VideoStreamState.NotAvailable:
            break;
    }

}

Rendern von Remote-Videos

Fügen Sie jeden Remotevideostream an MediaElement an.

private async Task AddVideoStreamsAsync(IReadOnlyList<RemoteVideoStream> remoteVideoStreams)
{
    foreach (var remoteVideoStream in remoteVideoStreams)
    {
        var remoteUri = await remoteVideoStream.Start();

        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            RemoteVideo.Source = remoteUri;
            RemoteVideo.Play();
        });
    }
}

Zustandsaktualisierung aufrufen

Wir müssen die Video-Renderer bereinigen, sobald der Anruf getrennt ist und den Fall behandeln, dass Remoteteilnehmer dem Anruf schon zu Anfang beitreten.

private async void Call_OnStateChanged(object sender, PropertyChangedEventArgs args)
{
    switch (((Call)sender).State)
    {
        case CallState.Disconnected:
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                LocalVideo.Source = null;
                RemoteVideo.Source = null;
            });
            break;

        case CallState.Connected:
            foreach (var remoteParticipant in call.RemoteParticipants)
            {
                String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
                remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
                await AddVideoStreams(remoteParticipant.VideoStreams);
                remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdated;
            }
            break;

        default:
            break;
    }
}

Beenden eines Anrufs

Beenden Sie den aktuellen Anruf, nachdem auf die Schaltfläche Hang Up geklickt wurde. Fügen Sie HangupButton_Click die Implementierung hinzu, um einen Aufruf mit dem von uns erstellten callAgent zu beenden, und löschen Sie die Teilnehmeraktualisierung und die Ereignishandler für den Anrufstatus.

var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
    try
    {
        await call.HangUpAsync(new HangUpOptions() { ForEveryone = true });
    }
    catch(Exception ex) 
    {
    }
}

Ausführen des Codes

Sie können den Build in Visual Studio erstellen und den Code ausführen. Für Lösungsplattformen unterstützen wir ARM64, x64 und x86.

Sie können einen ausgehenden Videoanruf tätigen, indem Sie in das Textfeld eine Benutzer-ID eingeben und auf die Schaltfläche Start Call klicken.

Hinweis: Durch den Aufruf von 8:echo123 wird der Video-Stream beendet, da der Echo-Bot das Video-Streaming nicht unterstützt.

Weitere Informationen zu Benutzer IDs (Identität) finden Sie im Leitfaden zu Benutzerzugriffstoken.

WinUI 3-Beispielcode

Voraussetzungen

Zum Durchführen dieses Tutorials benötigen Sie Folgendes:

Einrichten

Erstellen des Projekts

Erstellen Sie in Visual Studio ein neues Projekt mit der Vorlage Leere App, gepackt (WinUI 3 in Desktop), um eine WinUI 3-Einzelseiten-App einzurichten.

Screenshot des Fensters „Neues WinUI-Projekt“ in Visual Studio.

Installieren des Pakets

Klicken Sie mit der rechten Maustaste auf Ihr Projekt, und wechseln Sie zu Manage Nuget Packages, um Azure.Communication.Calling.WindowsClient1.0.0-beta.33 oder einer höhere Version zu installieren. Vergewissern Sie sich, dass „Vorabversion einbeziehen“ aktiviert ist.

Anfordern des Zugriffs

Screenshot: Anfordern des Zugriffs auf das Internet und das Mikrofon in Visual Studio

Fügen Sie Ihrem app.manifest den folgenden Code hinzu:

<file name="RtmMvrMf.dll">
    <activatableClass name="VideoN.VideoSchemeHandler" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>

Einrichten des App-Frameworks

Wir müssen ein einfaches Layout konfigurieren, um unsere Logik anzufügen. Um einen ausgehenden Anruf zu tätigen, benötigen wir ein TextBox-Element, um die Benutzer-ID des Angerufenen bereitzustellen. Außerdem benötigen wir die Schaltflächen Start Call und Hang Up. Darüber hinaus müssen wir eine Vorschau des lokalen Videos anzeigen und das Remotevideo des anderen Teilnehmers rendern. Daher benötigen wir zwei Elemente zum Anzeigen der Videostreams.

Öffnen Sie in Ihrem Projekt MainWindow.xaml, und ersetzen Sie den Inhalt durch folgende Implementierung.

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

    <Grid x:Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="32"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="200*"/>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" x:Name="AppTitleBar" Background="LightSeaGreen">
            <!-- Width of the padding columns is set in LayoutMetricsChanged handler. -->
            <!-- Using padding columns instead of Margin ensures that the background paints the area under the caption control buttons (for transparent buttons). -->
            <TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="4,4,0,0"/>
        </Grid>

        <TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" />

        <Grid Grid.Row="2" Background="LightGray">
            <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" Margin="10">
                <TextBlock VerticalAlignment="Center">Cameras:</TextBlock>
                <ComboBox x:Name="CameraList" HorizontalAlignment="Left" Grid.Column="0" DisplayMemberPath="Name" SelectionChanged="CameraList_SelectionChanged" Margin="10"/>
            </StackPanel>
            <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"/>
                <CheckBox x:Name="BackgroundBlur" Content="Background blur" Width="142" Margin="10,0,0,0" Click="BackgroundBlur_Click"/>
            </StackPanel>
        </StackPanel>
        <TextBox Grid.Row="4" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
    </Grid>    
</Page>

Öffnen Sie App.xaml.cs (mit einem Rechtsklick auf Ihrer Maus und „Code anzeigen“ auswählen), und fügen Sie oben diese Zeile hinzu:

using CallingQuickstart;

Öffnen der MainWindow.xaml.cs (mit einem Rechtsklick auf Ihrer Maus und „Code anzeigen“ auswählen), und ersetzen Sie den Inhalt mit der folgenden Implementierung:

using Azure.Communication.Calling.WindowsClient;
using Azure.WinRT.Communication;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Media.Core;

namespace CallingQuickstart
{
    public sealed partial class MainWindow : Window
    {
        CallAgent callAgent;
        Call call;
        DeviceManager deviceManager;
        Dictionary<string, RemoteParticipant> remoteParticipantDictionary = new Dictionary<string, RemoteParticipant>();

        public MainWindow()
        {
            this.InitializeComponent();
            Task.Run(() => this.InitCallAgentAndDeviceManagerAsync()).Wait();
        }

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            // Initialize call agent and Device Manager
        }

        private async void Agent_OnIncomingCallAsync(object sender, IncomingCall incomingCall)
        {
            // Accept an incoming call
        }

        private async void CallButton_Click(object sender, RoutedEventArgs e)
        {
            // Start a call with video
        }

        private async void HangupButton_Click(object sender, RoutedEventArgs e)
        {
            // End the current call
        }

        private async void Call_OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
        {
            var state = (sender as Call)?.State;
            this.DispatcherQueue.TryEnqueue(() => {
                State.Text = state.ToString();
            });
        }
    }
}

Objektmodell

Die folgenden Klassen und Schnittstellen befassen sich mit einigen der wichtigsten Features des Azure Communication Services Calling SDK:

Name BESCHREIBUNG
CallClient CallClient ist der Haupteinstiegspunkt der Calling-Client-Bibliothek.
CallAgent CallAgent dient zum Starten von und Teilnehmen an Anrufen.
CommunicationCall CommunicationCall dient zum Verwalten von Anrufen, die getätigt wurden oder an denen teilgenommen wurde.
CallTokenCredential CallTokenCredential dient als tokengestützte Anmeldeinformation zum Instanziieren von CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier wird zur Darstellung der Identität des Benutzers verwendet, der eine der folgenden Optionen sein kann: CommunicationUserIdentifier, PhoneNumberIdentifier oder CallingApplication.

Authentifizieren des Clients

Zum Initialisieren eines CallAgent benötigen Sie ein Benutzerzugriffs-Token. In der Regel wird dieses Token von einem Dienst mit einer für die Anwendung spezifischen Authentifizierung generiert. Weitere Informationen zu Benutzerzugriffstoken finden Sie im Leitfaden zu Benutzerzugriffstoken.

Ersetzen Sie für den Schnellstart <AUTHENTICATION_TOKEN> durch ein Benutzerzugriffstoken, das für Ihre Azure Communication Service-Ressource generiert wurde.

Sobald Sie ein Token haben, initialisieren Sie damit eine CallAgent-Instanz, die es uns ermöglicht, Anrufe zu tätigen und zu empfangen. Um auf die Kameras auf dem Gerät zugreifen zu können, benötigen wir auch eine Geräte-Manager-Instanz.

Fügen Sie der Funktion InitCallAgentAndDeviceManagerAsync den folgenden Code hinzu:

var callClient = new CallClient();
this.deviceManager = await callClient.GetDeviceManagerAsync();

var tokenCredential = new CallTokenCredential("<AUTHENTICATION_TOKEN>");
var callAgentOptions = new CallAgentOptions()
{
    DisplayName = "<DISPLAY_NAME>"
};

this.callAgent = await callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
this.callAgent.OnCallsUpdated += Agent_OnCallsUpdatedAsync;
this.callAgent.OnIncomingCall += Agent_OnIncomingCallAsync;

Starten eines Anrufs mit Video

Fügen Sie die Implementierung zu CallButton_Click hinzu, um einen Anruf mit Video zu starten. Wir müssen die Kameras mit der Gerätemanager-Instanz aufzählen und LocalVideoStream konstruieren. Wir müssen VideoOptions mit LocalVideoStream festlegen und mit startCallOptions übergeben, um die Anfangsoptionen für den Anruf festzulegen. Durch Anfügen von LocalVideoStream an MediaPlayerElement können wir die Vorschau des lokalen Videos sehen.

var startCallOptions = new StartCallOptions();

if (this.deviceManager.Cameras?.Count > 0)
{
    var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
    if (videoDeviceInfo != null)
    {
        var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
        cameraStream = new LocalOutgoingVideoStream(selectedCamerea);

        var localUri = await cameraStream.StartPreviewAsync();
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            LocalVideo.Source = MediaSource.CreateFromUri(localUri);
        });

        startCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { cameraStream });
    }
}

var callees = new ICommunicationIdentifier[1]
{
    new CommunicationUserIdentifier(CalleeTextBox.Text.Trim())
};

this.call = await this.callAgent.StartCallAsync(callees, startCallOptions);
this.call.OnRemoteParticipantsUpdated += Call_OnRemoteParticipantsUpdatedAsync;
this.call.OnStateChanged += Call_OnStateChangedAsync;

Annehmen eines eingehenden Anrufs

Fügen Sie die Implementierung zu Agent_OnIncomingCallAsync hinzu, um einen eingehenden Anruf mit Video zu beantworten, und übergeben Sie den LocalVideoStream an acceptCallOptions.

var acceptCallOptions = new AcceptCallOptions();

if (this.deviceManager.Cameras?.Count > 0)
{
    var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
    if (videoDeviceInfo != null)
    {
        var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
        cameraStream = new LocalOutgoingVideoStream(selectedCamerea);

        var localUri = await cameraStream.StartPreviewAsync();
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            LocalVideo.Source = MediaSource.CreateFromUri(localUri);
        });

        acceptCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { localVideoStream });
    }
}

call = await incomingCall.AcceptAsync(acceptCallOptions);

Remote-Teilnehmer- und -Videostreams

Alle Remoteteilnehmer sind über die RemoteParticipants-Sammlung für eine Anrufinstanz verfügbar. Sobald der Anruf verbunden ist, können wir auf die Remote-Teilnehmer des Anrufs zugreifen und die Remote-Video-Streams verarbeiten.

private async void Call_OnVideoStreamsUpdatedAsync(object sender, RemoteVideoStreamsEventArgs args)
{
    foreach (var remoteVideoStream in args.AddedRemoteVideoStreams)
    {
        this.DispatcherQueue.TryEnqueue(async () => {
            RemoteVideo.Source = MediaSource.CreateFromUri(await remoteVideoStream.Start());
            RemoteVideo.MediaPlayer.Play();
        });
    }

    foreach (var remoteVideoStream in args.RemovedRemoteVideoStreams)
    {
        remoteVideoStream.Stop();
    }
}

private async void Agent_OnCallsUpdatedAsync(object sender, CallsUpdatedEventArgs args)
{
    foreach (var call in args.AddedCalls)
    {
        foreach (var remoteParticipant in call.RemoteParticipants)
        {
            var remoteParticipantMRI = remoteParticipant.Identifier.ToString();
            this.remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
            await AddVideoStreamsAsync(remoteParticipant.VideoStreams);
            remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdatedAsync;
        }
    }
}

private async void Call_OnRemoteParticipantsUpdatedAsync(object sender, ParticipantsUpdatedEventArgs args)
{
    foreach (var remoteParticipant in args.AddedParticipants)
    {
        String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
        this.remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
        await AddVideoStreamsAsync(remoteParticipant.VideoStreams);
        remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdatedAsync;
    }

    foreach (var remoteParticipant in args.RemovedParticipants)
    {
        String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
        this.remoteParticipantDictionary.Remove(remoteParticipantMRI);
    }
}

Rendern von Remote-Videos

Fügen Sie jeden Remotevideostream an MediaPlayerElement an.

private async Task AddVideoStreamsAsync(IReadOnlyList<RemoteVideoStream> remoteVideoStreams)
{
    foreach (var remoteVideoStream in remoteVideoStreams)
    {
        var remoteUri = await remoteVideoStream.Start();

        this.DispatcherQueue.TryEnqueue(() => {
            RemoteVideo.Source = MediaSource.CreateFromUri(remoteUri);
            RemoteVideo.MediaPlayer.Play();
        });
    }
}

Zustandsaktualisierung aufrufen

Wir müssen die Video-Renderer bereinigen, sobald der Anruf getrennt ist und den Fall behandeln, dass Remoteteilnehmer dem Anruf schon zu Anfang beitreten.

private async void Call_OnStateChanged(object sender, PropertyChangedEventArgs args)
{
    switch (((Call)sender).State)
    {
        case CallState.Disconnected:
            this.DispatcherQueue.TryEnqueue(() => { =>
            {
                LocalVideo.Source = null;
                RemoteVideo.Source = null;
            });
            break;

        case CallState.Connected:
            foreach (var remoteParticipant in call.RemoteParticipants)
            {
                String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
                remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
                await AddVideoStreams(remoteParticipant.VideoStreams);
                remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdated;
            }
            break;

        default:
            break;
    }
}

Beenden eines Anrufs

Beenden Sie den aktuellen Anruf, nachdem auf die Schaltfläche Hang Up geklickt wurde. Fügen Sie HangupButton_Click die Implementierung hinzu, um einen Aufruf mit dem von uns erstellten callAgent zu beenden, und löschen Sie die Teilnehmeraktualisierung und die Ereignishandler für den Anrufstatus.

this.call.OnRemoteParticipantsUpdated -= Call_OnRemoteParticipantsUpdatedAsync;
this.call.OnStateChanged -= Call_OnStateChangedAsync;
await this.call.HangUpAsync(new HangUpOptions());

Ausführen des Codes

Sie können den Build in Visual Studio erstellen und den Code ausführen. Für Lösungsplattformen unterstützen wir ARM64, x64 und x86.

Sie können einen ausgehenden Videoanruf tätigen, indem Sie in das Textfeld eine Benutzer-ID eingeben und auf die Schaltfläche Start Call klicken.

Hinweis: Durch den Aufruf von 8:echo123 wird der Video-Stream beendet, da der Echo-Bot das Video-Streaming nicht unterstützt.

Weitere Informationen zu Benutzer IDs (Identität) finden Sie im Leitfaden zu Benutzerzugriffstoken.