Aan de slag met het voorbeeld van de belheld

Warning

Azure Communication Services voert ingrijpende wijzigingen door en sommige services worden uitgefaseerd. Lees meer in de handleiding voor buitengebruikstelling en ingrijpende wijzigingen.

Het Group Calling Hero Sample van Azure Communication Services laat zien hoe de Calling Web SDK van Communication Services kan worden gebruikt om een ervaring voor groepsgesprekken te bouwen.

In deze quickstart leert u hoe het voorbeeld werkt voordat u het voorbeeld uitvoert op uw lokale computer en vervolgens het voorbeeld implementeert in Azure met behulp van uw eigen Azure Communication Services-resources.

Code downloaden

Zoek het project voor dit voorbeeld op GitHub. Een versie van het voorbeeld met functies die momenteel beschikbaar zijn als openbare preview, zoals Teams Interop en Gespreksopname , vindt u in een afzonderlijke vertakking.

Implementeren op Azure

Overzicht

Het voorbeeld heeft zowel een toepassing aan de clientzijde als een toepassing aan de serverzijde. De toepassing aan de clientzijde is een React/Redux-webtoepassing die gebruikmaakt van het Fluent UI-framework van Microsoft. Met deze toepassing worden aanvragen verzonden naar een ASP.NET Core-toepassing aan de serverzijde zodat de toepassing aan de clientzijde kan worden verbonden met Azure.

Het voorbeeld ziet er als volgt uit:

Schermopname van de landingspagina van de voorbeeldtoepassing.

Wanneer u op de knop 'Gesprek starten' klikt, haalt de webtoepassing een gebruikertoegangstoken op uit de servertoepassing. Vervolgens wordt dit token gebruikt om de client-app met Azure Communication Services te verbinden. Zodra het token is opgehaald, wordt u gevraagd de camera en microfoon op te geven die u wilt gebruiken. U kunt uw apparaten uitschakelen/inschakelen met wisselknoppen:

Schermopname van het scherm voorafgaand aan het gesprek van de voorbeeldtoepassing.

Zodra u uw weergavenaam en apparaten hebt geconfigureerd, kunt u deelnemen aan de gesprekssessie. U ziet het hoofdgesprekscanvas waarin de belangrijkste oproepervaring zich bevindt.

Schermopname van het hoofdscherm van de voorbeeldtoepassing.

Onderdelen van het hoofdgespreksscherm:

  • Mediagalerie: het hoofdpodium waar deelnemers worden weergegeven. Als deelnemers hun camera hebben ingeschakeld, wordt hier hun videofeed weergegeven. Elke deelnemer beschikt over een afzonderlijke tegel waarop hun weergavenaam en videostream (indien beschikbaar) worden weergegeven
  • Koptekst: Hier bevinden de primaire oproepbesturingselementen zich om instellingen en zijbalk van deelnemers in of uit te schakelen, video in of uit te schakelen, scherm te delen en het gesprek te verlaten.
  • Zijbalk: Hier worden informatie over deelnemers en instellingen weergegeven wanneer u deze in- of uitschakelt met de bedieningselementen in de header. U kunt het onderdeel verwijderen door op X te klikken in de rechterbovenhoek. De zijbalk van deelnemers bevat een lijst met deelnemers en een koppeling om meer gebruikers uit te nodigen om te chatten. In de zijbalk met instellingen kunt u de microfoon- en camera-instellingen configureren.

Hieronder vindt u meer informatie over de vereisten en de stappen om het voorbeeld in te stellen.

Vereisten

Voordat u het voorbeeld voor de eerste keer uitvoert

  1. Open een instantie van PowerShell, Windows Terminal, de opdrachtprompt of een vergelijkbare service en ga naar de map waarnaar u het voorbeeld wilt klonen.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Haal de Connection String op via de Azure-portal of met behulp van de Azure CLI.

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

    Zie Een Azure Communications-resource maken voor meer informatie over verbindingsreeksen

  3. Zodra u het Connection Stringbestand hebt, voegt u de verbindingsreeks toe aan het bestand samples/Server/appsetting.json. Voer in de variabele uw verbindingsreeks in: ResourceConnectionString.

  4. Haal de Endpoint string uit de Azure-portal of met behulp van de Azure CLI.

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

    Zie Een Azure Communication-resource maken voor meer informatie over eindpuntreeksen.

  5. Wanneer u de Endpoint String hebt verkregen, voegt u de eindpunttekenreeks toe aan het bestand samples/Server/appsetting.json. Voer uw eindpunttekenreeks in de variabele in EndpointUrl

