Kom igång med det anropande hero-exemplet

Varning

Azure Communication Services inför icke bakåtkompatibla ändringar, och vissa tjänster avvecklas. Läs mer i guiden om utfasning och brytande ändringar.

Azure Communication Services Group Calling Hero-exemplet visar hur Communication Services Calling Web SDK kan användas för att skapa en lösning för gruppsamtal.

I den här exempelsnabbstarten lär vi oss hur exemplet fungerar innan vi kör exemplet på den lokala datorn och distribuerar sedan exemplet till Azure med dina egna Azure Communication Services-resurser.

Ladda ned kod

Hitta projektet för det här exemplet på GitHub. En version av exemplet som innehåller funktioner som för närvarande finns i offentlig förhandsversion, till exempel Teams Interop och Samtalsinspelning , finns på en separat gren.

Distribuera till Azure

Översikt

Exemplet har både ett program på klientsidan och ett program på serversidan. Programmet på klientsidan är ett React/Redux-webbprogram som använder Microsofts Fluent UI-ramverk. Det här programmet skickar begäranden till ett ASP.NET Core-program på serversidan som hjälper programmet på klientsidan att ansluta till Azure.

Så här ser exemplet ut:

Skärmbild som visar exempelprogrammets landningssida.

När du trycker på knappen Starta ett anrop hämtar webbprogrammet en användaråtkomsttoken från programmet på serversidan. Den här token används sedan för att ansluta klientappen till Azure Communication Services. När token har hämtats uppmanas du att ange den kamera och mikrofon som du vill använda. Du kan inaktivera/aktivera dina enheter med växlingskontroller:

Skärmbild som visar föranropsskärmen för exempelprogrammet.

När du har konfigurerat visningsnamnet och enheterna kan du ansluta till samtalssessionen. Du kommer att se huvudvyn för samtal där de viktigaste samtalsfunktionerna visas.

Skärmbild som visar huvudskärmen i exempelprogrammet.

Komponenter i huvudsamtalsskärmen:

  • Mediegalleri: Huvudscenen där deltagarna visas. Om en deltagare har sin kamera aktiverad visas deras videoflöde här. Varje deltagare har en egen ruta som visar deras visningsnamn och videoflöde (om det finns något)
  • Sidhuvud: Här finns de viktigaste samtalskontrollerna för att växla inställningar och sidofältet för deltagare, slå av/på video och ljud, dela skärmen och lämna samtalet.
  • Sidofält: Här visas information om deltagare och inställningar när visningen aktiveras med reglagen i sidhuvudet. Komponenten kan stängas med ”X” i det övre högra hörnet. Deltagarnas sidofält visar en lista över deltagare och en länk för att bjuda in fler användare att chatta. Med inställningssidan kan du konfigurera mikrofon- och kamerainställningar.

Nedan hittar du mer information om förutsättningar och steg för att konfigurera exemplet.

Förutsättningar

Innan du kör exemplet för första gången

  1. Öppna en instans av PowerShell, Windows-terminal, kommandotolken eller motsvarande och navigera till katalogen som du vill klona exemplet till.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Hämta Connection String från Azure-portalen eller med Azure CLI.

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

    Mer information om anslutningssträng finns i Skapa en Azure-kommunikationsresurser

  3. När du har hämtat Connection String, lägger du till anslutningssträngen i filen samples/Server/appsetting.json. Ange din anslutningssträng i variabeln: ResourceConnectionString.

  4. Hämta Endpoint string från Azure-portalen eller med Azure CLI.

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

    Mer information om slutpunktssträngar finns i Skapa en Azure-kommunikationsresurs

  5. När du har hämtat Endpoint String, lägger du till slutpunktssträngen i filen samples/Server/appsetting.json. Ange din slutpunktssträng i variabeln EndpointUrl

