Sdílet prostřednictvím


Začínáme s ukázkou volajícího hrdiny

Ukázka volání skupinových služeb Azure Communication Services Hero ukazuje, jak lze k vytvoření prostředí skupinového volání použít sadu SDK pro volání komunikačních služeb.

V tomto ukázkovém rychlém startu se dozvíte, jak ukázka funguje, než ukázku spustíme na místním počítači, a pak ukázku nasadíme do Azure pomocí vlastních prostředků Azure Communication Services.

Stažení kódu

Najděte projekt pro tuto ukázku na GitHubu. Verze ukázky, která obsahuje funkce, které jsou aktuálně ve verzi Public Preview, jako je Spolupráce v Teams a Nahrávání hovorů, najdete v samostatné větvi.

Nasazení do Azure

Přehled

Ukázka obsahuje aplikaci na straně klienta i serverovou aplikaci. Klientská aplikace je webová aplikace React/Redux, která používá rozhraní Fluent UI od Microsoftu. Tato aplikace odesílá požadavky do aplikace na straně serveru ASP.NET Core, která pomáhá aplikaci na straně klienta připojit se k Azure.

Ukázka vypadá takto:

Snímek obrazovky znázorňující cílovou stránku ukázkové aplikace

Když stisknete tlačítko Spustit volání, webová aplikace načte přístupový token uživatele z aplikace na straně serveru. Tento token se pak použije k připojení klientské aplikace ke službě Azure Communication Services. Po načtení tokenu se zobrazí výzva k zadání kamery a mikrofonu, který chcete použít. Zařízení můžete zakázat nebo povolit pomocí přepínacích ovládacích prvků:

Snímek obrazovky znázorňující obrazovku před voláním ukázkové aplikace

Jakmile nakonfigurujete zobrazované jméno a zařízení, můžete se připojit k relaci volání. Zobrazí se plátno hlavního volání, kde se nachází základní prostředí volání.

Snímek obrazovky znázorňující hlavní obrazovku ukázkové aplikace

Součásti hlavní volající obrazovky:

  • Galerie médií: Hlavní fáze, kde se zobrazují účastníci. Pokud má účastník povolenou kameru, zobrazí se zde informační kanál videa. Každý účastník má samostatnou dlaždici, která zobrazuje zobrazované jméno a video stream (pokud existuje).
  • Záhlaví: Tady se nacházejí ovládací prvky primárního volání pro přepínání nastavení a bočního panelu účastníků, zapnutí nebo vypnutí videa, sdílení obrazovky a opuštění hovoru.
  • Boční panel: Tady se při přepínání pomocí ovládacích prvků v záhlaví zobrazují informace o účastnících a nastaveních. Komponentu lze zavřít pomocí symbolu X v pravém horním rohu. Na bočním panelu účastníků se zobrazuje seznam účastníků a odkaz pro pozvání dalších uživatelů do chatu. Boční panel nastavení umožňuje konfigurovat nastavení mikrofonu a kamery.

Níže najdete další informace o požadavcích a krocích pro nastavení ukázky.

Požadavky

Před prvním spuštěním ukázky

  1. Otevřete instanci PowerShellu, Terminál Windows, příkazového řádku nebo ekvivalent a přejděte do adresáře, do kterého chcete ukázku naklonovat.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Získejte azure Connection String z webu Azure Portal nebo pomocí Azure CLI.

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

    Další informace o připojovací řetězec najdete v tématu Vytvoření komunikačních prostředků Azure.

  3. Jakmile ho získáteConnection String, přidejte připojovací řetězec do souboru samples/Server/appsetting.json. Zadejte připojovací řetězec do proměnné: ResourceConnectionString.

  4. Získejte azure Endpoint string z webu Azure Portal nebo pomocí Azure CLI.

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

    Další informace o řetězcích koncových bodů najdete v tématu Vytvoření komunikačních prostředků Azure.

  5. Jakmile získáte Endpoint Stringřetězec koncového bodu, přidejte do souboru samples/Server/appsetting.json . Zadejte řetězec koncového bodu do proměnné. EndpointUrl