Lokaal uitvoeren

  1. Afhankelijkheden installeren

    npm run setup
    
  2. De aanroepende app starten

    npm run start
    

    Hiermee opent u een clientserver op poort 3000 die de websitebestanden dient en een API-server op poort 8080 die functionaliteit uitvoert, zoals munttokens voor oproepdeelnemers.

Probleemoplossing

  • In de app wordt een scherm 'Niet-ondersteunde browser' weergegeven, maar ik gebruik een ondersteunde browser.

    Als uw app wordt geleverd via een andere hostnaam dan localhost, moet u verkeer via https en niet http leveren.

Publiceren naar Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. De Azure-extensie gebruiken en de map Aanroepen/verwijderen implementeren in uw app-service

Resources opruimen

Als u een Communication Services-abonnement wilt opschonen en verwijderen, kunt u de resource of resourcegroep verwijderen. Als u de resourcegroep verwijdert, worden ook alle bijbehorende resources verwijderd. Meer informatie over het opschonen van resources.

Volgende stappen

Raadpleeg voor meer informatie de volgende artikelen:

Verder lezen

  • Voorbeelden - Vind meer voorbeelden en voorbeelden op onze overzichtspagina met voorbeelden.
  • Redux: statusbeheer op de client
  • FluentUI: door Microsoft ondersteunde bibliotheek voor de gebruikersinterface
  • React: bibliotheek voor het ontwikkelen van gebruikersinterfaces
  • ASP.NET Core: een framework voor het bouwen van webtoepassingen

De Azure Communication Services-voorbeeldtoepassing voor groepsgesprekken voor iOS demonstreert hoe de Communication Services Calling iOS SDK kan worden gebruikt om een ervaring voor groepsgesprekken met spraak en video te bouwen. In deze voorbeeldsnelstartgids leert u hoe u het voorbeeld instelt en uitvoert. Er wordt een overzicht gegeven van het voorbeeld voor context.

Code downloaden

Zoek het project voor dit voorbeeld op GitHub.

Overzicht

Het voorbeeld is een systeemeigen iOS-toepassing die gebruikmaakt van de Azure Communication Services iOS SDK's om een belervaring te bouwen die zowel spraak- als videogesprekken bevat. De toepassing maakt gebruik van een onderdeel aan de serverzijde om toegangstokens in te richten die vervolgens worden gebruikt om de Azure Communication Services SDK te initialiseren. Om dit serveronderdeel te configureren, kunt u gerust de zelfstudie Trusted Service with Azure Functions volgen.

Het voorbeeld ziet er als volgt uit:

Schermopname van de landingspagina van de voorbeeldtoepassing.

Wanneer u op de knop Nieuwe oproep starten drukt, wordt u door de iOS-toepassing gevraagd uw weergavenaam in te voeren die u voor het gesprek wilt gebruiken.

Schermopname van het scherm voorafgaand aan het gesprek van de voorbeeldtoepassing.

Nadat u op Volgende hebt getikt op het scherm Gesprek starten, hebt u de mogelijkheid om de groeps-id van de oproep te delen via het iOS-shareblad.

Schermafbeelding van het scherm voor het delen van de groeps-id van de voorbeeldtoepassing.

Met de toepassing kunt u ook deelnemen aan een bestaande Azure Communication Services-aanroep door de koppeling naar de id of de teams-id van de bestaande aanroep op te geven.

Schermopname van het scherm join-oproep van de voorbeeldtoepassing.