Lokal körning

  1. Installera beroenden

    npm run setup
    
  2. Starta samtalsappen

    npm run start
    

    Då öppnas en klientserver på port 3000 som hanterar webbplatsfilerna och en API-server på port 8080 som utför funktioner som minting-token för samtalsdeltagare.

Felsökning

  • Appen visar en "webbläsare som inte stöds" men jag finns i en webbläsare som stöds.

    Om din app hanteras över ett annat värdnamn än localhost måste du hantera trafik via https och inte http.

Publicera till Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. Använd Azure-tillägget och distribuera katalogen Calling/dist till din apptjänst

Rensa resurser

Om du vill rensa och ta bort en Communication Services-prenumeration kan du ta bort resursen eller resursgruppen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort. Läs mer om att rensa resurser.

Nästa steg

Mer information finns i följande artiklar:

Mer att läsa

  • Exempel – Hitta fler exempel på vår översiktssida för exempel.
  • Redux – Tillståndshantering på klientsidan
  • FluentUI – Microsofts drivna användargränssnittsbibliotek
  • React – Bibliotek för att skapa användargränssnitt
  • ASP.NET Core – Ramverk för att skapa webbprogram

Azure Communication Services Group Calling Hero Sample för iOS visar hur Communication Services Calling iOS SDK kan användas för att skapa en gruppsamtalsupplevelse som innehåller röst och video. I den här exempelsnabbstarten får du lära dig hur du konfigurerar och kör exemplet. En översikt över exemplet tillhandahålls för kontexten.

Ladda ned kod

Hitta projektet för det här exemplet på GitHub.

Översikt

Exemplet är ett internt iOS-program som använder Azure Communication Services iOS SDK:er för att skapa en samtalsupplevelse som innehåller både röst- och videosamtal. Programmet använder en komponent på serversidan för att etablera åtkomsttoken som sedan används för att initiera Azure Communication Services SDK. Om du vill konfigurera den här komponenten på serversidan kan du följa självstudien Betrodd tjänst med Azure Functions.

Så här ser exemplet ut:

Skärmbild som visar exempelprogrammets landningssida.

När du trycker på knappen "Starta nytt anrop" uppmanar iOS-programmet dig att ange ditt visningsnamn som ska användas för samtalet.

Skärmbild som visar föranropsskärmen för exempelprogrammet.

När du har tryckt på Nästa på skärmen "Starta samtal" har du möjlighet att dela grupp-ID:t för samtalet via iOS-resursbladet.

Skärmbild som visar skärmen för grupp-ID för delning i exempelappen.

Med programmet kan du också ansluta till ett befintligt Azure Communication Services-anrop genom att ange det befintliga anropets ID- eller teams-ID-länk.

Skärmbild som visar skärmen för kopplingsanrop i exempelprogrammet.

När du har anslutit till ett samtal uppmanas du att ge programmet behörighet att komma åt kameran och mikrofonen, om den inte redan är auktoriserad. Tänk på att precis som alla AVFoundation-baserade appar är sann ljud- och videofunktion endast tillgänglig på verklig maskinvara.

När du har ställt in ditt visningsnamn och anslutit till samtalet visas huvudvyn för samtalet, där de viktigaste samtalsfunktionerna finns.

Skärmbild som visar huvudskärmen i exempelprogrammet.

Komponenter i huvudsamtalsskärmen:

  • Mediegalleri: Huvudscenen där deltagarna visas. Om en deltagare har sin kamera aktiverad visas deras videoflöde här. Varje deltagare har en egen ruta som visar deras visningsnamn och videoström (om det finns någon). Galleriet stöder flera deltagare och uppdateras när deltagarna läggs till eller tas bort i anropet.
  • Åtgärdsfält: Här finns de primära anropskontrollerna. Med de här kontrollerna kan du aktivera/inaktivera video och mikrofon, dela skärmen och lämna samtalet.

Nedan hittar du mer information om förutsättningar och steg för att konfigurera exemplet.

