Introduzione all'esempio hero chiamante

L'esempio Servizi di comunicazione di Azure Group Calling Hero illustra come usare Communication Services Calling Web SDK per creare un'esperienza di chiamata a un gruppo.

In questa guida introduttiva di esempio si apprenderà come funziona l'esempio prima di eseguire l'esempio nel computer locale e quindi distribuire l'esempio in Azure usando le proprie risorse Servizi di comunicazione di Azure.

Scaricare il codice

Trovare il progetto per questo esempio in GitHub. Una versione dell'esempio che include le funzionalità attualmente in anteprima pubblica, ad esempio Interoperabilità di Teams e Registrazione delle chiamate, è disponibile in un ramo separato.

Distribuzione in Azure

Panoramica

L'esempio include sia un'applicazione lato client che un'applicazione lato server. L'applicazione lato client è un'applicazione Web React/Redux che usa il framework Fluent UI di Microsoft. Questa applicazione invia richieste a un'applicazione lato server ASP.NET Core tramite la quale l'applicazione lato client si connette ad Azure.

L'esempio ha l'aspetto seguente:

Screenshot che mostra la pagina di destinazione dell'applicazione di esempio.

Quando si preme il pulsante "Start a call" (Avvia una chiamata), l'applicazione Web recupera un token di accesso utente dall'applicazione lato server. Questo token viene quindi usato per connettere l'app client a Servizi di comunicazione di Azure. Una volta recuperato il token, viene richiesto di specificare la fotocamera e il microfono da usare. È possibile disabilitare/abilitare i dispositivi con l'interruttore:

Screenshot che mostra la schermata di pre-chiamata dell'applicazione di esempio.

Dopo aver configurato il nome visualizzato e i dispositivi, è possibile partecipare alla sessione di chiamata. Verrà visualizzato l'area di disegno delle chiamate principale in cui si trova l'esperienza di chiamata principale.

Screenshot che mostra la schermata principale dell'applicazione di esempio.

Componenti della schermata principale della chiamata:

  • Media Gallery: la fase principale in cui vengono visualizzati i partecipanti. Se un partecipante ha la fotocamera abilitata, il suo feed video viene visualizzato qui. A ogni partecipante è associato un singolo riquadro che mostra il nome visualizzato e il flusso video (se presente)
  • Intestazione: qui si trovano i controlli delle chiamate primari per attivare/disattivare le impostazioni e la barra laterale del partecipante, attivare/disattivare il video, condividere lo schermo e lasciare la chiamata.
  • Barra laterale: qui vengono visualizzate le informazioni sui partecipanti e sulle impostazioni quando vengono attivati o disattivati usando i controlli nell'intestazione. Il componente può essere rimosso usando la 'X' nell'angolo in alto a destra. La barra laterale dei partecipanti mostra un elenco di partecipanti e un collegamento per invitare altri utenti a chattare. La barra laterale delle impostazioni consente di configurare il microfono e la fotocamera.

Di seguito sono disponibili altre informazioni sui prerequisiti e sui passaggi per configurare l'esempio.

Prerequisiti

Prima di eseguire l'esempio per la prima volta

  1. Aprire un'istanza di PowerShell, Terminale Windows, prompt dei comandi o equivalente e passare alla directory in cui clonare l'esempio.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Ottenere dal Connection String portale di Azure o usando l'interfaccia della riga di comando di Azure.

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

    Per altre informazioni sulle stringhe di connessione, vedere Creare risorse di comunicazione di Azure

  3. Dopo aver visualizzato Connection String, aggiungere il stringa di connessione al file samples/Server/appsetting.json. Immettere la stringa di connessione nella variabile: ResourceConnectionString.

  4. Ottenere dal Endpoint string portale di Azure o usando l'interfaccia della riga di comando di Azure.

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

    Per altre informazioni sulle stringhe di endpoint, vedere Creare un'istanza di Risorse di comunicazione di Azure

  5. Dopo aver visualizzato Endpoint String, aggiungere la stringa dell'endpoint al file samples/Server/appsetting.json . Immettere la stringa dell'endpoint nella variabile EndpointUrl