Nadat u deelneemt aan een gesprek, wordt u gevraagd om de toepassing toestemming te geven om toegang te krijgen tot uw camera en microfoon, als deze nog niet is geautoriseerd. Houd er rekening mee dat, net als alle AVFoundation-apps, echte audio- en videofunctionaliteit alleen beschikbaar is op echte hardware.

Zodra u uw weergavenaam hebt geconfigureerd en deelneemt aan het gesprek, ziet u het hoofdgesprekcanvas waarin de belangrijkste oproepervaring zich bevindt.

Schermopname van het hoofdscherm van de voorbeeldtoepassing.

Onderdelen van het hoofdgespreksscherm:

  • Mediagalerie: het hoofdpodium waar deelnemers worden weergegeven. Als deelnemers hun camera hebben ingeschakeld, wordt hier hun videofeed weergegeven. Elke deelnemer heeft een eigen tegel waarop de weergavenaam en videostream te zien zijn (als die er is). De galerie ondersteunt meerdere deelnemers en wordt bijgewerkt wanneer deelnemers aan het gesprek worden toegevoegd of verwijderd.
  • Actiebalk: hier bevinden zich de primaire oproepbesturingselementen. Met deze besturingselementen kunt u uw video en microfoon in-/uitschakelen, uw scherm delen en het gesprek verlaten.

Hieronder vindt u meer informatie over de vereisten en stappen om het voorbeeld in te stellen.

Vereisten

Lokaal voorbeeld uitvoeren

Het voorbeeld van groepsgesprekken kan lokaal worden uitgevoerd met behulp van XCode. Ontwikkelaars kunnen hun fysieke apparaat of een emulator gebruiken om de toepassing te testen.

Voordat u het voorbeeld voor de eerste keer uitvoert

  1. Installeer afhankelijkheden door uit te voeren pod install.
  2. Open AzureCalling.xcworkspace in Xcode.
  3. Maak in de hoofdmap een tekstbestand met de naam AppSettings.xcconfig en stel de waarde in:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Voorbeeld uitvoeren

Bouw en voer het voorbeeld uit in XCode met behulp van het AzureCalling-doel op de simulator of het apparaat van uw keuze.

(Optioneel) Een verificatie-eindpunt beveiligen

Voor demonstratiedoeleinden gebruikt dit voorbeeld standaard een openbaar toegankelijk eindpunt om een Azure Communication Services-toegangstoken op te halen. Voor productiescenario's raden we u aan uw eigen beveiligde eindpunt te gebruiken om uw eigen tokens in te richten.

Met aanvullende configuratie biedt dit voorbeeld ondersteuning voor het maken van verbinding met een met Microsoft Entra ID beveiligd eindpunt (Microsoft Entra ID), zodat gebruikersaanmelding is vereist voor de app om een Azure Communication Services-toegangstoken op te halen. Zie de onderstaande stappen:

  1. Schakel Microsoft Entra-verificatie in uw app in.
  2. Ga naar de overzichtspagina van uw geregistreerde app onder Microsoft Entra App Registrations. Noteer de Application (client) ID, , Directory (tenant) IDApplication ID URI

Microsoft Entra-configuratie in het Azure-portal.

  1. Maak een AppSettings.xcconfig bestand in de hoofdmap als dit nog niet aanwezig is en voeg de waarden toe:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Resources opruimen

Als u een Communication Services-abonnement wilt opschonen en verwijderen, kunt u de resource of resourcegroep verwijderen. Als u de resourcegroep verwijdert, worden ook alle bijbehorende resources verwijderd. Meer informatie over het opschonen van resources.

Volgende stappen

Raadpleeg voor meer informatie de volgende artikelen:

Verder lezen

Het Hero-voorbeeld voor groepsgesprekken van Azure Communication Services voor Android laat zien hoe de Communication Services Calling Android SDK kan worden gebruikt om een ervaring voor groepsgesprekken met spraak en video te bouwen. In deze voorbeeldsnelstartgids leert u hoe u het voorbeeld instelt en uitvoert. Er wordt een overzicht gegeven van het voorbeeld voor context.

Code downloaden

Zoek het project voor dit voorbeeld op GitHub.

Overzicht