Förutsättningar

  • Ett Azure-konto med en aktiv prenumeration. Mer information finns i Skapa ett konto kostnadsfritt.
  • En Mac som kör Xcode, tillsammans med ett giltigt utvecklarcertifikat installerat i nyckelringen.
  • En Azure Communication Services-resurs. Mer information finns i Skapa en Azure Communication Services-resurs.
  • En Azure-funktion som kör autentiseringsslutpunkten för att hämta åtkomsttoken.

Köra exempel lokalt

Gruppsamtalsexemplet kan köras lokalt med XCode. Utvecklare kan antingen använda sin fysiska enhet eller en emulator för att testa programmet.

Innan du kör exemplet för första gången

  1. Installera beroenden genom att köra pod install.
  2. Öppna AzureCalling.xcworkspace i XCode.
  3. Skapa en textfil i roten med namnet AppSettings.xcconfig och ange värdet:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Kör exempel

Skapa och kör exemplet i XCode med hjälp av AzureCalling-målet på valfri simulator eller enhet.

(Valfritt) Skydda en autentiseringsslutpunkt

I demonstrationssyfte använder det här exemplet en offentligt tillgänglig slutpunkt som standard för att hämta en Azure Communication Services-åtkomsttoken. För produktionsscenarier rekommenderar vi att du använder din egen skyddade slutpunkt för att etablera egna token.

Med ytterligare konfiguration stöder det här exemplet anslutning till en Microsoft Entra-ID (Microsoft Entra ID) skyddad slutpunkt så att användarinloggning krävs för att appen ska kunna hämta en Åtkomsttoken för Azure Communication Services. Se stegen nedan:

  1. Aktivera Microsoft Entra-autentisering i din app.
  2. Gå till översiktssidan för din registrerade app under Microsoft Entra-appregistreringar. Observera Application (client) ID, Directory (tenant) ID, Application ID URI

Microsoft Entra-konfiguration på Azure Portal.

  1. Skapa en AppSettings.xcconfig fil i roten om den inte redan finns och lägg till värdena:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Rensa resurser

Om du vill rensa och ta bort en Communication Services-prenumeration kan du ta bort resursen eller resursgruppen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort. Läs mer om att rensa resurser.

Nästa steg

Mer information finns i följande artiklar:

Mer att läsa

Azure Communication Services Group Calling Hero-exemplet för Android visar hur Communication Services Calling Android SDK kan användas för att skapa en gruppsamtalsupplevelse som innehåller röst och video. I den här exempelsnabbstarten får du lära dig hur du konfigurerar och kör exemplet. En översikt över exemplet tillhandahålls för kontexten.

Ladda ned kod

Hitta projektet för det här exemplet på GitHub.

Översikt

Exemplet är ett internt Android-program som använder Azure Communication Services Android UI-klientbiblioteket för att skapa en samtalsupplevelse som innehåller både röst- och videosamtal. Programmet använder en komponent på serversidan för att etablera åtkomsttoken som sedan används för att initiera Azure Communication Services SDK. Om du vill konfigurera den här komponenten på serversidan kan du följa självstudien Betrodd tjänst med Azure Functions.

Så här ser exemplet ut:

Skärmbild som visar exempelprogrammets landningssida.

När du trycker på knappen "Starta nytt anrop" uppmanar Android-programmet dig att ange ditt visningsnamn som ska användas för samtalet.

Skärmbild som visar föranropsskärmen för exempelprogrammet.

När du har tryckt på Nästa på sidan "Starta ett samtal" har du möjlighet att dela "Gruppsamtals-ID".

Skärmbild som visar skärmen för att dela gruppsamtals-ID i exempelappen.

Med programmet kan du ansluta till ett befintligt Azure Communication Services-anrop genom att ange det befintliga samtalets ID eller teams mötes-ID-länk och visningsnamn.

Skärmbild som visar skärmen för kopplingsanrop i exempelprogrammet.