Místní spuštění

  1. Instalace závislostí

    npm run setup
    
  2. Spuštění volající aplikace

    npm run start
    

    Tím se otevře klientský server na portu 3000, který obsluhuje soubory webu, a server rozhraní API na portu 8080, který provádí funkce, jako je vytěsňování tokenů pro účastníky volání.

Řešení problému

  • Aplikace zobrazuje obrazovku Nepodporovaný prohlížeč, ale jsem v podporovaném prohlížeči.

    Pokud se vaše aplikace obsluhuje přes jiný název hostitele než localhost, musíte obsluhovat provoz přes https a ne http.

Publikování do Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. Použití rozšíření Azure a nasazení adresáře Volání/dist do služby App Service

Vyčištění prostředků

Pokud chcete vyčistit a odebrat předplatné služby Communication Services, můžete odstranit prostředek nebo skupinu prostředků. Odstraněním skupiny prostředků se odstraní také všechny ostatní prostředky, které jsou k ní přidružené. Přečtěte si další informace o čištění prostředků.

Další kroky

Další informace najdete v následujících článcích:

Další čtení

  • Ukázky – další ukázky a příklady najdete na stránce s přehledem ukázek.
  • Redux – Správa stavu na straně klienta
  • FluentUI – Knihovna uživatelského rozhraní Microsoftu
  • React – Knihovna pro vytváření uživatelských rozhraní
  • ASP.NET Core – architektura pro vytváření webových aplikací

Ukázka volání skupinových služeb Azure Communication Services pro iOS ukazuje, jak lze sadu SDK pro volání komunikačních služeb pro iOS použít k vytvoření skupinového volání, které zahrnuje hlas a video. V tomto ukázkovém rychlém startu se dozvíte, jak nastavit a spustit ukázku. Přehled ukázky je k dispozici pro kontext.

Stažení kódu

Najděte projekt pro tuto ukázku na GitHubu.

Přehled

Ukázka je nativní aplikace pro iOS, která používá sady SDK služby Azure Communication Services pro iOS k vytvoření volajícího prostředí, které obsahuje hlasové i videohovory. Aplikace používá komponentu na straně serveru ke zřízení přístupových tokenů, které se pak používají k inicializaci sady SDK služby Azure Communication Services. Pokud chcete nakonfigurovat tuto součást na straně serveru, můžete postupovat podle kurzu k důvěryhodné službě pomocí služby Azure Functions .

Ukázka vypadá takto:

Snímek obrazovky znázorňující cílovou stránku ukázkové aplikace

Když stisknete tlačítko "Zahájit nový hovor", aplikace pro iOS vás vyzve k zadání zobrazovaného jména, které se má pro hovor použít.

Snímek obrazovky znázorňující obrazovku před voláním ukázkové aplikace

Po klepnutí na tlačítko Další na obrazovce Zahájit hovor máte možnost sdílet ID skupiny hovoru prostřednictvím share listu pro iOS.

Snímek obrazovky s ID skupiny sdílení ukázkové aplikace

Aplikace také umožňuje připojit se k existujícímu volání služby Azure Communication Services zadáním ID existujícího volání nebo odkazu NA ID týmu.

Snímek obrazovky znázorňující obrazovku volání připojení ukázkové aplikace

Po připojení k hovoru se zobrazí výzva, abyste aplikaci dali oprávnění pro přístup k fotoaparátu a mikrofonu, pokud ještě nemáte oprávnění. Mějte na paměti, že stejně jako všechny aplikace založené na AVFoundation jsou skutečné funkce zvuku a videa dostupné pouze na skutečném hardwaru.

Jakmile nakonfigurujete zobrazované jméno a připojíte se k hovoru, uvidíte plátno hlavního volání, kde se nachází základní prostředí volání.