Het voorbeeld is een systeemeigen Android-toepassing die gebruikmaakt van de Azure Communication Services Android UI-clientbibliotheek om een belervaring te bouwen die zowel spraak- als videogesprekken bevat. De toepassing maakt gebruik van een onderdeel aan de serverzijde om toegangstokens in te richten die vervolgens worden gebruikt om de Azure Communication Services SDK te initialiseren. Om dit serveronderdeel te configureren, kunt u gerust de zelfstudie Trusted Service with Azure Functions volgen.

Het voorbeeld ziet er als volgt uit:

Schermopname van de landingspagina van de voorbeeldtoepassing.

Wanneer u op de knop Nieuwe oproep starten drukt, wordt u in de Android-toepassing gevraagd uw weergavenaam in te voeren die u voor het gesprek wilt gebruiken.

Schermopname van het scherm voorafgaand aan het gesprek van de voorbeeldtoepassing.

Nadat u op 'Volgende' op de pagina 'Een gesprek starten' hebt getikt, hebt u de mogelijkheid om de 'Groepsoproep-id' te delen.

Schermafbeelding van het scherm voor het delen van de groepsoproep-ID van de voorbeeldtoepassing.

Met de applicatie kunt u deelnemen aan een bestaand Azure Communication Services-gesprek door de id van het bestaande gesprek of de koppeling naar de vergaderings-id van Teams, en de weergavenaam op te geven.

Schermopname van het scherm join-oproep van de voorbeeldtoepassing.

Nadat u deelneemt aan een gesprek, wordt u gevraagd om de toepassing toestemming te geven om toegang te krijgen tot uw camera en microfoon, als deze nog niet is geautoriseerd. U ziet het hoofdgesprekscanvas waarin de belangrijkste gesprekservaring zich bevindt.

Schermopname van het hoofdscherm van de voorbeeldtoepassing.

Onderdelen van het hoofdgespreksscherm:

  • Mediagalerie: het hoofdpodium waar deelnemers worden weergegeven. Als deelnemers hun camera hebben ingeschakeld, wordt hier hun videofeed weergegeven. Elke deelnemer heeft een eigen tegel waarop de weergavenaam en videostream te zien zijn (als die er is). De galerie ondersteunt meerdere deelnemers en wordt bijgewerkt wanneer deelnemers aan het gesprek worden toegevoegd of verwijderd.
  • Actiebalk: hier bevinden zich de primaire oproepbesturingselementen. Met deze besturingselementen kunt u uw video en microfoon in-/uitschakelen, uw scherm delen en het gesprek verlaten.

Hieronder vindt u meer informatie over de vereisten en stappen om het voorbeeld in te stellen.

Vereisten

Lokaal voorbeeld uitvoeren

De voorbeeldapp voor groepsgesprekken kan lokaal worden uitgevoerd met behulp van Android Studio. Ontwikkelaars kunnen hun fysieke apparaat of een emulator gebruiken om de toepassing te testen.

Voordat u het voorbeeld voor de eerste keer uitvoert

  1. Open Android Studio en selecteer Open an Existing Project
  2. Open de map AzureCalling in de gedownloade release voor het voorbeeld.
  3. Klap app/assets uit om appSettings.properties bij te werken. Stel de waarde voor de sleutel communicationTokenFetchUrl in op de URL van het authenticatie-eindpunt dat u als vereiste hebt ingesteld.

Voorbeeld uitvoeren

Bouw en voer het voorbeeld uit in Android Studio.

(Optioneel) Een verificatie-eindpunt beveiligen

Voor demonstratiedoeleinden gebruikt dit voorbeeld standaard een openbaar toegankelijk eindpunt om een Azure Communication Services-token op te halen. Voor productiescenario's raden we u aan uw eigen beveiligde eindpunt te gebruiken om uw eigen tokens in te richten.

Met extra configuratie ondersteunt dit voorbeeld het maken van verbinding met een met Microsoft Entra ID beveiligd eindpunt (Microsoft Entra ID), zodat gebruikersaanmelding is vereist voor de app om een Azure Communication Services-token op te halen. Zie de onderstaande stappen:

  1. Schakel Microsoft Entra-verificatie in uw app in.

  2. Ga naar de overzichtspagina van uw geregistreerde app onder Microsoft Entra App Registrations. Let op de Package name, Signature hash, MSAL Configuration.