När du har anslutit till ett samtal uppmanas du att ge programmet behörighet att komma åt kameran och mikrofonen, om den inte redan är auktoriserad. Du kommer att se den huvudsakliga samtalsytan där de centrala samtalsfunktionerna finns.

Skärmbild som visar huvudskärmen i exempelprogrammet.

Komponenter i huvudsamtalsskärmen:

  • Mediegalleri: Huvudscenen där deltagarna visas. Om en deltagare har sin kamera aktiverad visas deras videoflöde här. Varje deltagare har en egen ruta som visar deras visningsnamn och videoström (om det finns någon). Galleriet stöder flera deltagare och uppdateras när deltagarna läggs till eller tas bort i anropet.
  • Åtgärdsfält: Här finns de primära anropskontrollerna. Med de här kontrollerna kan du aktivera/inaktivera video och mikrofon, dela skärmen och lämna samtalet.

Nedan hittar du mer information om förutsättningar och steg för att konfigurera exemplet.

Förutsättningar

Köra exempel lokalt

Gruppsamtalsexemplet kan köras lokalt med Android Studio. Utvecklare kan antingen använda sin fysiska enhet eller en emulator för att testa programmet.

Innan du kör exemplet för första gången

  1. Öppna Android Studio och välj Open an Existing Project
  2. Öppna mappen AzureCalling i den nedladdade utgåvan för exemplet.
  3. Expandera app/assets för att uppdatera appSettings.properties. Ange värdet för nyckeln communicationTokenFetchUrl till URL:en för den autentiseringsändpunkt som du har konfigurerat som en förutsättning.

Kör exempel

Skapa och kör exemplet i Android Studio.

(Valfritt) Skydda en autentiseringsslutpunkt

I demonstrationssyfte använder det här exemplet en offentligt tillgänglig slutpunkt som standard för att hämta en Azure Communication Services-token. För produktionsscenarier rekommenderar vi att du använder din egen skyddade slutpunkt för att etablera egna token.

Med ytterligare konfiguration stöder det här exemplet anslutning till en Microsoft Entra-ID (Microsoft Entra ID) skyddad slutpunkt så att användarinloggning krävs för att appen ska kunna hämta en Azure Communication Services-token. Se stegen nedan:

  1. Aktivera Microsoft Entra-autentisering i din app.

  2. Gå till översiktssidan för din registrerade app under Microsoft Entra-appregistreringar. Notera Package name, Signature hash, MSAL Configuration.

Microsoft Entra-konfiguration på Azure Portal.

  1. Redigera AzureCalling/app/src/main/res/raw/auth_config_single_account.json och ange isAADAuthEnabled för att aktivera Microsoft Entra-ID.

  2. Redigera AndroidManifest.xml och ställ in android:path på signaturhashen för nyckellagret. (Valfritt. Det aktuella värdet använder hash från bundled debug.keystore. Om ett annat nyckelarkiv används måste detta uppdateras.)

    <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. Kopiera MSAL Android-konfigurationen från Azure Portal och klistra in till AzureCalling/app/src/main/res/raw/auth_config_single_account.json. Ange "account_mode": "SINGLE"

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Redigera AzureCalling/app/src/main/res/raw/auth_config_single_account.json och ange värdet för nyckeln communicationTokenFetchUrl som URL för din säkra autentiseringsslutpunkt.

  5. Redigera AzureCalling/app/src/main/res/raw/auth_config_single_account.json och ange värdet för nyckeln aadScopes i Azure Active DirectoryExpose an API-omfattningarna

  6. Ange värdet för graphURL i AzureCalling/app/assets/appSettings.properties som Graph API-slutpunkt för att hämta användarinformation.

  7. Redigera AzureCalling/app/src/main/assets/appSettings.properties och ange värdet för nyckeln tenant för att aktivera tyst inloggning så att användaren inte behöver autentiseras om och om igen när programmet startas om.

Rensa resurser