Esecuzione locale

  1. Installare le dipendenze

    npm run setup
    
  2. Avviare l'app chiamante

    npm run start
    

    Verrà aperto un server client sulla porta 3000 che serve i file del sito Web e un server API sulla porta 8080 che esegue funzionalità come token di coniazione per i partecipanti alla chiamata.

Risoluzione dei problemi

  • L'app mostra una schermata "Browser non supportato", ma sono in un browser supportato.

    Se l'app viene servita tramite un nome host diverso da localhost, è necessario gestire il traffico tramite https e non http.

Pubblicare in Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. Usare l'estensione di Azure e distribuire la directory Calling/dist nel servizio app

Pulire le risorse

Se si vuole pulire e rimuovere una sottoscrizione a Servizi di comunicazione, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate. Altre informazioni sulla pulizia delle risorse.

Passaggi successivi

Per altre informazioni, vedere gli articoli seguenti:

Altre letture

  • Esempi: trovare altri esempi ed esempi nella pagina di panoramica degli esempi.
  • Redux: gestione dello stato lato client
  • FluentUI - Libreria dell'interfaccia utente di Microsoft
  • React - Libreria per la compilazione di interfacce utente
  • ASP.NET Core - Framework per la compilazione di applicazioni Web

L'esempio Servizi di comunicazione di Azure Group Calling Hero per iOS illustra come usare Communication Services Calling iOS SDK per creare un'esperienza di chiamata di gruppo che include voce e video. In questa guida introduttiva di esempio si apprenderà come configurare ed eseguire l'esempio. Viene fornita una panoramica dell'esempio per il contesto.

Scaricare il codice

Trovare il progetto per questo esempio in GitHub.

Panoramica

L'esempio è un'applicazione iOS nativa che usa gli SDK iOS Servizi di comunicazione di Azure per creare un'esperienza di chiamata che include sia chiamate vocali che videochiamate. L'applicazione usa un componente lato server per effettuare il provisioning dei token di accesso che vengono quindi usati per inizializzare Servizi di comunicazione di Azure SDK. Per configurare questo componente lato server, è possibile seguire l'esercitazione servizio attendibile con Funzioni di Azure.

L'esempio ha l'aspetto seguente:

Screenshot che mostra la pagina di destinazione dell'applicazione di esempio.

Quando si preme il pulsante "Avvia nuova chiamata", l'applicazione iOS richiede di immettere il nome visualizzato da usare per la chiamata.

Screenshot che mostra la schermata di pre-chiamata dell'applicazione di esempio.

Dopo aver toccato "Avanti" nella schermata "Avvia chiamata", è possibile condividere l'ID gruppo della chiamata tramite il foglio di condivisione iOS.

Screenshot che mostra la schermata dell'ID gruppo di condivisione dell'applicazione di esempio.

L'applicazione consente anche di partecipare a una chiamata Servizi di comunicazione di Azure esistente specificando l'ID o l'ID team esistente.

Screenshot che mostra la schermata di chiamata di join dell'applicazione di esempio.

Dopo aver aggiunto una chiamata, verrà richiesto di concedere all'applicazione l'autorizzazione per accedere alla fotocamera e al microfono, se non è già autorizzato. Tieni presente che, come tutte le app basate su AVFoundation, la vera funzionalità audio e video è disponibile solo su hardware reale.

Dopo aver configurato il nome visualizzato e aggiunto alla chiamata, verrà visualizzato l'area di disegno delle chiamate principale in cui si trova l'esperienza di chiamata principale.

Screenshot che mostra la schermata principale dell'applicazione di esempio.

Componenti della schermata principale della chiamata:

  • Media Gallery: la fase principale in cui vengono visualizzati i partecipanti. Se un partecipante ha la fotocamera abilitata, il suo feed video viene visualizzato qui. Ogni partecipante ha un singolo riquadro che mostra il nome visualizzato e il flusso video (quando ne esiste uno). La raccolta supporta più partecipanti e viene aggiornata quando i partecipanti vengono aggiunti o rimossi alla chiamata.
  • Barra delle azioni: è la posizione in cui si trovano i controlli delle chiamate primari. Questi controlli consentono di attivare/disattivare il video e il microfono, condividere lo schermo e lasciare la chiamata.

Di seguito sono disponibili ulteriori informazioni sui prerequisiti e i passaggi da seguire per configurare l'esempio.