Microsoft Entra-configuratie in het Azure-portal.

  1. Bewerk AzureCalling/app/src/main/res/raw/auth_config_single_account.json en stel isAADAuthEnabled in om Microsoft Entra ID in te schakelen.

  2. Bewerk AndroidManifest.xml en stel android:path in op de handtekeninghash van de sleutelopslag. (Optioneel. De huidige waarde maakt gebruik van hash uit gebundelde foutopsporing.keystore. Als er een ander sleutelarchief wordt gebruikt, moet dit worden bijgewerkt.)

    <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. Kopieer de MSAL Android-configuratie vanuit de Azure-portal en plak deze in AzureCalling/app/src/main/res/raw/auth_config_single_account.json. Neem "account_mode": "SINGLE" op

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Bewerk AzureCalling/app/src/main/res/raw/auth_config_single_account.json en stel de waarde in voor de sleutel communicationTokenFetchUrl als de URL voor uw beveiligde verificatie-eindpunt.

  5. Bewerk AzureCalling/app/src/main/res/raw/auth_config_single_account.json en stel de waarde voor de sleutel aadScopes in uit de bereiken Azure Active DirectoryExpose an API

  6. Stel de waarde voor graphURL in AzureCalling/app/assets/appSettings.properties als het Graph API-eindpunt om gebruikersgegevens op te halen.

  7. Bewerk AzureCalling/app/src/main/assets/appSettings.properties en stel de waarde voor de sleutel tenant in om stille aanmelding in te schakelen, zodat de gebruiker niet opnieuw en opnieuw hoeft te worden geverifieerd tijdens het opnieuw opstarten van de toepassing.

Resources opruimen

Als u een Communication Services-abonnement wilt opschonen en verwijderen, kunt u de resource of resourcegroep verwijderen. Als u de resourcegroep verwijdert, worden ook alle bijbehorende resources verwijderd. Meer informatie over het opschonen van resources.

Volgende stappen

Raadpleeg voor meer informatie de volgende artikelen:

Verder lezen

Het Hero-voorbeeld voor groepsgesprekken voor Windows van Azure Communication Services laat zien hoe de Communication Services Calling Windows SDK kan worden gebruikt om een groepsbelervaring met spraak en video te bouwen. In dit voorbeeld leert u hoe u het voorbeeld instelt en uitvoert. Er wordt een overzicht gegeven van het voorbeeld voor context.

In deze quickstart leert u hoe u een 1:1-videogesprek start met behulp van de Azure Communication Services Calling SDK voor Windows.

UWP-voorbeeldcode

Vereisten

Voor het voltooien van deze zelfstudie moet aan de volgende vereisten worden voldaan:

Configureren

Het project maken

Maak in Visual Studio een nieuw project met de sjabloon Blank App (Universal Windows) om een UWP-app (single page Universeel Windows-platform) in te stellen.

Schermopname van het venster Nieuw UWP-project in Visual Studio.

Het pakket installeren

Klik met de rechtermuisknop op uw project en ga naar Manage Nuget Packages om Azure.Communication.Calling.WindowsClient1.2.0-beta.1 of hoger te installeren. Zorg ervoor dat 'Preleased opnemen' is aangevinkt.

Toegang aanvragen

Ga naar Package.appxmanifest en klik op Capabilities. Schakel Internet (Client & Server) in om inkomende en uitgaande toegang tot het internet te krijgen. Controleer Microphone of u toegang wilt krijgen tot de audiofeed van de microfoon. Controleer WebCam of u toegang hebt tot de camera van het apparaat.

Voeg de volgende code toe aan uw Package.appxmanifest door met de rechtermuisknop te klikken en Code weergeven te kiezen.

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

Stel het app-framework in