Om du vill rensa och ta bort en Communication Services-prenumeration kan du ta bort resursen eller resursgruppen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort. Läs mer om att rensa resurser.

Nästa steg

Mer information finns i följande artiklar:

Mer att läsa

Azure Communication Services Group Calling Hero Sample för Windows visar hur Communication Services Calling Windows SDK kan användas för att skapa en gruppsamtalsupplevelse som innehåller röst och video. I det här exemplet får du lära dig hur du konfigurerar och kör exemplet. En översikt över exemplet tillhandahålls för kontexten.

I den här snabbstarten får du lära dig hur du startar ett 1:1-videosamtal med hjälp av Azure Communication Services Calling SDK för Windows.

UWP-exempelkod

Förutsättningar

För att slutföra den här självstudien, finns följande förhandskrav:

Konfiguration

Skapa projektet

I Visual Studio skapar du ett nytt projekt med mallen Tom app (Universell Windows) för att konfigurera en enkelsidig Universell Windows-plattform-app (UWP).

Skärmbild som visar fönstret Nytt UWP-projekt i Visual Studio.

Installera paketet

Högerklicka på ditt projekt och gå till Manage Nuget Packages för att installera Azure.Communication.Calling.WindowsClient1.2.0-beta.1 eller senare. Kontrollera att Inkludera förhandsversioner är markerat.

Begär åtkomst

Gå till Package.appxmanifest och klicka på Capabilities. Kontrollera Internet (Client & Server) om du vill få inkommande och utgående åtkomst till Internet. Kontrollera Microphone om du vill komma åt mikrofonens ljudflöde. Kontrollera WebCam om du vill komma åt enhetens kamera.

Lägg till följande kod i din Package.appxmanifest genom att högerklicka och välja Visa kod.

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

Konfigurera appramverket

Vi måste konfigurera en grundläggande layout för att koppla vår logik. För att kunna ringa ett utgående samtal behöver vi ett TextBox för att ange användar-ID:t för den anropade. Vi behöver också en Start Call knapp och en Hang Up knapp. Vi måste också förhandsgranska den lokala videon och återge fjärrvideon för den andra deltagaren. Därför behöver vi två element för att visa videoströmmarna.

MainPage.xaml Öppna projektet och ersätt innehållet med följande implementering.

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

Öppna App.xaml.cs (högerklicka och välj Visa kod) och lägg till den här raden längst upp:

using CallingQuickstart;

MainPage.xaml.cs Öppna (högerklicka och välj Visa kod) och ersätt innehållet med följande implementering:

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

Följande klasser och gränssnitt hanterar några av de viktigaste funktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient CallClient är den huvudsakliga startpunkten för anropsklientbiblioteket.
CallAgent CallAgent Används för att starta och ansluta anrop.
CommunicationCall CommunicationCall Används för att hantera placerade eller anslutna anrop.
CallTokenCredential CallTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier Används för att representera användarens identitet, vilket kan vara något av följande alternativ: CommunicationUserIdentifier, PhoneNumberIdentifier eller CallingApplication.

Autentisera klienten

För att initiera en CallAgentbehöver du en användaråtkomsttoken. Vanligtvis genereras denna token från en tjänst med autentisering som är specifik för programmet. Mer information om token för användaråtkomst finns i guiden Användaråtkomsttoken .

För snabbstarten ersätter du <AUTHENTICATION_TOKEN> med en användaråtkomsttoken som genererats för din Azure Communication Service-resurs.

När du har en token initierar du en CallAgent instans med den, vilket gör att vi kan ringa och ta emot samtal. För att komma åt kamerorna på enheten måste vi också få Enhetshanteraren instans.

Lägg till följande kod i InitCallAgentAndDeviceManagerAsync funktionen.

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

Starta ett samtal med video