Prerequisiti

  • Un account Azure con una sottoscrizione attiva. Per informazioni dettagliate vedere Creare un account gratuito.
  • Un Mac che esegue Xcode, insieme a un certificato dello sviluppatore valido installato nel portachiavi.
  • Risorsa Servizi di comunicazione di Azure. Per informazioni dettagliate, vedere Creare una risorsa Servizi di comunicazione di Azure.
  • Funzione di Azure che esegue l'endpoint di autenticazione per recuperare i token di accesso.

Esecuzione dell'esempio in locale

L'esempio di chiamata di gruppo può essere eseguito in locale usando XCode. Gli sviluppatori possono usare il dispositivo fisico o un emulatore per testare l'applicazione.

Prima di eseguire l'esempio per la prima volta

  1. Installare le dipendenze eseguendo pod install.
  2. Aprire AzureCalling.xcworkspace in XCode.
  3. Creare un file di testo nella radice, chiamato AppSettings.xcconfig e impostare il valore:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Eseguire l'esempio

Compilare ed eseguire l'esempio in XCode usando la destinazione AzureCalling nel simulatore o nel dispositivo preferito.

(Facoltativo) Protezione di un endpoint di autenticazione

A scopo dimostrativo, questo esempio usa un endpoint accessibile pubblicamente per impostazione predefinita per recuperare un token di accesso Servizi di comunicazione di Azure. Per gli scenari di produzione, è consigliabile usare il proprio endpoint protetto per effettuare il provisioning di token personalizzati.

Con una configurazione aggiuntiva, questo esempio supporta la connessione a un endpoint protetto microsoft Entra ID (Microsoft Entra ID) in modo che l'account di accesso dell'utente sia necessario affinché l'app recuperi un token di accesso Servizi di comunicazione di Azure. Vedere i passaggi seguenti:

  1. Abilitare l'autenticazione Di Microsoft Entra nell'app.
  2. Passare alla pagina di panoramica dell'app registrata in Registrazioni app Microsoft Entra. Prendere nota di Application (client) ID, , Directory (tenant) IDApplication ID URI

Configurazione di Microsoft Entra in portale di Azure.

  1. Creare un AppSettings.xcconfig file nella radice, se non è già presente e aggiungere i valori:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Pulire le risorse

Se si vuole pulire e rimuovere una sottoscrizione a Servizi di comunicazione, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate. Altre informazioni sulla pulizia delle risorse.

Passaggi successivi

Per altre informazioni, vedere gli articoli seguenti:

Altre letture

L'esempio Servizi di comunicazione di Azure Group Calling Hero per Android illustra come usare Communication Services Calling Android SDK per creare un'esperienza di chiamata di gruppo che include voce e video. In questa guida introduttiva di esempio si apprenderà come configurare ed eseguire l'esempio. Viene fornita una panoramica dell'esempio per il contesto.

Scaricare il codice

Trovare il progetto per questo esempio in GitHub.

Panoramica

L'esempio è un'applicazione Android nativa che usa la libreria client dell'interfaccia utente Android Servizi di comunicazione di Azure per creare un'esperienza di chiamata che include sia chiamate vocali che videochiamate. L'applicazione usa un componente lato server per effettuare il provisioning dei token di accesso che vengono quindi usati per inizializzare Servizi di comunicazione di Azure SDK. Per configurare questo componente lato server, è possibile seguire l'esercitazione servizio attendibile con Funzioni di Azure.

L'esempio ha l'aspetto seguente:

Screenshot che mostra la pagina di destinazione dell'applicazione di esempio.

Quando si preme il pulsante "Avvia nuova chiamata", l'applicazione Android richiede di immettere il nome visualizzato da usare per la chiamata.

Screenshot che mostra la schermata di pre-chiamata dell'applicazione di esempio.

Dopo aver toccato "Avanti" nella pagina "Avvia una chiamata", è possibile condividere l'ID chiamata di gruppo.

Screenshot che mostra la schermata share Group Call ID dell'applicazione di esempio.

L'applicazione consente di partecipare a una chiamata Servizi di comunicazione di Azure esistente specificando l'ID della chiamata esistente o l'ID riunione team e il nome visualizzato.

Screenshot che mostra la schermata di chiamata di join dell'applicazione di esempio.