Snímek obrazovky znázorňující hlavní obrazovku ukázkové aplikace

Součásti hlavní volající obrazovky:

  • Galerie médií: Hlavní fáze, kde se zobrazují účastníci. Pokud má účastník povolenou kameru, zobrazí se zde informační kanál videa. Každý účastník má samostatnou dlaždici, která zobrazuje zobrazované jméno a video stream (pokud existuje). Galerie podporuje více účastníků a aktualizuje se při přidání nebo odebrání účastníků do hovoru.
  • Panel akcí: Tady se nacházejí primární ovládací prvky volání. Tyto ovládací prvky umožňují zapnout nebo vypnout video a mikrofon, sdílet obrazovku a opustit hovor.

Níže najdete další informace o požadavcích a krocích pro nastavení ukázky.

Požadavky

  • Účet Azure s aktivním předplatným. Podrobnosti najdete v tématu Vytvoření účtu zdarma.
  • Mac se systémem Xcode spolu s platným certifikátem vývojáře nainstalovaným do klíčenky.
  • Prostředek Azure Communication Services. Podrobnosti najdete v tématu Vytvoření prostředku Azure Communication Services.
  • Funkce Azure, která spouští koncový bod ověřování pro načtení přístupových tokenů.

Místní spuštění ukázky

Ukázku volání skupiny je možné spustit místně pomocí XCode. Vývojáři můžou k otestování aplikace použít fyzické zařízení nebo emulátor.

Před prvním spuštěním ukázky

  1. Nainstalujte závislosti spuštěním pod installpříkazu .
  2. Otevřete AzureCalling.xcworkspace v XCode.
  3. Vytvořte textový soubor v kořenovém adresáři a AppSettings.xcconfig nastavte hodnotu:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Spuštění ukázky

Sestavte a spusťte ukázku v XCode pomocí cíle AzureCalling na simulátoru nebo zařízení podle vašeho výběru.

(Volitelné) Zabezpečení koncového bodu ověřování

Pro demonstrační účely tato ukázka ve výchozím nastavení používá veřejně přístupný koncový bod k načtení přístupového tokenu služby Azure Communication Services. V produkčních scénářích doporučujeme ke zřízení vlastních tokenů použít vlastní zabezpečený koncový bod.

Tato ukázka s další konfigurací podporuje připojení ke koncovému bodu chráněnému microsoft entra ID (Microsoft Entra ID), aby se pro aplikaci vyžadovalo přihlášení uživatele k načtení přístupového tokenu služby Azure Communication Services. Projděte si následující kroky:

  1. Povolte v aplikaci ověřování Microsoft Entra.
  2. V části Registrace aplikací Microsoft Entra přejděte na stránku s přehledem zaregistrované aplikace. Poznamenejte Application (client) IDsi , Directory (tenant) IDApplication ID URI

Konfigurace Microsoft Entra na webu Azure Portal

  1. Vytvořte AppSettings.xcconfig soubor v kořenovém adresáři, pokud ještě není k dispozici, a přidejte hodnoty:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Vyčištění prostředků

Pokud chcete vyčistit a odebrat předplatné služby Communication Services, můžete odstranit prostředek nebo skupinu prostředků. Odstraněním skupiny prostředků se odstraní také všechny ostatní prostředky, které jsou k ní přidružené. Přečtěte si další informace o čištění prostředků.

Další kroky

Další informace najdete v následujících článcích:

Další čtení

Ukázka volání skupiny Azure Communication Services pro Android ukazuje, jak lze sadu SDK pro volání komunikačních služeb pro Android použít k vytvoření skupinového volání, které zahrnuje hlas a video. V tomto ukázkovém rychlém startu se dozvíte, jak nastavit a spustit ukázku. Přehled ukázky je k dispozici pro kontext.

Stažení kódu

Najděte projekt pro tuto ukázku na GitHubu.

Přehled