Lägg till implementeringen i CallButton_Click för att starta ett anrop med video. Vi måste räkna upp kamerorna med enhetshanterarens instans och skapa LocalOutgoingVideoStream. Vi måste ange VideoOptions med LocalVideoStream och skicka det med startCallOptions för att ange inledande alternativ för anropet. Genom att ansluta LocalOutgoingVideoStream till en MediaElementkan vi se förhandsversionen av den lokala videon.

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

Lägg till metoderna för att starta eller ansluta till de olika typerna av samtal (1:1 Azure Communication Services-samtal, 1:1-telefonsamtal, Gruppsamtal för Azure Communication Services, Teams-mötesanslutning osv.).

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

Lägg till koden för att skapa LocalVideoStream beroende på den valda kameran på CameraList_SelectionChanged metoden.

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

Acceptera ett inkommande samtal

Lägg till implementeringen i OnIncomingCallAsync för att besvara ett inkommande samtal med video, skicka LocalVideoStream till acceptCallOptions.

var incomingCall = args.IncomingCall;

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

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Fjärrdeltagare och fjärrvideoströmmar

Alla deltagare på distans är tillgängliga via samlingen RemoteParticipants i en samtalsinstans. När samtalet ansluts (CallState.Connected) kan vi komma åt fjärrdeltagarna i samtalet och hantera fjärrvideoströmmarna.

Kommentar

När en användare ansluter till ett samtal kan de komma åt de aktuella fjärrdeltagarna via RemoteParticipants samlingen. Händelsen RemoteParticipantsUpdated utlöses inte för dessa befintliga deltagare. Den här händelsen utlöses endast när en fjärrdeltagare ansluter eller lämnar samtalet medan användaren redan är i samtalet.


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

}

Rendera fjärrvideor

För varje fjärrvideoström kopplar du den till 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();
        });
    }
}

Uppdatering av samtalstillstånd

Vi måste rensa videorenderarna när samtalet har kopplats från och hantera fallet när fjärrdeltagarna först ansluter till samtalet.

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

Avsluta samtal

Avsluta det aktuella samtalet när Hang Up knappen klickas. Lägg till implementeringen i HangupButton_Click för att avsluta ett anrop med den callAgent som vi skapade och ta ned händelsehanterare för deltagaruppdatering och samtalstillstånd.

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

Kör koden

Du kan skapa och köra koden i Visual Studio. För lösningsplattformar stöder vi ARM64, x64 och x86.

Du kan göra ett utgående videosamtal genom att ange ett användar-ID i textfältet och klicka på Start Call knappen.

Obs! Att ringa 8:echo123 stoppar videoströmmen eftersom ekoboten inte stöder videoströmning.

Mer information om användar-ID:t (identitet) finns i guiden Användaråtkomsttoken .

WinUI 3-exempelkod

Förutsättningar

För att slutföra den här självstudien, finns följande förhandskrav:

Konfiguration

Skapa projektet

I Visual Studio skapar du ett nytt projekt med mallen Tom app, Paketerad (WinUI 3 i Desktop) för att konfigurera en winui 3-app med en enda sida.

Skärmbild som visar fönstret Nytt WinUI-projekt i Visual Studio.

Installera paketet

Högerklicka på ditt projekt och gå till Manage Nuget Packages för att installera Azure.Communication.Calling.WindowsClient1.0.0 eller senare. Kontrollera att Inkludera förhandsversioner är markerat.

Begär åtkomst

Skärmbild som visar begäran om åtkomst till Internet och mikrofon i Visual Studio.

Lägg till följande kod i din app.manifest:

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

Konfigurera appramverket

Vi måste konfigurera en grundläggande layout för att koppla vår logik. För att kunna ringa ett utgående samtal behöver vi ett TextBox för att ange användar-ID:t för den anropade. Vi behöver också en Start Call knapp och en Hang Up knapp. Vi måste också förhandsgranska den lokala videon och återge fjärrvideon för den andra deltagaren. Därför behöver vi två element för att visa videoströmmarna.