Dopo aver aggiunto una chiamata, verrà richiesto di concedere all'applicazione l'autorizzazione per accedere alla fotocamera e al microfono, se non è già autorizzato. Verrà visualizzato l'area di disegno delle chiamate principale in cui si trova l'esperienza di chiamata principale.

Screenshot che mostra la schermata principale dell'applicazione di esempio.

Componenti della schermata principale della chiamata:

  • Media Gallery: la fase principale in cui vengono visualizzati i partecipanti. Se un partecipante ha la fotocamera abilitata, il suo feed video viene visualizzato qui. Ogni partecipante ha un singolo riquadro che mostra il nome visualizzato e il flusso video (quando ne esiste uno). La raccolta supporta più partecipanti e viene aggiornata quando i partecipanti vengono aggiunti o rimossi alla chiamata.
  • Barra delle azioni: è la posizione in cui si trovano i controlli delle chiamate primari. Questi controlli consentono di attivare/disattivare il video e il microfono, condividere lo schermo e lasciare la chiamata.

Di seguito sono disponibili ulteriori informazioni sui prerequisiti e i passaggi da seguire per configurare l'esempio.

Prerequisiti

  • Un account Azure con una sottoscrizione attiva. Per informazioni dettagliate vedere Creare un account gratuito.
  • Android Studio in esecuzione nel computer
  • Risorsa Servizi di comunicazione di Azure. Per informazioni dettagliate, vedere Creare una risorsa Servizi di comunicazione di Azure.
  • Funzione di Azure che esegue l'endpoint di autenticazione per recuperare i token di accesso.

Esecuzione dell'esempio in locale

L'esempio di chiamata di gruppo può essere eseguito in locale usando Android Studio. Gli sviluppatori possono usare il dispositivo fisico o un emulatore per testare l'applicazione.

Prima di eseguire l'esempio per la prima volta

  1. Aprire Android Studio e selezionare Open an Existing Project
  2. Aprire la cartella all'interno della AzureCalling versione scaricata per l'esempio.
  3. Espandere app/asset per aggiornare appSettings.properties. Impostare il valore per la chiave communicationTokenFetchUrl come URL per l'endpoint di autenticazione configurato come prerequisito.

Eseguire l'esempio

Compilare ed eseguire l'esempio in Android Studio.

(Facoltativo) Protezione di un endpoint di autenticazione

A scopo dimostrativo, questo esempio usa un endpoint accessibile pubblicamente per impostazione predefinita per recuperare un token Servizi di comunicazione di Azure. Per gli scenari di produzione, è consigliabile usare il proprio endpoint protetto per effettuare il provisioning di token personalizzati.

Con una configurazione aggiuntiva, questo esempio supporta la connessione a un endpoint protetto microsoft Entra ID (Microsoft Entra ID) in modo che l'account di accesso utente sia necessario per l'app per recuperare un token di Servizi di comunicazione di Azure. Vedere i passaggi seguenti:

  1. Abilitare l'autenticazione Di Microsoft Entra nell'app.

  2. Passare alla pagina di panoramica dell'app registrata in Registrazioni app Microsoft Entra. Prendere nota di Package name, Signature hash, MSAL Configutaion.

