Introduzione all'esempio hero chiamante

L'esempio hero di chiamata di gruppo di Servizi di comunicazione di Azure illustra come usare ll’SDK Web Chiamate di Servizi di comunicazione per creare un'esperienza di chiamata di 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 di 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 chiesto di specificare la fotocamera e il microfono da usare. È possibile disabilitare o abilitare i dispositivi con gli appositi controlli:

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 il canvas principale in cui risiede l'esperienza principale della chiamata.

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: si tratta dell'area in cui si trovano i controlli principali per la chiamata, che consentono di attivare e disattivare le impostazioni e la barra laterale dei partecipanti, attivare e disattivare il video e il microfono, condividere lo schermo e abbandonare la chiamata.
  • Barra laterale: questa barra mostra i partecipanti e le informazioni sulle impostazioni attivate con i controlli dell'intestazione. Il componente può essere rimosso usando la 'X' nell'angolo in alto a destra. La barra laterale dei partecipanti mostra l'elenco dei partecipanti e un collegamento per invitare altri utenti alla chat. La barra laterale delle impostazioni consente di configurare il microfono e la fotocamera.

Di seguito sono disponibili ulteriori informazioni sui prerequisiti e i passaggi da seguire 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 Connection String dal 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 il Connection String, aggiungere la stringa di connessione al file samples/Server/appsetting.json. Immettere la stringa di connessione nella variabile: ResourceConnectionString.

  4. Ottenere Endpoint string dal 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 risorse di Servizi 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 : altri modelli ed esempi sono disponibili 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 hero per chiamate di gruppi per iOS di Servizi di comunicazione di Azure illustra come usare l’SDK di chiamata iOS Servizi di comunicazione 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 di Servizi di comunicazione di Azure per creare un'esperienza di chiamata con funzionalità vocali e videochiamate. L'applicazione usa un componente lato server per effettuare il provisioning dei token di accesso che vengono quindi usati per inizializzare Azure Communication Services SDK. Per configurare questo componente lato server, 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 di Servizi di comunicazione di Azure esistente specificando il collegamento ID o ID team della chiamata esistente.

Screenshot che mostra la schermata di partecipazione alla chiamata 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. Tenere 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 ed essersi aggiunti alla chiamata, verrà visualizzata 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). 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

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 di 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 in modo che sia necessario l'account di accesso utente per l'app per recuperare un token di accesso 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 Application (client) ID, Directory (tenant) ID, Application ID URI

Configurazione di Microsoft Entra nel portale di Azure.

  1. Creare un file AppSettings.xcconfig 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 hero per chiamate di gruppi per Android di Servizi di comunicazione di Azure illustra come usare l’SDK di chiamata Android Servizi di comunicazione 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 di Servizi di comunicazione di Azure per creare un'esperienza di chiamata che include chiamate vocali e videochiamate. L'applicazione usa un componente lato server per effettuare il provisioning dei token di accesso che vengono quindi usati per inizializzare Azure Communication Services SDK. Per configurare questo componente lato server, 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 di Servizi di comunicazione di Azure esistente specificando il collegamento ID o ID riunione team esistente e il nome visualizzato.

Screenshot che mostra la schermata di partecipazione alla chiamata 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 il canvas di chiamata principale in cui risiede l'esperienza principale della chiamata.

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

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 AzureCalling all'interno della 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 di 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 nel 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 android:path su hash 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 dal 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 da ambiti di Azure Active Directory Expose an API

  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 hero per chiamate di gruppi per Windows di Servizi di comunicazione di Azure illustra come usare l’SDK di chiamata Windows Servizi di comunicazione 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.

In questa guida introduttiva si apprenderà come avviare una videochiamata 1:1 usando Azure Communication Services 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 (Universal Windows Platform) a pagina singola.

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.WindowsClient 1.2.0-beta.1 o versione 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) per ottenere l'accesso in ingresso e in uscita a Internet. Controllare Microphone per accedere al feed audio del microfono. Controllare WebCam per accedere alla fotocamera del dispositivo.

Aggiungere il codice seguente al Package.appxmanifest 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 un TextBox per fornire l'ID utente del chiamato. È anche necessario un pulsante Start Call e un pulsante Hang Up. È 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 il MainPage.xaml.cs (fare clic con il pulsante destro del 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à del SDK Chiamate di Servizi di comunicazione di Azure:

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

Autenticare il client

Per inizializzare un CallAgent, è necessario un token di accesso utente. In genere, questo token viene generato da un servizio con l'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 con essa un'istanza di CallAgent, che consente di effettuare e ricevere chiamate. Per accedere alle fotocamere nel dispositivo, è anche necessario ottenere l'istanza di Gestione dispositivi.

Aggiungere il codice seguente alla funzione 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
    }
}

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. Collegando LocalOutgoingVideoStream a un MediaElement, è 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 chiamata di Servizi di comunicazione di Azure, chiamata 1:1, chiamata al gruppo di Servizi di comunicazione di Azure, partecipazione alle riunioni 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 metodo CameraList_SelectionChanged.

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 arrivo

Aggiungere l'implementazione a OnIncomingCallAsync per rispondere a 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 RemoteParticipants in un'istanza 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 pulsante Hang Up. Aggiungere l'implementazione all’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 fornendo un ID utente nel campo di testo e facendo clic sul pulsante Start Call.

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

Per altre informazioni sugli ID utente (identità) vedere la guida 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 la versione Azure.Communication.Calling.WindowsClient1.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 un TextBox per fornire l'ID utente del chiamato. È anche necessario un pulsante Start Call e un pulsante Hang Up. È 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 il MainWindow.xaml.cs (fare clic con il pulsante destro del 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à del SDK Chiamate di Servizi di comunicazione di Azure:

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

Autenticare il client

Per inizializzare un CallAgent, è necessario un token di accesso utente. In genere, questo token viene generato da un servizio con l'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 con essa un'istanza di CallAgent, che consente di effettuare e ricevere chiamate. Per accedere alle fotocamere nel dispositivo, è anche necessario ottenere l'istanza di Gestione dispositivi.

Aggiungere il codice seguente alla funzione 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;

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. Collegando LocalVideoStream a un MediaPlayerElement, è 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 arrivo

Aggiungere l'implementazione a Agent_OnIncomingCallAsync per rispondere a 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 RemoteParticipants in un'istanza di chiamata. Una volta connessa la chiamata, è possibile accedere ai partecipanti remoti della chiamata e gestire i flussi video remoti.

Nota

Quando un utente partecipa a una chiamata, può accedere ai partecipanti remoti correnti tramite la raccolta RemoteParticipants. L'evento OnRemoteParticipantsUpdated non verrà attivato per questi partecipanti esistenti. Questo evento viene attivato solo quando un partecipante remoto partecipa o lascia la chiamata mentre l'utente è già nella chiamata.

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 pulsante Hang Up. Aggiungere l'implementazione all’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 fornendo un ID utente nel campo di testo e facendo clic sul pulsante Start Call.

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

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