We moeten een eenvoudige indeling configureren om onze logica te koppelen. Om een uitgaande oproep te plaatsen, hebben we TextBox nodig om de gebruikers-id van de opgebelde gebruiker op te geven. We hebben ook een Start Call knop en een Hang Up knop nodig. We moeten ook een voorbeeld van de lokale video bekijken en de externe video van de andere deelnemer weergeven. We hebben dus twee elementen nodig om de videostreams weer te geven.

Open het MainPage.xaml project en vervang de inhoud door de volgende implementatie.

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

Open App.xaml.cs (klik met de rechtermuisknop en kies Code weergeven) en voeg deze regel bovenaan toe:

using CallingQuickstart;

Open de MainPage.xaml.cs (klik met de rechtermuisknop en kies Code bekijken) en vervang de inhoud door de volgende implementatie:

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

Objectmodel

De volgende klassen en interfaces verwerken enkele van de belangrijkste functies van de Azure Communication Services Calling SDK:

Name Beschrijving
CallClient Het CallClient is het belangrijkste ingangspunt voor de clientbibliotheek voor Calling.
CallAgent Het CallAgent wordt gebruikt om oproepen te starten en eraan deel te nemen.
CommunicationCall Het CommunicationCall wordt gebruikt voor het beheren van geplaatste of gekoppelde oproepen.
CallTokenCredential De CallTokenCredential wordt gebruikt als het tokengeloofsgegeven om de CallAgent te instantiëren.
CommunicationUserIdentifier Het CommunicationUserIdentifier wordt gebruikt om de identiteit van de gebruiker weer te geven. Dit kan een van de volgende opties zijn: CommunicationUserIdentifier, PhoneNumberIdentifier of CallingApplication.

De client verifiëren

Als u een CallAgentinitialisatie wilt uitvoeren, hebt u een token voor gebruikerstoegang nodig. Over het algemeen wordt dit token gegenereerd op basis van een service met verificatie die specifiek is voor de toepassing. Raadpleeg de handleiding gebruikerstoegangstokens voor meer informatie over tokens voor gebruikerstoegang.

Voor de quickstart vervangt u <AUTHENTICATION_TOKEN> door een gebruikerstoegangstoken dat voor uw Azure Communication Service-resource is gegenereerd.

Zodra u een token hebt, initialiseert u er een CallAgent exemplaar mee, zodat we oproepen kunnen plaatsen en ontvangen. Om toegang te krijgen tot de camera's op het apparaat, moeten we ook Apparaatbeheer exemplaar ophalen.

Voeg de volgende code toe aan de InitCallAgentAndDeviceManagerAsync functie.

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

Een gesprek starten met video

Voeg de implementatie toe aan de CallButton_Click om een videogesprek te starten. We moeten de camera's opsommen met de Device Manager-instantie en LocalOutgoingVideoStream opbouwen. We moeten het VideoOptions instellen met LocalVideoStream en het met startCallOptions doorgeven om de initiële opties voor het gesprek in te stellen. Door LocalOutgoingVideoStream aan een MediaElement te koppelen, kunnen we de voorbeeldweergave van de lokale video zien.

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

Voeg de methoden toe om de verschillende typen oproepen te starten of eraan deel te nemen (1:1 Azure Communication Services-oproep, 1:1 telefoongesprek, Azure Communication Services-groepsgesprek, deelnemen aan Teams-vergadering, enzovoort).

private async Task<CommunicationCall> StartAcsCallAsync(string acsCallee)
{
    var options = await GetStartCallOptionsAsync();
    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 GetStartCallOptionsAsync();
    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> GetStartCallOptionsAsync()
{
    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 } }
    };
}

Voeg de code toe om de LocalVideoStream te maken, afhankelijk van de geselecteerde camera op de CameraList_SelectionChanged methode.

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

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

Een inkomende oproep accepteren

Voeg de implementatie toe aan de OnIncomingCallAsync om een inkomende oproep met video te beantwoorden en geef LocalVideoStream door aan acceptCallOptions.

var incomingCall = args.IncomingCall;

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

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Externe deelnemer en externe videostreams