Configurazione di Microsoft Entra in portale di Azure.

  1. Modificare AzureCalling/app/src/main/res/raw/auth_config_single_account.json e impostare isAADAuthEnabled per abilitare Microsoft Entra ID.

  2. Modificare AndroidManifest.xml e impostare l'hash android:path della firma dell'archivio chiavi. (Facoltativo. Il valore corrente usa l'hash di debug.keystore in bundle. Se viene usato un archivio chiavi diverso, è necessario aggiornarlo.

    <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. Copiare la configurazione di MSAL Android da portale di Azure e incollarla in AzureCalling/app/src/main/res/raw/auth_config_single_account.json. Includere "account_mode": "SINGLE"

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Modificare AzureCalling/app/src/main/res/raw/auth_config_single_account.json e impostare il valore della chiave communicationTokenFetchUrl come URL per l'endpoint di autenticazione sicuro.

  5. Modificare AzureCalling/app/src/main/res/raw/auth_config_single_account.json e impostare il valore per la chiave aadScopes dagli Azure Active DirectoryExpose an API ambiti

  6. Impostare il valore per graphURL in AzureCalling/app/assets/appSettings.properties come endpoint dell'API Graph per recuperare le informazioni utente.

  7. Modificare AzureCalling/app/src/main/assets/appSettings.properties e impostare il valore per la chiave tenant per abilitare l'accesso invisibile all'utente in modo che l'utente non deve essere autenticato nuovamente e di nuovo durante il riavvio dell'applicazione.

Pulire le risorse

Se si vuole pulire e rimuovere una sottoscrizione a Servizi di comunicazione, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate. Altre informazioni sulla pulizia delle risorse.

Passaggi successivi

Per altre informazioni, vedere gli articoli seguenti:

Altre letture

L'esempio Servizi di comunicazione di Azure Group Calling Hero per Windows illustra come usare Servizi di comunicazione che chiamano Windows SDK per creare un'esperienza di chiamata di gruppo che include voce e video. In questo esempio si apprenderà come configurare ed eseguire l'esempio. Viene fornita una panoramica dell'esempio per il contesto.

Questo argomento di avvio rapido illustra come avviare una videochiamata 1:1 usando Servizi di comunicazione di Azure Calling SDK per Windows.

Codice di esempio UWP

Prerequisiti

Per completare questa esercitazione è necessario soddisfare i prerequisiti seguenti:

Configurazione

Creazione del progetto

In Visual Studio creare un nuovo progetto con il modello App vuota (Windows universale) per configurare un'app UWP (Single Page Piattaforma UWP (Universal Windows Platform)).

Screenshot che mostra la finestra Nuovo progetto UWP in Visual Studio.

Installare il pacchetto

Fare clic con il pulsante destro del mouse sul progetto e passare a Manage Nuget Packages per installare Azure.Communication.Calling.WindowsClientla versione 1.2.0-beta.1 o superiore. Verificare che l'opzione Includi Preleased sia selezionata.

Richiedere l'accesso

Passare a Package.appxmanifest e fare clic su Capabilities. Controllare Internet (Client & Server) di ottenere l'accesso in ingresso e in uscita a Internet. Controllare Microphone di accedere al feed audio del microfono. Controllare WebCam di accedere alla fotocamera del dispositivo.

Aggiungere il codice seguente al Package.appxmanifest proprio facendo clic con il pulsante destro del mouse e scegliendo Visualizza codice.

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

Configurare il framework dell'app

È necessario configurare un layout di base per collegare la logica. Per effettuare una chiamata in uscita, è necessario specificare TextBox l'ID utente del chiamato. Abbiamo anche bisogno di un Start Call pulsante e un Hang Up pulsante. È anche necessario visualizzare in anteprima il video locale ed eseguire il rendering del video remoto dell'altro partecipante. Sono quindi necessari due elementi per visualizzare i flussi video.

Aprire il MainPage.xaml del progetto e sostituire il contenuto con l'implementazione seguente.

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

Aprire su App.xaml.cs (fare clic con il pulsante destro del mouse e scegliere Visualizza codice) e aggiungere questa riga all'inizio:

using CallingQuickstart;

Aprire (fare clic con il pulsante destro del MainPage.xaml.cs mouse e scegliere Visualizza codice) e sostituire il contenuto con l'implementazione seguente:

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

Modello a oggetti

Le classi e le interfacce seguenti gestiscono alcune delle principali funzionalità di Servizi di comunicazione di Azure Calling SDK:

Nome Descrizione
CallClient CallClient è il punto di ingresso principale della libreria client chiamante.
CallAgent Viene CallAgent utilizzato per avviare e partecipare alle chiamate.
CommunicationCall L'oggetto CommunicationCall viene utilizzato per gestire le chiamate inserite o unite in join.
CallTokenCredential Viene CallTokenCredential usato come credenziale del token per creare un'istanza di CallAgent.
CommunicationUserIdentifier Viene CommunicationUserIdentifier usato per rappresentare l'identità dell'utente, che può essere una delle opzioni seguenti: CommunicationUserIdentifiero PhoneNumberIdentifierCallingApplication.

Autenticare il client

Per inizializzare un , CallAgentè necessario un token di accesso utente. In genere questo token viene generato da un servizio con autenticazione specifica per l'applicazione. Per altre informazioni sui token di accesso utente, vedere la Guida ai token di accesso utente.

Per la guida di avvio rapido, sostituire <AUTHENTICATION_TOKEN> con un token di accesso utente generato per la risorsa del servizio di comunicazione di Azure.

Dopo aver ottenuto un token, inizializzare un'istanza CallAgent con essa, che consente di effettuare e ricevere chiamate. Per accedere alle fotocamere nel dispositivo, è anche necessario ottenere Gestione dispositivi istanza.

Aggiungere il codice seguente alla InitCallAgentAndDeviceManagerAsync funzione .

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

Avviare una chiamata con il video

Aggiungere l'implementazione a CallButton_Click per avviare una chiamata con il video. È necessario enumerare le fotocamere con l'istanza di Gestione dispositivi e costruire LocalOutgoingVideoStream. È necessario impostare VideoOptions con LocalVideoStream e passarlo con startCallOptions per impostare le opzioni iniziali per la chiamata. LocalOutgoingVideoStream Collegando a un MediaElementoggetto , è possibile visualizzare l'anteprima del video locale.

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

Aggiungere i metodi per avviare o partecipare ai diversi tipi di chiamata (1:1 Servizi di comunicazione di Azure chiamata, 1:1 telefonata, Servizi di comunicazione di Azure chiamata di gruppo, partecipazione alla riunione di Teams e così via).

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

Aggiungere il codice per creare LocalVideoStream a seconda della fotocamera selezionata nel CameraList_SelectionChanged metodo .

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

Accettare una chiamata in ingresso

Aggiungere l'implementazione a per rispondere a OnIncomingCallAsync una chiamata in ingresso con video, passare LocalVideoStream a acceptCallOptions.

var incomingCall = args.IncomingCall;

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

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Partecipanti remoti e flussi video remoti

Tutti i partecipanti remoti sono disponibili tramite la raccolta in un'istanza RemoteParticipants di chiamata. Una volta connessa la chiamata, è possibile accedere ai partecipanti remoti della chiamata e gestire i flussi video remoti.


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

}