Ukázka je nativní aplikace pro Android, která používá klientskou knihovnu uživatelského rozhraní Androidu v Azure Communication Services k vytvoření volajícího prostředí, které obsahuje hlasové i videohovory. Aplikace používá komponentu na straně serveru ke zřízení přístupových tokenů, které se pak používají k inicializaci sady SDK služby Azure Communication Services. Pokud chcete nakonfigurovat tuto součást na straně serveru, můžete postupovat podle kurzu k důvěryhodné službě pomocí služby Azure Functions .

Ukázka vypadá takto:

Snímek obrazovky znázorňující cílovou stránku ukázkové aplikace

Když stisknete tlačítko Zahájit nový hovor, aplikace pro Android vás vyzve k zadání zobrazovaného jména, které se má pro hovor použít.

Snímek obrazovky znázorňující obrazovku před voláním ukázkové aplikace

Po klepnutí na tlačítko Další na stránce Zahájit hovor máte možnost sdílet ID skupinového hovoru.

Snímek obrazovky s ID skupinového volání ukázkové aplikace

Aplikace umožňuje připojit se k existujícímu volání služby Azure Communication Services zadáním ID existujícího hovoru nebo odkazu na ID schůzky týmů a zobrazovaného jména.

Snímek obrazovky znázorňující obrazovku volání připojení ukázkové aplikace

Po připojení k hovoru se zobrazí výzva, abyste aplikaci dali oprávnění pro přístup k fotoaparátu a mikrofonu, pokud ještě nemáte oprávnění. Uvidíte plátno hlavního volání, kde se nachází základní prostředí volání.

Snímek obrazovky znázorňující hlavní obrazovku ukázkové aplikace

Součásti hlavní volající obrazovky:

  • Galerie médií: Hlavní fáze, kde se zobrazují účastníci. Pokud má účastník povolenou kameru, zobrazí se zde informační kanál videa. Každý účastník má samostatnou dlaždici, která zobrazuje zobrazované jméno a video stream (pokud existuje). Galerie podporuje více účastníků a aktualizuje se při přidání nebo odebrání účastníků do hovoru.
  • Panel akcí: Tady se nacházejí primární ovládací prvky volání. Tyto ovládací prvky umožňují zapnout nebo vypnout video a mikrofon, sdílet obrazovku a opustit hovor.

Níže najdete další informace o požadavcích a krocích pro nastavení ukázky.

Požadavky

  • Účet Azure s aktivním předplatným. Podrobnosti najdete v tématu Vytvoření účtu zdarma.
  • Android Studio spuštěné na vašem počítači
  • Prostředek Azure Communication Services. Podrobnosti najdete v tématu Vytvoření prostředku Azure Communication Services.
  • Funkce Azure, která spouští koncový bod ověřování pro načtení přístupových tokenů.

Místní spuštění ukázky

Ukázku volání skupiny je možné spustit místně pomocí Android Studia. Vývojáři můžou k otestování aplikace použít fyzické zařízení nebo emulátor.

Před prvním spuštěním ukázky

  1. Otevřete Android Studio a vyberte Open an Existing Project
  2. AzureCalling Otevřete složku uvnitř stažené verze pro ukázku.
  3. Rozbalte aplikaci nebo prostředky, které chcete aktualizovat appSettings.properties. Nastavte hodnotu klíče communicationTokenFetchUrl tak, aby byla adresa URL vašeho koncového bodu ověřování nastavená jako předpoklad.

Spuštění ukázky

Sestavte a spusťte ukázku v Android Studiu.

(Volitelné) Zabezpečení koncového bodu ověřování

Pro demonstrační účely tato ukázka ve výchozím nastavení používá veřejně přístupný koncový bod k načtení tokenu Azure Communication Services. V produkčních scénářích doporučujeme ke zřízení vlastních tokenů použít vlastní zabezpečený koncový bod.