Alle deelnemers op afstand zijn beschikbaar via de verzameling RemoteParticipants van een oproepinstantie. Zodra de oproep is verbonden (CallState.Connected), hebben we toegang tot de externe deelnemers aan het gesprek en verwerken we de externe videostreams.

Notitie

Wanneer een gebruiker deelneemt aan een gesprek, heeft deze via de RemoteParticipants verzameling toegang tot de huidige externe deelnemers. De RemoteParticipantsUpdated gebeurtenis wordt niet geactiveerd voor deze bestaande deelnemers. Deze gebeurtenis wordt alleen geactiveerd wanneer een externe deelnemer deelneemt of de oproep verlaat terwijl de gebruiker zich al in het gesprek bevindt.


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

}

Externe video's weergeven

Koppel elke externe videostream aan de MediaElement.

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

Update van oproepstatus

We moeten de videorenderers opruimen zodra het gesprek is beëindigd en rekening houden met het geval waarin deelnemers op afstand voor het eerst aan het gesprek deelnemen.

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

Een gesprek beëindigen

Beëindig het huidige gesprek wanneer op de Hang Up knop wordt geklikt. Voeg de implementatie toe aan de HangupButton_Click om een gesprek te beëindigen met de callAgent die we hebben gemaakt, en verwijder de gebeurtenis-handlers voor deelnemersupdates en wijzigingen in de gespreksstatus.

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

De code uitvoeren

U kunt de code bouwen en uitvoeren in Visual Studio. Voor oplossingsplatforms ondersteunen we ARM64, x64 en x86.

U kunt een uitgaande videogesprek voeren door een gebruikers-id op te geven in het tekstveld en op de Start Call knop te klikken.

Opmerking: bellen 8:echo123 stopt de videostream omdat echobot geen ondersteuning biedt voor videostreaming.

Raadpleeg de handleiding gebruikerstoegangstokens voor meer informatie over gebruikers-id's (identiteit).

WinUI 3-voorbeeldcode

Vereisten

Voor het voltooien van deze zelfstudie moet aan de volgende vereisten worden voldaan:

Configureren

Het project maken

Maak in Visual Studio een nieuw project met de sjabloon Blank App, Packaged (WinUI 3 in Desktop) om een WinUI 3-app met één pagina in te stellen.

Schermopname van het venster Nieuw WinUI-project in Visual Studio.

Het pakket installeren

Klik met de rechtermuisknop op uw project en ga naar Manage Nuget Packages om Azure.Communication.Calling.WindowsClient1.0.0 of hoger te installeren. Zorg ervoor dat 'Preleased opnemen' is aangevinkt.

Toegang aanvragen

Schermopname van het aanvragen van toegang tot internet en microfoon in Visual Studio.

Voeg de volgende code toe aan uw app.manifest:

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

Stel het app-framework in

We moeten een eenvoudige indeling configureren om onze logica te koppelen. Om een uitgaande oproep te plaatsen, hebben we TextBox nodig om de gebruikers-id van de opgebelde gebruiker op te geven. We hebben ook een Start Call knop en een Hang Up knop nodig. We moeten ook een voorbeeld van de lokale video bekijken en de externe video van de andere deelnemer weergeven. We hebben dus twee elementen nodig om de videostreams weer te geven.

Open het MainWindow.xaml project en vervang de inhoud door de volgende implementatie.

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

Open App.xaml.cs (klik met de rechtermuisknop en kies Code weergeven) en voeg deze regel bovenaan toe:

using CallingQuickstart;

Open de MainWindow.xaml.cs (klik met de rechtermuisknop en kies Code bekijken) en vervang de inhoud door de volgende implementatie:

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

Objectmodel

De volgende klassen en interfaces verwerken enkele van de belangrijkste functies van de Azure Communication Services Calling SDK:

Name Beschrijving
CallClient Het CallClient is het belangrijkste ingangspunt voor de clientbibliotheek voor Calling.
CallAgent Het CallAgent wordt gebruikt om oproepen te starten en eraan deel te nemen.
CommunicationCall Het CommunicationCall wordt gebruikt voor het beheren van geplaatste of gekoppelde oproepen.
CallTokenCredential De CallTokenCredential wordt gebruikt als het tokengeloofsgegeven om de CallAgent te instantiëren.
CommunicationUserIdentifier Het CommunicationUserIdentifier wordt gebruikt om de identiteit van de gebruiker weer te geven. Dit kan een van de volgende opties zijn: CommunicationUserIdentifier, PhoneNumberIdentifier of CallingApplication.