Eseguire il rendering di video remoti

Per ogni flusso video remoto, collegarlo all'oggetto 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();
        });
    }
}

Aggiornamento dello stato della chiamata

È necessario pulire i renderer video una volta disconnessa la chiamata e gestire il caso quando i partecipanti remoti partecipano inizialmente alla chiamata.

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

Terminare una chiamata

Terminare la chiamata corrente quando si fa clic sul Hang Up pulsante. Aggiungere l'implementazione al HangupButton_Click per terminare una chiamata con callAgent creato e rimuovere i gestori eventi di chiamata e aggiornamento del partecipante.

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

Eseguire il codice

È possibile compilare ed eseguire il codice in Visual Studio. Per le piattaforme di soluzioni, è supportato ARM64, x64 e x86.

È possibile effettuare una videochiamata in uscita specificando un ID utente nel campo di testo e facendo clic sul Start Call pulsante.

Nota: la chiamata arresta 8:echo123 il flusso video perché echo bot non supporta lo streaming video.

Per altre informazioni sugli ID utente (identità) vedere la guida ai token di accesso utente.

Codice di esempio winUI 3

Prerequisiti

Per completare questa esercitazione è necessario soddisfare i prerequisiti seguenti:

Configurazione

Creazione del progetto

In Visual Studio creare un nuovo progetto con il modello App vuota, In pacchetto (WinUI 3 in Desktop) per configurare un'app WinUI 3 a pagina singola.

Screenshot che mostra la finestra Nuovo progetto WinUI in Visual Studio.

Installare il pacchetto

Fare clic con il pulsante destro del mouse sul progetto e passare a Manage Nuget Packages per installare Azure.Communication.Calling.WindowsClientla versione 1.0.0 o superiore. Verificare che l'opzione Includi Preleased sia selezionata.

Richiedere l'accesso

Screenshot che mostra la richiesta di accesso a Internet e microfono in Visual Studio.

Aggiungere il codice seguente a app.manifest:

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

Configurare il framework dell'app

È necessario configurare un layout di base per collegare la logica. Per effettuare una chiamata in uscita, è necessario specificare TextBox l'ID utente del chiamato. Abbiamo anche bisogno di un Start Call pulsante e un Hang Up pulsante. È anche necessario visualizzare in anteprima il video locale ed eseguire il rendering del video remoto dell'altro partecipante. Sono quindi necessari due elementi per visualizzare i flussi video.