V případě další konfigurace tato ukázka podporuje připojení ke koncovému bodu chráněnému Microsoft Entra ID (Microsoft Entra ID), aby se pro aplikaci vyžadovalo přihlášení uživatele k načtení tokenu služby Azure Communication Services. Projděte si následující kroky:

  1. Povolte v aplikaci ověřování Microsoft Entra.

  2. V části Registrace aplikací Microsoft Entra přejděte na stránku s přehledem zaregistrované aplikace. Povšimněte Package namesi , Signature hash, MSAL Configutaion.

Konfigurace Microsoft Entra na webu Azure Portal

  1. Upravte AzureCalling/app/src/main/res/raw/auth_config_single_account.json a nastavte isAADAuthEnabled povolení MICROSOFT Entra ID.

  2. Upravte AndroidManifest.xml a nastavte android:path hodnotu hash podpisu úložiště klíčů. (Volitelné. Aktuální hodnota používá hodnotu hash z bundled debug.keystore. Pokud se používá jiné úložiště klíčů, je nutné ho aktualizovat.)

    <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. Zkopírujte konfiguraci MSAL Pro Android z webu Azure Portal a vložte do AzureCalling/app/src/main/res/raw/auth_config_single_account.jsonsouboru . Zahrnout "account_mode": "SINGLE"

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Upravte AzureCalling/app/src/main/res/raw/auth_config_single_account.json a nastavte hodnotu klíče communicationTokenFetchUrl tak, aby byla adresa URL vašeho zabezpečeného koncového bodu ověřování.

  5. Úprava AzureCalling/app/src/main/res/raw/auth_config_single_account.json a nastavení hodnoty klíče aadScopes z Azure Active Directory Expose an API oborů

  6. Nastavte hodnotu graphURL in AzureCalling/app/assets/appSettings.properties jako koncový bod rozhraní Graph API pro načtení informací o uživateli.

  7. Upravte AzureCalling/app/src/main/assets/appSettings.properties a nastavte hodnotu klíče tenant , aby bylo možné povolit tiché přihlášení, aby se uživatel nemusel znovu ověřovat a znovu při restartování aplikace.

Vyčištění prostředků

Pokud chcete vyčistit a odebrat předplatné služby Communication Services, můžete odstranit prostředek nebo skupinu prostředků. Odstraněním skupiny prostředků se odstraní také všechny ostatní prostředky, které jsou k ní přidružené. Přečtěte si další informace o čištění prostředků.

Další kroky

Další informace najdete v následujících článcích:

Další čtení

Ukázka volání skupiny Azure Communication Services pro Windows ukazuje, jak lze sadu Windows SDK pro volání komunikačních služeb použít k vytvoření skupinového volání, které zahrnuje hlas a video. V této ukázce se dozvíte, jak nastavit a spustit ukázku. Přehled ukázky je k dispozici pro kontext.

V tomto rychlém startu se dozvíte, jak spustit videohovor ve verzi 1:1 pomocí sady SDK pro volání služeb Azure Communication Services pro Windows.

Ukázkový kód UPW

Požadavky

Pro absolvování tohoto kurzu musí být splněné následující požadavky:

Nastavení

Vytvoření projektu

V sadě Visual Studio vytvořte nový projekt pomocí šablony Prázdná aplikace (Univerzální windows) pro nastavení jednostránka Univerzální platforma Windows (UPW).

Snímek obrazovky s oknem Nový projekt UPW v sadě Visual Studio

Nainstalujte balíček .

Klikněte pravým tlačítkem na projekt a přejděte na Manage Nuget Packages instalaci Azure.Communication.Calling.WindowsClient verze 1.2.0-beta.1 nebo vyšší verze. Ujistěte se, že je zaškrtnuté políčko Zahrnout předběžné verze.

Vyžádat si přístup

Přejděte na Package.appxmanifest a klikněte na Capabilities. Zkontrolujte Internet (Client & Server) , jestli chcete získat příchozí a odchozí přístup k internetu. Zkontrolujte Microphone přístup ke zvukovému kanálu mikrofonu. Zkontrolujte WebCam přístup ke kameře zařízení.

