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.
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:
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:
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.
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
- Un account Azure con una sottoscrizione attiva. Per informazioni dettagliate, vedere Creare un account gratuito
- Node.js (12.18.4 e versioni successive)
- Visual Studio Code (build stabile)
- Risorsa di Servizi di comunicazione di Azure. Per informazioni dettagliate vedere Creare una risorsa di comunicazione di servizi di Azure. Per questo avvio rapido è necessario registrare la stringa di connessione della risorsa.
Prima di eseguire l'esempio per la prima volta
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
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
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
.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
Dopo aver visualizzato
Endpoint String
, aggiungere la stringa dell'endpoint al file samples/Server/appsetting.json. Immettere la stringa dell'endpoint nella variabileEndpointUrl
Esecuzione locale
Installare le dipendenze
npm run setup
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
npm run setup
npm run build
npm run package
- 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:
- Acquisire familiarità con usare l'SDK chiamante
- Leggere altre informazioni sul funzionamento delle chiamate
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:
Quando si preme il pulsante "Avvia nuova chiamata", l'applicazione iOS richiede di immettere il nome visualizzato da usare per la chiamata.
Dopo aver toccato "Avanti" nella schermata "Avvia chiamata", è possibile condividere l'ID gruppo della chiamata tramite il foglio di condivisione iOS.
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.
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.
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
- 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 di Servizi di comunicazione di Azure. Per informazioni dettagliate vedere Creare una risorsa di comunicazione di servizi 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
- Installare le dipendenze eseguendo
pod install
. - Aprire
AzureCalling.xcworkspace
in XCode. - 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:
- Abilitare l'autenticazione Di Microsoft Entra nell'app.
- 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
- 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:
- Acquisire familiarità con usare l'SDK chiamante
- Leggere altre informazioni sul funzionamento delle chiamate
Altre letture
- Pagina GitHub dei servizi di comunicazione di Azure - Nella pagina ufficiale di GitHub sono disponibili altri esempi e informazioni
- Esempi : altri modelli ed esempi sono disponibili nella pagina di panoramica degli esempi.
- Funzionalità di chiamata di Azure: per altre informazioni sulla chiamata di iOS SDK -Azure Communication iOS Calling SDK
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:
Quando si preme il pulsante "Avvia nuova chiamata", l'applicazione Android richiede di immettere il nome visualizzato da usare per la chiamata.
Dopo aver toccato "Avanti" nella pagina "Avvia una chiamata", è possibile condividere l'ID chiamata di gruppo.
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.
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.
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
- Un account Azure con una sottoscrizione attiva. Per informazioni dettagliate vedere Creare un account gratuito.
- Android Studio in esecuzione nel computer
- Risorsa di Servizi di comunicazione di Azure. Per informazioni dettagliate vedere Creare una risorsa di comunicazione di servizi 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
- Aprire Android Studio e selezionare
Open an Existing Project
- Aprire la cartella
AzureCalling
all'interno della versione scaricata per l'esempio. - Espandere app/asset per aggiornare
appSettings.properties
. Impostare il valore per la chiavecommunicationTokenFetchUrl
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:
Abilitare l'autenticazione Di Microsoft Entra nell'app.
Passare alla pagina di panoramica dell'app registrata in Registrazioni app Microsoft Entra. Prendere nota di
Package name
,Signature hash
,MSAL Configuration
.
Modificare
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
e impostareisAADAuthEnabled
per abilitare Microsoft Entra ID.Modificare
AndroidManifest.xml
e impostareandroid: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>
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": "" } } ] }
Modificare
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
e impostare il valore della chiavecommunicationTokenFetchUrl
come URL per l'endpoint di autenticazione sicuro.Modificare
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
e impostare il valore per la chiaveaadScopes
da ambiti diAzure Active Directory
Expose an API
Impostare il valore per
graphURL
inAzureCalling/app/assets/appSettings.properties
come endpoint dell'API Graph per recuperare le informazioni utente.Modificare
AzureCalling/app/src/main/assets/appSettings.properties
e impostare il valore per la chiavetenant
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:
- Acquisire familiarità con usare l'SDK chiamante
- Leggere altre informazioni sul funzionamento delle chiamate
Altre letture
- Pagina GitHub dei servizi di comunicazione di Azure - Nella pagina ufficiale di GitHub sono disponibili altri esempi e informazioni
- Esempi : altri modelli ed esempi sono disponibili nella pagina di panoramica degli esempi.
- Funzionalità di chiamata di Azure - Per altre informazioni sulla chiamata di Android SDK-Azure Communication Android Calling SDK
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:
Un account Azure con una sottoscrizione attiva. Creare un account gratuitamente.
Installare Visual Studio 2022 con il carico di lavoro Sviluppo di app per la piattaforma UWP (Universal Windows Platform).
Una risorsa di Servizi di comunicazione distribuita. Creare una risorsa di Servizi di comunicazione. Per questa guida introduttiva è necessario registrare la stringa di connessione.
Un token di accesso utente per il servizio di comunicazione di Azure. È anche possibile usare l'interfaccia della riga di comando di Azure ed eseguire il comando con la stringa di connessione per creare un utente e un token di accesso.
az communication identity token issue --scope voip --connection-string "yourConnectionString"
Per informazioni dettagliate, vedere Usare l'interfaccia della riga di comando di Azure per creare e gestire i token di accesso.
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.
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 GetStartCallOptionsAsync();
var call = await this.callAgent.StartCallAsync( new [] { new UserCallIdentifier(acsCallee) }, options);
return call;
}
private async Task<CommunicationCall> StartPhoneCallAsync(string acsCallee, string alternateCallerId)
{
var options = await GetStartCallOptionsAsync();
options.AlternateCallerId = new PhoneNumberCallIdentifier(alternateCallerId);
var call = await this.callAgent.StartCallAsync( new [] { new PhoneNumberCallIdentifier(acsCallee) }, options);
return call;
}
private async Task<CommunicationCall> JoinGroupCallByIdAsync(Guid groupId)
{
var joinCallOptions = await GetJoinCallOptionsAsync();
var groupCallLocator = new GroupCallLocator(groupId);
var call = await this.callAgent.JoinAsync(groupCallLocator, joinCallOptions);
return call;
}
private async Task<CommunicationCall> JoinTeamsMeetingByLinkAsync(Uri teamsCallLink)
{
var joinCallOptions = await GetJoinCallOptionsAsync();
var teamsMeetingLinkLocator = new TeamsMeetingLinkLocator(teamsCallLink.AbsoluteUri);
var call = await callAgent.JoinAsync(teamsMeetingLinkLocator, joinCallOptions);
return call;
}
private async Task<StartCallOptions> GetStartCallOptionsAsync()
{
return new StartCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true, OutgoingAudioStream = micStream },
OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
};
}
private async Task<JoinCallOptions> GetJoinCallOptionsAsync()
{
return new JoinCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true },
OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
};
}
Aggiungere il codice per creare LocalVideoStream a seconda della fotocamera selezionata nel metodo CameraList_SelectionChanged
.
var selectedCamera = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamera);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
if (call != null)
{
await call?.StartVideoAsync(cameraStream);
}
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. Quando la chiamata diventa connessa (CallState.Connected
), è possibile accedere ai partecipanti remoti alla 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 RemoteParticipantsUpdated
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)
{
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:
Un account Azure con una sottoscrizione attiva. Creare un account gratuitamente.
Installare Visual Studio 2022 e Windows App SDK versione 1.2 preview 2.
Conoscenza di base di come creare un'app WinUI 3. Creare il primo progetto WinUI 3 (Windows App SDK) è una buona risorsa da cui iniziare.
Una risorsa di Servizi di comunicazione distribuita. Creare una risorsa di Servizi di comunicazione. Per questa guida introduttiva è necessario registrare la stringa di connessione.
Un token di accesso utente per il servizio di comunicazione di Azure. È anche possibile usare l'interfaccia della riga di comando di Azure ed eseguire il comando con la stringa di connessione per creare un utente e un token di accesso.
az communication identity token issue --scope voip --connection-string "yourConnectionString"
Per informazioni dettagliate, vedere Usare l'interfaccia della riga di comando di Azure per creare e gestire i token di accesso.
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.
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.WindowsClient
1.0.0 o superiore. Verificare che l'opzione Includi Preleased sia selezionata.
Richiedere l'accesso
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 selectedCamera = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamera);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
startCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { cameraStream });
}
}
var callees = new ICommunicationIdentifier[1]
{
new CommunicationUserIdentifier(CalleeTextBox.Text.Trim())
};
this.call = await this.callAgent.StartCallAsync(callees, startCallOptions);
this.call.OnRemoteParticipantsUpdated += Call_OnRemoteParticipantsUpdatedAsync;
this.call.OnStateChanged += Call_OnStateChangedAsync;
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 selectedCamera = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamera);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
acceptCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { localVideoStream });
}
}
call = await incomingCall.AcceptAsync(acceptCallOptions);
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.