De client verifiëren

Als u een CallAgentinitialisatie wilt uitvoeren, hebt u een token voor gebruikerstoegang nodig. Over het algemeen wordt dit token gegenereerd op basis van een service met verificatie die specifiek is voor de toepassing. Raadpleeg de handleiding gebruikerstoegangstokens voor meer informatie over tokens voor gebruikerstoegang.

Voor de quickstart vervangt u <AUTHENTICATION_TOKEN> door een gebruikerstoegangstoken dat voor uw Azure Communication Service-resource is gegenereerd.

Zodra u een token hebt, initialiseert u daarmee een exemplaar van CallAgent, waarmee u oproepen kunt plaatsen en ontvangen. Om toegang te krijgen tot de camera's op het apparaat, moeten we ook een instantie van Apparaatbeheer ophalen.

Voeg de volgende code toe aan de InitCallAgentAndDeviceManagerAsync functie.

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;

Een gesprek starten met video

Voeg de implementatie toe aan de CallButton_Click om een oproep met beeld te starten. We moeten de camera's opsommen met de instantie van Apparaatbeheer en LocalVideoStream opbouwen. We moeten de VideoOptions instellen met LocalVideoStream en deze samen met startCallOptions doorgeven om de initiële opties voor het gesprek in te stellen. Door LocalVideoStream aan een MediaPlayerElement te koppelen, kunnen we de voorbeeldweergave van de lokale video zien.

var startCallOptions = new StartCallOptions();

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

        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;

Een inkomende oproep accepteren

Voeg de implementatie toe aan de Agent_OnIncomingCallAsync om een inkomende oproep met video te beantwoorden, geef LocalVideoStream door aan acceptCallOptions.

var acceptCallOptions = new AcceptCallOptions();

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

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

Deelnemer op afstand en videostreams op afstand

Alle externe deelnemers zijn beschikbaar via de verzameling RemoteParticipants in een gespreksinstantie. Zodra de oproep is verbonden, hebben we toegang tot de externe deelnemers aan het gesprek en verwerken we de externe videostreams.

Notitie

Wanneer een gebruiker deelneemt aan een gesprek, heeft deze via de RemoteParticipants verzameling toegang tot de huidige externe deelnemers. De OnRemoteParticipantsUpdated gebeurtenis wordt niet geactiveerd voor deze bestaande deelnemers. Deze gebeurtenis wordt alleen geactiveerd wanneer een externe deelnemer deelneemt of de oproep verlaat terwijl de gebruiker zich al in het gesprek bevindt.

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

Externe video's weergeven

Voor elke externe videostream koppelt u deze aan de MediaPlayerElement.

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

Update van oproepstatus

We moeten de videorenderers opruimen zodra het gesprek is beëindigd en rekening houden met het geval waarin deelnemers op afstand voor het eerst aan het gesprek deelnemen.

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

Een gesprek beëindigen

Beëindig het huidige gesprek wanneer op de Hang Up knop wordt geklikt. Voeg de implementatie toe aan HangupButton_Click om een gesprek te beëindigen met de callAgent die we hebben gemaakt, en ruim de gebeurtenis-handlers voor deelnemersupdates en gespreksstatus op.

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

De code uitvoeren

U kunt de code bouwen en uitvoeren in Visual Studio. Voor oplossingsplatforms ondersteunen we ARM64, x64 en x86.

U kunt een uitgaande videogesprek voeren door een gebruikers-id op te geven in het tekstveld en op de Start Call knop te klikken.

Opmerking: bellen 8:echo123 stopt de videostream omdat echobot geen ondersteuning biedt voor videostreaming.

Raadpleeg de handleiding gebruikerstoegangstokens voor meer informatie over gebruikers-id's (identiteit).