Kliknutím pravým tlačítkem myši a zvolením možnosti Zobrazit kód přidejte následující kód.Package.appxmanifest

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

Nastavení architektury aplikace

Potřebujeme nakonfigurovat základní rozložení pro připojení naší logiky. Abychom mohli umístit odchozí hovor, musíme TextBox zadat ID uživatele volaného. Potřebujeme Start Call také tlačítko a Hang Up tlačítko. Potřebujeme také zobrazit náhled místního videa a vykreslit vzdálené video druhého účastníka. Potřebujeme tedy dva prvky k zobrazení streamů videa.

MainPage.xaml Otevřete projekt a nahraďte obsah následující implementací.

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

Otevřete ( App.xaml.cs klikněte pravým tlačítkem myši a zvolte Zobrazit kód) a přidejte tento řádek do horní části:

using CallingQuickstart;

MainPage.xaml.cs Otevřete (klikněte pravým tlačítkem myši a zvolte Zobrazit kód) a nahraďte obsah následující implementací:

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

Objektový model

Následující třídy a rozhraní zpracovávají některé z hlavních funkcí sady SDK pro volání služeb Azure Communication Services:

Název Popis
CallClient Jedná se CallClient o hlavní vstupní bod do klientské knihovny volání.
CallAgent Slouží CallAgent ke spuštění a připojení k voláním.
CommunicationCall Slouží CommunicationCall ke správě umístěných nebo připojených hovorů.
CallTokenCredential Slouží CallTokenCredential jako přihlašovací údaje tokenu k vytvoření instance CallAgent.
CommunicationUserIdentifier Slouží CommunicationUserIdentifier k reprezentaci identity uživatele, což může být jedna z následujících možností: CommunicationUserIdentifiernebo PhoneNumberIdentifier CallingApplication.

Ověření klienta

K inicializaci CallAgentpotřebujete přístupový token uživatele. Obecně platí, že tento token se generuje ze služby s ověřováním specifickým pro aplikaci. Další informace o přístupových tokenech uživatelů najdete v průvodci uživatelskými přístupovými tokeny .

V tomto rychlém startu nahraďte <AUTHENTICATION_TOKEN> přístupovým tokenem uživatele vygenerovaným pro prostředek služby Azure Communication Service.

Jakmile máte token, inicializujete CallAgent s ní instanci, která nám umožní provádět a přijímat volání. Abychom měli přístup k fotoaparátům na zařízení, musíme také získat Správce zařízení instanci.

Do funkce přidejte následující kód InitCallAgentAndDeviceManagerAsync .

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

Zahájení hovoru s videem

Přidejte implementaci k CallButton_Click zahájení hovoru s videem. Potřebujeme vytvořit výčet fotoaparátů s instancí správce zařízení a konstruktorem LocalOutgoingVideoStream. Potřebujeme nastavit a VideoOptions LocalVideoStream předat ho startCallOptions , abychom nastavili počáteční možnosti volání. Když se připojíte LocalOutgoingVideoStream k objektu MediaElement, uvidíme náhled místního videa.

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

Přidejte metody pro zahájení nebo připojení k různým typům volání (1:1 volání služeb Azure Communication Services, telefonní hovor 1:1, skupinový hovor služby Azure Communication Services, připojení ke schůzce Teams atd.).

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

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

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

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

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

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

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

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

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

Přidejte kód pro vytvoření LocalVideoStream v závislosti na vybrané kameře v CameraList_SelectionChanged metodě.

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

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

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

Přijetí příchozího hovoru

Přidejte implementaci do OnIncomingCallAsync příchozího hovoru s videem, předejte ho LocalVideoStream .acceptCallOptions

var incomingCall = args.IncomingCall;

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

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Vzdálený účastník a vzdálené video streamy