MainWindow.xaml Öppna projektet och ersätt innehållet med följande implementering.

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

Öppna App.xaml.cs (högerklicka och välj Visa kod) och lägg till den här raden längst upp:

using CallingQuickstart;

MainWindow.xaml.cs Öppna (högerklicka och välj Visa kod) och ersätt innehållet med följande implementering:

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

Följande klasser och gränssnitt hanterar några av de viktigaste funktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient CallClient är den huvudsakliga startpunkten för anropsklientbiblioteket.
CallAgent CallAgent Används för att starta och ansluta anrop.
CommunicationCall CommunicationCall Används för att hantera placerade eller anslutna anrop.
CallTokenCredential CallTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier Används för att representera användarens identitet, vilket kan vara något av följande alternativ: CommunicationUserIdentifier, PhoneNumberIdentifier eller CallingApplication.

Autentisera klienten

För att initiera en CallAgentbehöver du en användaråtkomsttoken. Vanligtvis genereras denna token från en tjänst med autentisering som är specifik för programmet. Mer information om token för användaråtkomst finns i guiden Användaråtkomsttoken .

För snabbstarten ersätter du <AUTHENTICATION_TOKEN> med en användaråtkomsttoken som genererats för din Azure Communication Service-resurs.

När du har en token initierar du en CallAgent instans med den, vilket gör att vi kan göra och ta emot anrop. För att komma åt kamerorna på enheten måste vi också få Enhetshanteraren instans.

Lägg till följande kod i InitCallAgentAndDeviceManagerAsync funktionen.

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;

Starta ett samtal med video

Lägg till implementeringen i CallButton_Click för att starta ett anrop med video. Vi måste räkna upp kamerorna med enhetshanterarens instans och skapa LocalVideoStream. Vi måste ange VideoOptions med LocalVideoStream och skicka det med startCallOptions för att ange inledande alternativ för anropet. Genom att ansluta LocalVideoStream till en MediaPlayerElementkan vi se förhandsversionen av den lokala videon.

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;

Acceptera ett inkommande samtal

Lägg till implementeringen i Agent_OnIncomingCallAsync för att besvara ett inkommande samtal med video, skicka LocalVideoStream till 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);

Fjärrdeltagare och fjärrvideoströmmar

Alla deltagare på distans är tillgängliga via samlingen RemoteParticipants i en samtalsinstans. När samtalet är anslutet kan vi komma åt fjärrdeltagarna i samtalet och hantera fjärrvideoströmmarna.

Kommentar

När en användare ansluter till ett samtal kan de komma åt de aktuella fjärrdeltagarna via RemoteParticipants samlingen. Händelsen OnRemoteParticipantsUpdated utlöses inte för dessa befintliga deltagare. Den här händelsen utlöses endast när en fjärrdeltagare ansluter eller lämnar samtalet medan användaren redan är i samtalet.

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

Rendera fjärrvideor

För varje fjärrvideoström kopplar du den till 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();
        });
    }
}

Uppdatering av samtalstillstånd

Vi måste rensa videorenderarna när samtalet har kopplats från och hantera fallet när fjärrdeltagarna först ansluter till samtalet.

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

Avsluta samtal

Avsluta det aktuella samtalet när Hang Up knappen klickas. Lägg till implementeringen i HangupButton_Click för att avsluta ett anrop med den callAgent som vi skapade och ta ned händelsehanterare för deltagaruppdatering och samtalstillstånd.

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

Kör koden

Du kan skapa och köra koden i Visual Studio. För lösningsplattformar stöder vi ARM64, x64 och x86.

Du kan göra ett utgående videosamtal genom att ange ett användar-ID i textfältet och klicka på Start Call knappen.

Obs! Att ringa 8:echo123 stoppar videoströmmen eftersom ekoboten inte stöder videoströmning.

Mer information om användar-ID:t (identitet) finns i guiden Användaråtkomsttoken .