Aprire il MainWindow.xaml del progetto e sostituire il contenuto con l'implementazione seguente.

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

Aprire su App.xaml.cs (fare clic con il pulsante destro del mouse e scegliere Visualizza codice) e aggiungere questa riga all'inizio:

using CallingQuickstart;

Aprire (fare clic con il pulsante destro del MainWindow.xaml.cs mouse e scegliere Visualizza codice) e sostituire il contenuto con l'implementazione seguente:

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

Modello a oggetti

Le classi e le interfacce seguenti gestiscono alcune delle principali funzionalità di Servizi di comunicazione di Azure Calling SDK:

Nome Descrizione
CallClient CallClient è il punto di ingresso principale della libreria client chiamante.
CallAgent Viene CallAgent utilizzato per avviare e partecipare alle chiamate.
CommunicationCall L'oggetto CommunicationCall viene utilizzato per gestire le chiamate inserite o unite in join.
CallTokenCredential Viene CallTokenCredential usato come credenziale del token per creare un'istanza di CallAgent.
CommunicationUserIdentifier Viene CommunicationUserIdentifier usato per rappresentare l'identità dell'utente, che può essere una delle opzioni seguenti: CommunicationUserIdentifiero PhoneNumberIdentifierCallingApplication.

Autenticare il client

Per inizializzare un , CallAgentè necessario un token di accesso utente. In genere questo token viene generato da un servizio con autenticazione specifica per l'applicazione. Per altre informazioni sui token di accesso utente, vedere la Guida ai token di accesso utente.

Per la guida di avvio rapido, sostituire <AUTHENTICATION_TOKEN> con un token di accesso utente generato per la risorsa del servizio di comunicazione di Azure.

Dopo aver inizializzato un CallAgent token con esso, che consente di effettuare e ricevere chiamate. Per accedere alle fotocamere nel dispositivo, è anche necessario ottenere Gestione dispositivi istanza.

Aggiungere il codice seguente alla InitCallAgentAndDeviceManagerAsync funzione .

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;

Avviare una chiamata con il video

Aggiungere l'implementazione a CallButton_Click per avviare una chiamata con il video. È necessario enumerare le fotocamere con l'istanza di Gestione dispositivi e costruire LocalVideoStream. È necessario impostare VideoOptions con LocalVideoStream e passarlo con startCallOptions per impostare le opzioni iniziali per la chiamata. LocalVideoStream Collegando a un MediaPlayerElementoggetto , è possibile visualizzare l'anteprima del video locale.

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;

Accettare una chiamata in ingresso

Aggiungere l'implementazione a per rispondere a Agent_OnIncomingCallAsync una chiamata in ingresso con video, passare LocalVideoStream a 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);

Partecipanti remoti e flussi video remoti

Tutti i partecipanti remoti sono disponibili tramite la raccolta in un'istanza RemoteParticipants di chiamata. Una volta connessa la chiamata, è possibile accedere ai partecipanti remoti della chiamata e gestire i flussi video remoti.

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

Eseguire il rendering di video remoti

Per ogni flusso video remoto, collegarlo all'oggetto 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();
        });
    }
}

Aggiornamento dello stato della chiamata

È necessario pulire i renderer video una volta disconnessa la chiamata e gestire il caso quando i partecipanti remoti partecipano inizialmente alla chiamata.

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

Terminare una chiamata

Terminare la chiamata corrente quando si fa clic sul Hang Up pulsante. Aggiungere l'implementazione al HangupButton_Click per terminare una chiamata con callAgent creato e rimuovere i gestori eventi di chiamata e aggiornamento del partecipante.

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

Eseguire il codice

È possibile compilare ed eseguire il codice in Visual Studio. Per le piattaforme di soluzioni, è supportato ARM64, x64 e x86.

È possibile effettuare una videochiamata in uscita specificando un ID utente nel campo di testo e facendo clic sul Start Call pulsante.

Nota: la chiamata arresta 8:echo123 il flusso video perché echo bot non supporta lo streaming video.

Per altre informazioni sugli ID utente (identità) vedere la guida ai token di accesso utente.