Všichni vzdálení účastníci jsou k dispozici prostřednictvím RemoteParticipants kolekce v instanci volání. Jakmile se hovor připojí (CallState.Connected), můžeme přistupovat ke vzdáleným účastníkům hovoru a zpracovávat vzdálené streamy videa.

Poznámka:

Když se uživatel připojí k hovoru, bude mít přístup k aktuálním vzdáleným účastníkům prostřednictvím RemoteParticipants kolekce. Událost RemoteParticipantsUpdated se pro tyto stávající účastníky neaktivuje. Tato událost se aktivuje jenom v případě, že se vzdálený účastník připojí nebo opustí hovor, když je uživatel již v hovoru.


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

}

Vykreslení vzdálených videí

Pro každý vzdálený video stream, připojte ho MediaElementk .

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

Aktualizace stavu volání

Jakmile se hovor odpojí, musíme vykreslovat vykreslovací moduly videa a zpracovat případ, když se vzdálení účastníci poprvé připojí k hovoru.

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

Ukončení hovoru

Ukončení aktuálního hovoru po kliknutí na Hang Up tlačítko Přidejte implementaci do HangupButton_Click pro ukončení volání pomocí callAgent, který jsme vytvořili, a odbourejte obslužné rutiny událostí stavu volání a aktualizace účastníka.

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

Spuštění kódu

Kód můžete sestavit a spustit v sadě Visual Studio. Pro platformy řešení podporujeme ARM64x64 a x86.

Odchozí videohovor můžete provést tak, že do textového pole zadáte ID uživatele a kliknete na Start Call tlačítko.

Poznámka: Volání 8:echo123 zastaví stream videa, protože robot echo nepodporuje streamování videa.

Další informace o ID uživatele (identitě) najdete v průvodci přístupové tokeny uživatele.

Vzorový kód WinUI 3

Požadavky

Pro absolvování tohoto kurzu musí být splněné následující požadavky:

Nastavení

Vytvoření projektu

V sadě Visual Studio vytvořte nový projekt pomocí šablony Prázdná aplikace zabalená (WinUI 3 v desktopové verzi) pro nastavení jednostráňové aplikace WinUI 3.

Snímek obrazovky s oknem Nový projekt WinUI v sadě Visual Studio

Nainstalujte balíček .

Klikněte pravým tlačítkem na projekt a přejděte na Manage Nuget Packages instalaci Azure.Communication.Calling.WindowsClient verze 1.0.0 nebo vyšší verze. Ujistěte se, že je zaškrtnuté políčko Zahrnout předběžné verze.

Vyžádat si přístup

Snímek obrazovky s žádostí o přístup k internetu a mikrofonu v sadě Visual Studio

Do svého počítače app.manifestpřidejte následující kód:

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

Nastavení architektury aplikace

Potřebujeme nakonfigurovat základní rozložení pro připojení naší logiky. Abychom mohli umístit odchozí hovor, musíme TextBox zadat ID uživatele volaného. Potřebujeme Start Call také tlačítko a Hang Up tlačítko. Potřebujeme také zobrazit náhled místního videa a vykreslit vzdálené video druhého účastníka. Potřebujeme tedy dva prvky k zobrazení streamů videa.

MainWindow.xaml Otevřete projekt a nahraďte obsah následující implementací.

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

Otevřete ( App.xaml.cs klikněte pravým tlačítkem myši a zvolte Zobrazit kód) a přidejte tento řádek do horní části:

using CallingQuickstart;

MainWindow.xaml.cs Otevřete (klikněte pravým tlačítkem myši a zvolte Zobrazit kód) a nahraďte obsah následující implementací:

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

Objektový model

Následující třídy a rozhraní zpracovávají některé z hlavních funkcí sady SDK pro volání služeb Azure Communication Services:

Název Popis
CallClient Jedná se CallClient o hlavní vstupní bod do klientské knihovny volání.
CallAgent Slouží CallAgent ke spuštění a připojení k voláním.
CommunicationCall Slouží CommunicationCall ke správě umístěných nebo připojených hovorů.
CallTokenCredential Slouží CallTokenCredential jako přihlašovací údaje tokenu k vytvoření instance CallAgent.
CommunicationUserIdentifier Slouží CommunicationUserIdentifier k reprezentaci identity uživatele, což může být jedna z následujících možností: CommunicationUserIdentifiernebo PhoneNumberIdentifier CallingApplication.

Ověření klienta

K inicializaci CallAgentpotřebujete přístupový token uživatele. Obecně platí, že tento token se generuje ze služby s ověřováním specifickým pro aplikaci. Další informace o přístupových tokenech uživatelů najdete v průvodci uživatelskými přístupovými tokeny .

V tomto rychlém startu nahraďte <AUTHENTICATION_TOKEN> přístupovým tokenem uživatele vygenerovaným pro prostředek služby Azure Communication Service.

Jakmile s ní inicializujete CallAgent token, který nám umožní provádět a přijímat volání. Abychom měli přístup k fotoaparátům na zařízení, musíme také získat Správce zařízení instanci.

Do funkce přidejte následující kód InitCallAgentAndDeviceManagerAsync .

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;

Zahájení hovoru s videem

Přidejte implementaci k CallButton_Click zahájení hovoru s videem. Potřebujeme vytvořit výčet fotoaparátů s instancí správce zařízení a konstruktorem LocalVideoStream. Potřebujeme nastavit a VideoOptions LocalVideoStream předat ho startCallOptions , abychom nastavili počáteční možnosti volání. Když se připojíte LocalVideoStream k objektu MediaPlayerElement, uvidíme náhled místního videa.

var startCallOptions = new StartCallOptions();

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

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

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

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

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

Přijetí příchozího hovoru

Přidejte implementaci do Agent_OnIncomingCallAsync příchozího hovoru s videem, předejte ho LocalVideoStream .acceptCallOptions

var acceptCallOptions = new AcceptCallOptions();

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

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

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

call = await incomingCall.AcceptAsync(acceptCallOptions);

Vzdálený účastník a vzdálené video streamy

Všichni vzdálení účastníci jsou k dispozici prostřednictvím RemoteParticipants kolekce v instanci volání. Jakmile je hovor připojený, můžeme získat přístup ke vzdáleným účastníkům hovoru a zpracovat vzdálené streamy videa.

Poznámka:

Když se uživatel připojí k hovoru, bude mít přístup k aktuálním vzdáleným účastníkům prostřednictvím RemoteParticipants kolekce. Událost OnRemoteParticipantsUpdated se pro tyto stávající účastníky neaktivuje. Tato událost se aktivuje jenom v případě, že se vzdálený účastník připojí nebo opustí hovor, když je uživatel již v hovoru.

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

Vykreslení vzdálených videí

Pro každý vzdálený video stream, připojte ho MediaPlayerElementk .

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

Aktualizace stavu volání

Jakmile se hovor odpojí, musíme vykreslovat vykreslovací moduly videa a zpracovat případ, když se vzdálení účastníci poprvé připojí k hovoru.

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

Ukončení hovoru

Ukončení aktuálního hovoru po kliknutí na Hang Up tlačítko Přidejte implementaci do HangupButton_Click pro ukončení volání pomocí callAgent, který jsme vytvořili, a odbourejte obslužné rutiny událostí stavu volání a aktualizace účastníka.

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

Spuštění kódu

Kód můžete sestavit a spustit v sadě Visual Studio. Pro platformy řešení podporujeme ARM64x64 a x86.

Odchozí videohovor můžete provést tak, že do textového pole zadáte ID uživatele a kliknete na Start Call tlačítko.

Poznámka: Volání 8:echo123 zastaví stream videa, protože robot echo nepodporuje streamování videa.

Další informace o ID uživatele (identitě) najdete v průvodci přístupové tokeny uživatele.