Bagikan melalui


Mulai menggunakan sampel hero panggilan

Sampel Group Calling Hero Azure Communication Services menunjukkan cara Communication Services Calling Web SDK dapat digunakan untuk membangun pengalaman panggilan grup.

Dalam Mulai cepat Sampel ini, kita mempelajari cara kerja sampel sebelum kita menjalankan sampel di komputer lokal Anda lalu menyebarkan sampel ke Azure menggunakan sumber daya Azure Communication Services Anda sendiri.

Mengunduh kode

Temukan proyek untuk sampel ini di GitHub. Versi sampel yang menyertakan fitur yang saat ini ada di pratinjau publik seperti Interop Teams dan Rekaman Panggilan dapat ditemukan di cabang terpisah.

Sebarkan ke Azure

Gambaran Umum

Sampel ini memiliki aplikasi sisi klien dan aplikasi sisi server. Aplikasi sisi klien adalah aplikasi web React/Redux yang menggunakan kerangka kerja antarmuka pengguna Fluent Microsoft. Aplikasi ini mengirimkan permintaan ke aplikasi sisi server ASP.NET Core yang membantu aplikasi sisi klien terhubung ke Azure.

Berikut tampilan sampelnya:

Cuplikan layar yang menampilkan halaman arahan dari aplikasi sampel.

Ketika Anda menekan tombol "Mulai panggilan", aplikasi web mengambil token akses pengguna dari aplikasi sisi server. Token ini kemudian digunakan untuk menghubungkan aplikasi klien ke Azure Communication Services. Setelah token diambil, Anda diminta untuk menentukan kamera dan mikrofon yang ingin Anda gunakan. Anda dapat menonaktifkan/mengaktifkan perangkat Anda dengan kontrol pengalih:

Cuplikan layar yang menampilkan layar pra-panggilan dari aplikasi contoh.

Setelah Anda mengonfigurasi nama tampilan dan perangkat, Anda dapat bergabung dengan sesi. Anda akan melihat kanvas panggilan utama tempat pengalaman panggilan inti berada.

Cuplikan layar yang menampilkan layar utama aplikasi contoh.

Komponen layar panggilan utama:

  • Galeri Media: Tempat utama untuk menampilkan peserta. Jika peserta mengaktifkan kameranya, umpan video mereka akan ditampilkan di sini. Setiap peserta memiliki petak individu yang menunjukkan nama tampilan dan aliran video mereka (bila ada)
  • Header: Di sinilah kontrol panggilan utama berada untuk beralih pengaturan dan bilah sisi peserta, menyalakan dan mencampur video, berbagi layar, dan meninggalkan panggilan.
  • Bilah Samping: Di sinilah peserta dan informasi pengaturan ditampilkan saat beralih menggunakan kontrol di header. Komponen dapat dimatikan menggunakan 'X' yang ada di sudut kanan atas. Bilah sisi peserta memperlihatkan daftar peserta dan tautan untuk mengundang lebih banyak pengguna untuk mengobrol. Bilah sisi pengaturan memungkinkan Anda mengonfigurasi pengaturan mikrofon dan kamera.

Di bawah ini Anda dapat menemukan informasi selengkapnya tentang prasyarat dan langkah-langkah untuk menyiapkan sampel.

Prasyarat

Sebelum menjalankan sampel untuk pertama kalinya

  1. Buka instans PowerShell, Terminal Windows, Perintah atau yang setara, dan buka direktori yang ingin Anda kloning sampelnya.

    git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
    
  2. Connection String Dapatkan dari portal Azure atau dengan menggunakan Azure CLI.

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

    Untuk informasi selengkapnya tentang string koneksi, lihat Membuat Sumber Daya Komunikasi Azure

  3. Setelah Anda mendapatkan Connection String, tambahkan string koneksi ke file sampel/Server/appsetting.json. Masukkan string koneksi Anda dalam variabel: ResourceConnectionString.

  4. Endpoint string Dapatkan dari portal Azure atau dengan menggunakan Azure CLI.

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

    Untuk informasi selengkapnya tentang string Titik Akhir, lihat Membuat Sumber Daya Komunikasi Azure

  5. Setelah Anda mendapatkan Endpoint String, tambahkan string titik akhir ke file sampel/Server/appsetting.json . Masukkan string titik akhir Anda dalam variabel EndpointUrl

Eksekusi lokal

  1. Instal dependensi

    npm run setup
    
  2. Memulai aplikasi panggilan

    npm run start
    

    Ini membuka server klien pada port 3000 yang melayani file situs web, dan server api pada port 8080 yang melakukan fungsionalitas seperti menambang token untuk peserta panggilan.

Pemecahan Masalah

  • Aplikasi ini menunjukkan layar "Browser yang tidak didukung" tetapi saya berada di browser yang didukung.

    Jika aplikasi Anda dilayani melalui nama host selain localhost, Anda harus melayani lalu lintas melalui https dan bukan http.

Menerbitkan ke Azure

  1. npm run setup
  2. npm run build
  3. npm run package
  4. Menggunakan ekstensi Azure dan menyebarkan direktori Panggilan/dist ke layanan aplikasi Anda

Membersihkan sumber daya

Jika ingin membersihkan dan menghapus langganan Azure Communication Services, Anda bisa menghapus sumber daya atau grup sumber daya. Menghapus grup sumber daya juga menghapus sumber daya apa pun yang terkait dengannya. Pelajari selengkapnya tentang membersihkan sumber daya.

Langkah berikutnya

Untuk informasi lebih lanjut, baca artikel berikut:

Pembacaan tambahan

  • Sampel - Temukan lebih banyak sampel dan contoh di halaman gambaran umum sampel kami.
  • Redux - Manajemen status sisi klien
  • FluentUI - Pustaka UI yang didukung Microsoft
  • React - Pustaka untuk membangun antarmuka pengguna
  • ASP.NET Core - Kerangka kerja untuk membangun aplikasi web

Azure Communication Services Contoh Group Calling Hero untuk iOS menunjukkan bagaimana Communication Services Calling untuk SDK iOS dapat digunakan untuk membangun pengalaman panggilan grup yang mencakup suara dan video. Dalam sampel panduan mulai cepat ini, Anda akan mempelajari cara menyiapkan dan menjalankan sampel. Ringkasan sampel disediakan untuk konteks.

Mengunduh kode

Temukan proyek untuk sampel ini di GitHub.

Gambaran Umum

Sampelnya adalah aplikasi iOS asli yang menggunakan Azure Communication Services untuk SDK iOS untuk membangun pengalaman panggilan yang menampilkan panggilan suara dan video. Aplikasi menggunakan komponen sisi server untuk melakukan provisi token akses yang kemudian digunakan untuk menginisialisasi Azure Communication Services SDK. Untuk mengonfigurasi komponen sisi server ini, silakan ikuti tutorial Layanan Tepercaya dengan Azure Functions.

Berikut tampilan sampelnya:

Cuplikan layar yang menampilkan halaman arahan dari aplikasi sampel.

Saat Anda menekan tombol "Mulai panggilan baru", aplikasi iOS meminta Anda untuk memasukkan nama tampilan yang akan digunakan untuk panggilan.

Cuplikan layar yang menampilkan layar pra-panggilan dari aplikasi contoh.

Setelah mengetuk "Berikutnya" di layar "Mulai Panggilan", Anda memiliki kesempatan untuk membagikan ID grup panggilan melalui lembar berbagi iOS.

Cuplikan layar memperlihatkan layar ID grup berbagi aplikasi sampel.

Aplikasi ini juga memungkinkan Anda untuk bergabung dengan panggilan Azure Communication Services yang ada dengan menentukan tautan ID panggilan atau ID tim yang ada.

Cuplikan layar memperlihatkan layar panggilan gabungan dari aplikasi sampel.

Setelah bergabung dengan panggilan, Anda akan diminta untuk memberikan izin aplikasi untuk mengakses kamera dan mikrofon Anda, jika belum diotorisasi. Perlu diingat bahwa, seperti semua aplikasi berbasis AVFoundation, fungsionalitas audio dan video sejati hanya tersedia di perangkat keras nyata.

Setelah mengonfigurasi nama tampilan dan bergabung dalam panggilan, Anda akan melihat kanvas panggilan utama tempat pengalaman panggilan inti berada.

Cuplikan layar yang menampilkan layar utama aplikasi contoh.

Komponen layar panggilan utama:

  • Galeri Media: Tempat utama untuk menampilkan peserta. Jika peserta mengaktifkan kameranya, umpan video mereka akan ditampilkan di sini. Setiap peserta memiliki petak individu yang menunjukkan nama tampilan dan aliran video mereka (bila ada). Galeri mendukung banyak peserta dan diperbarui saat peserta ditambahkan atau dihapus ke panggilan.
  • Bilah Tindakan: Di sinilah kontrol panggilan utama berada. Kontrol ini memungkinkan Anda mengaktifkan/menonaktifkan video dan mikrofon, membagikan layar, dan meninggalkan panggilan.

Di bawah ini Anda akan menemukan informasi lebih lanjut tentang prasyarat dan langkah-langkah untuk menyiapkan sampel.

Prasyarat

Menjalankan sampel secara lokal

Sampel panggilan grup dapat dijalankan secara lokal menggunakan XCode. Pengembang dapat menggunakan perangkat fisik mereka atau emulator untuk menguji aplikasi.

Sebelum menjalankan sampel untuk pertama kalinya

  1. Pasang dependensi dengan menjalankan pod install.
  2. Buka AzureCalling.xcworkspace di XCode.
  3. Buat file teks di akar, dipanggil AppSettings.xcconfig dan atur nilainya:
    communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
    

Menjalankan sampel

Buat dan jalankan sampel di XCode, menggunakan target AzureCalling pada simulator atau perangkat pilihan Anda.

(Opsional) Mengamankan titik akhir autentikasi

Untuk tujuan demonstrasi, sampel ini menggunakan titik akhir yang dapat diakses publik secara default untuk mengambil token akses Azure Communication Services. Untuk skenario produksi, sebaiknya gunakan titik akhir aman Anda sendiri untuk melakukan provisi token Anda sendiri.

Dengan konfigurasi tambahan, sampel ini mendukung koneksi ke titik akhir yang dilindungi ID Microsoft Entra (ID Microsoft Entra) sehingga login pengguna diperlukan agar aplikasi mengambil token akses Azure Communication Services. Lihat langkah di bawah ini:

  1. Aktifkan autentikasi Microsoft Entra di aplikasi Anda.
  2. Buka halaman gambaran umum aplikasi terdaftar Anda di bawah Pendaftaran Aplikasi Microsoft Entra. Catat Application (client) ID, Directory (tenant) ID, Application ID URI

Konfigurasi Microsoft Entra pada portal Azure.

  1. Buat AppSettings.xcconfig file di akar jika belum ada dan tambahkan nilai:
    communicationTokenFetchUrl = <Application ID URI, without the https:// component>
    aadClientId = <Application (client) ID>
    aadTenantId = <Directory (tenant) ID>
    

Membersihkan sumber daya

Jika ingin membersihkan dan menghapus langganan Azure Communication Services, Anda bisa menghapus sumber daya atau grup sumber daya. Menghapus grup sumber daya juga menghapus sumber daya apa pun yang terkait dengannya. Pelajari selengkapnya tentang membersihkan sumber daya.

Langkah berikutnya

Untuk informasi lebih lanjut, baca artikel berikut:

Pembacaan tambahan

Sampel Group Calling Hero untuk Android Azure Communication Services menunjukkan bagaimana Communication Services Calling Android SDK dapat digunakan untuk membangun pengalaman panggilan grup yang mencakup suara dan video. Dalam sampel panduan mulai cepat ini, Anda akan mempelajari cara menyiapkan dan menjalankan sampel. Ringkasan sampel disediakan untuk konteks.

Mengunduh kode

Temukan proyek untuk sampel ini di GitHub.

Gambaran Umum

Sampelnya adalah aplikasi Android asli yang menggunakan pustaka klien UI Android Azure Communication Services untuk membangun pengalaman panggilan yang menampilkan panggilan suara dan video. Aplikasi menggunakan komponen sisi server untuk melakukan provisi token akses yang kemudian digunakan untuk menginisialisasi Azure Communication Services SDK. Untuk mengonfigurasi komponen sisi server ini, silakan ikuti tutorial Layanan Tepercaya dengan Azure Functions.

Berikut tampilan sampelnya:

Cuplikan layar yang menampilkan halaman arahan dari aplikasi sampel.

Saat Anda menekan tombol "Mulai panggilan baru", aplikasi Android meminta Anda untuk memasukkan nama tampilan yang akan digunakan untuk panggilan.

Cuplikan layar yang menampilkan layar pra-panggilan dari aplikasi contoh.

Setelah mengetuk "Berikutnya" di halaman "Mulai Panggilan", Anda memiliki kesempatan untuk berbagi "ID Panggilan Grup".

Cuplikan layar memperlihatkan layar BERBAGI ID Panggilan Grup dari aplikasi sampel.

Aplikasi ini memungkinkan Anda untuk bergabung dengan panggilan Azure Communication Services yang ada dengan menentukan tautan ID panggilan atau ID rapat teams yang ada dan nama tampilan.

Cuplikan layar memperlihatkan layar panggilan gabungan dari aplikasi sampel.

Setelah bergabung dengan panggilan, Anda akan diminta untuk memberikan izin aplikasi untuk mengakses kamera dan mikrofon Anda, jika belum diotorisasi. Anda akan melihat kanvas panggilan utama tempat pengalaman panggilan inti berada.

Cuplikan layar yang menampilkan layar utama aplikasi contoh.

Komponen layar panggilan utama:

  • Galeri Media: Tempat utama untuk menampilkan peserta. Jika peserta mengaktifkan kameranya, umpan video mereka akan ditampilkan di sini. Setiap peserta memiliki petak individu yang menunjukkan nama tampilan dan aliran video mereka (bila ada). Galeri mendukung banyak peserta dan diperbarui saat peserta ditambahkan atau dihapus ke panggilan.
  • Bilah Tindakan: Di sinilah kontrol panggilan utama berada. Kontrol ini memungkinkan Anda mengaktifkan/menonaktifkan video dan mikrofon, membagikan layar, dan meninggalkan panggilan.

Di bawah ini Anda akan menemukan informasi lebih lanjut tentang prasyarat dan langkah-langkah untuk menyiapkan sampel.

Prasyarat

Menjalankan sampel secara lokal

Sampel panggilan grup dapat dijalankan secara lokal menggunakan Android Studio. Pengembang dapat menggunakan perangkat fisik mereka atau emulator untuk menguji aplikasi.

Sebelum menjalankan sampel untuk pertama kalinya

  1. Buka Android Studio dan pilih Open an Existing Project
  2. Buka folder AzureCalling di dalam rilis yang diunduh untuk sampel.
  3. Perluas aplikasi/aset untuk memperbarui appSettings.properties. Tetapkan nilai untuk kunci communicationTokenFetchUrl menjadi URL untuk Titik Akhir Autentikasi Anda disiapkan sebagai prasyarat.

Menjalankan sampel

Buat dan jalankan sampel di Android Studio.

(Opsional) Mengamankan titik akhir autentikasi

Untuk tujuan demonstrasi, sampel ini menggunakan titik akhir yang dapat diakses publik secara default untuk mengambil token Azure Communication Services. Untuk skenario produksi, sebaiknya gunakan titik akhir aman Anda sendiri untuk melakukan provisi token Anda sendiri.

Dengan konfigurasi tambahan, sampel ini mendukung koneksi ke titik akhir yang dilindungi ID Microsoft Entra (ID Microsoft Entra) sehingga login pengguna diperlukan agar aplikasi mengambil token Azure Communication Services. Lihat langkah di bawah ini:

  1. Aktifkan autentikasi Microsoft Entra di aplikasi Anda.

  2. Buka halaman gambaran umum aplikasi terdaftar Anda di bawah Pendaftaran Aplikasi Microsoft Entra. Perhatikan Package name, , Signature hashMSAL Configutaion.

Konfigurasi Microsoft Entra pada portal Azure.

  1. Edit AzureCalling/app/src/main/res/raw/auth_config_single_account.json dan atur isAADAuthEnabled untuk mengaktifkan ID Microsoft Entra.

  2. Edit AndroidManifest.xml dan tetapkan android:path ke hash tanda tangan keystore. (Opsional. Nilai saat ini menggunakan hash dari debug.keystore yang dibundel. Jika keystore yang berbeda digunakan, ini harus diperbarui.)

    <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. Salin konfigurasi Android MSAL dari portal Microsoft Azure dan tempelkan ke AzureCalling/app/src/main/res/raw/auth_config_single_account.json. Sertakan "account_mode": "SINGLE"

       {
          "client_id": "",
          "authorization_user_agent": "DEFAULT",
          "redirect_uri": "",
          "account_mode" : "SINGLE",
          "authorities": [
             {
                "type": "AAD",
                "audience": {
                "type": "AzureADMyOrg",
                "tenant_id": ""
                }
             }
          ]
       }
    
  4. Edit AzureCalling/app/src/main/res/raw/auth_config_single_account.json dan tetapkan nilai untuk kunci communicationTokenFetchUrl menjadi URL untuk Titik Akhir Autentikasi Anda.

  5. Edit AzureCalling/app/src/main/res/raw/auth_config_single_account.json dan tetapkan nilai untuk kunci aadScopes dari cakupan Azure Active Directory Expose an API

  6. Tetapkan nilai untuk graphURL masuk AzureCalling/app/assets/appSettings.properties sebagai titik akhir Graph API untuk mengambil informasi pengguna.

  7. Edit AzureCalling/app/src/main/assets/appSettings.properties dan atur nilai untuk kunci tenant untuk mengaktifkan masuk senyap sehingga pengguna tidak perlu diautentikasi lagi dan lagi saat memulai ulang aplikasi.

Membersihkan sumber daya

Jika ingin membersihkan dan menghapus langganan Azure Communication Services, Anda bisa menghapus sumber daya atau grup sumber daya. Menghapus grup sumber daya juga menghapus sumber daya apa pun yang terkait dengannya. Pelajari selengkapnya tentang membersihkan sumber daya.

Langkah berikutnya

Untuk informasi lebih lanjut, baca artikel berikut:

Pembacaan tambahan

Sampel Hero Panggilan Grup Azure Communication Services untuk Windows menunjukkan bagaimana Communication Services Calling Windows SDK dapat digunakan untuk membangun pengalaman panggilan grup yang menyertakan suara dan video. Dalam sampel ini, Anda mempelajari cara menyiapkan dan menjalankan sampel. Ringkasan sampel disediakan untuk konteks.

Dalam mulai cepat ini, Anda mempelajari cara memulai panggilan video 1:1 menggunakan Azure Communication Services Calling SDK untuk Windows.

Kode sampel UWP

Prasyarat

Untuk menyelesaikan tutorial ini, Anda memerlukan prasyarat berikut:

Menyiapkan

Membuat proyek

Di Visual Studio, buat proyek baru dengan templat Blank App (Universal Windows) untuk menyiapkan aplikasi Universal Windows Platform (UWP) satu halaman.

Cuplikan layar memperlihatkan jendela Proyek UWP Baru dalam Visual Studio.

Pasang paket

Klik kanan proyek Anda dan buka Manage Nuget Packages untuk menginstal Azure.Communication.Calling.WindowsClient 1.2.0-beta.1 atau versi unggul. Pastikan Sertakan Yang Telah Dilepas telah dicentang.

Meminta akses

Buka Package.appxmanifest dan klik Capabilities. Periksa Internet (Client & Server) untuk mendapatkan akses masuk dan keluar ke Internet. Periksa Microphone untuk mengakses umpan audio mikrofon. Periksa WebCam untuk mengakses kamera perangkat.

Tambahkan kode berikut ke Package.appxmanifest Anda dengan mengeklik kanan dan memilih Tampilkan Kode.

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

Menyiapkan kerangka kerja aplikasi

Kita perlu mengonfigurasi tata letak dasar untuk melampirkan logika. Untuk melakukan panggilan keluar, kita perlu TextBox memberikan ID Pengguna dari penerima panggilan. Kita juga butuh tombol Start Call dan tombol Hang Up. Kita juga perlu mempratinjau video lokal dan merender video jarak jauh peserta lain. Jadi kita perlu dua elemen untuk menampilkan aliran video.

Buka MainPage.xaml dari proyek Anda dan ganti konten dengan implementasi berikut.

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

Buka ke App.xaml.cs (klik kanan dan pilih Tampilkan Kode) dan tambahkan baris ini ke atas:

using CallingQuickstart;

Buka MainPage.xaml.cs (klik kanan dan pilih Tampilkan Kode) dan ganti konten dengan implementasi berikut:

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

Model objek

Kelas dan antarmuka berikut menghandel beberapa fitur utama Azure Communication Services Calling SDK:

Nama Deskripsi
CallClient CallClient adalah titik masuk utama ke pustaka klien Panggilan.
CallAgent CallAgent digunakan untuk memulai dan menggabungkan panggilan.
CommunicationCall CommunicationCall digunakan untuk mengelola panggilan yang ditempatkan atau digabungkan.
CallTokenCredential CallTokenCredential digunakan sebagai kredensial token untuk membuat instans CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier digunakan untuk mewakili identitas pengguna, yang dapat menjadi salah satu opsi berikut: CommunicationUserIdentifier, PhoneNumberIdentifier atau CallingApplication.

Mengautentikasi klien

Untuk menginisialisasi CallAgent, Anda memerlukan Token Akses Pengguna. Umumnya token ini dihasilkan dari layanan dengan autentikasi khusus untuk aplikasi. Untuk informasi selengkapnya tentang token akses pengguna, periksa panduan Token Akses Pengguna.

Untuk mulai cepat, ganti <AUTHENTICATION_TOKEN> dengan token akses pengguna yang dihasilkan untuk sumber daya Azure Communication Service Anda.

Setelah Anda memiliki token, inisialisasi CallAgent instans dengannya, yang memungkinkan kami untuk melakukan dan menerima panggilan. Untuk mengakses kamera pada perangkat, kita juga perlu mendapatkan instans Device Manager.

Tambahkan kode berikut ke fungsi 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
    }
}

Memulai panggilan dengan video

Tambahkan implementasi ke CallButton_Click untuk memulai panggilan dengan video. Kita perlu menghitung kamera dengan instans manajer perangkat dan membangun LocalOutgoingVideoStream. Kita perlu mengatur VideoOptions dengan LocalVideoStream dan meneruskannya dengan startCallOptions untuk mengatur opsi awal untuk panggilan. Dengan melampirkan LocalOutgoingVideoStream ke MediaElement, kita dapat melihat pratinjau video lokal.

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

Tambahkan metode untuk memulai atau menggabungkan berbagai jenis Panggilan (panggilan Azure Communication Services 1:1, panggilan telepon 1:1, panggilan Grup Azure Communication Services, gabungan rapat Teams, dll.).

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

Tambahkan kode untuk membuat LocalVideoStream tergantung pada kamera yang dipilih pada CameraList_SelectionChanged metode .

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

Menerima panggilan masuk

Tambahkan implementasi ke OnIncomingCallAsync untuk menjawab panggilan masuk dengan video, teruskan LocalVideoStream ke acceptCallOptions.

var incomingCall = args.IncomingCall;

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

_ = await incomingCall.AcceptAsync(acceptCallOptions);

Peserta jarak jauh dan streaming video jarak jauh

Semua peserta jarak jauh tersedia melalui koleksi RemoteParticipants pada instans panggilan. Setelah panggilan tersambung (CallState.Connected), kita dapat mengakses peserta jarak jauh panggilan dan menangani aliran video jarak jauh.

Catatan

Saat pengguna bergabung dalam panggilan, mereka dapat mengakses peserta jarak jauh saat ini melalui RemoteParticipants koleksi. Kejadian RemoteParticipantsUpdated ini tidak akan memicu peserta yang ada ini. Kejadian ini hanya akan memicu ketika peserta jarak jauh bergabung atau meninggalkan panggilan saat pengguna sudah dalam panggilan.


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

}

Merender video jarak jauh

Untuk setiap streaming video jarak jauh, lampirkan ke 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();
        });
    }
}

Pembaruan status panggilan

Kita perlu membersihkan perender video setelah panggilan terputus dan menangani kasus ketika peserta jarak jauh awalnya bergabung dalam panggilan.

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

Mengakhiri panggilan

Akhiri panggilan saat ini ketika tombol Hang Up diklik. Tambahkan implementasi ke HangupButton_Click untuk mengakhiri panggilan dengan callAgent yang kami buat, dan robek pembaruan peserta dan panggil penanganan aktivitas status.

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

Menjalankan kode

Anda dapat membangun dan menjalankan kode di Visual Studio. Untuk platform solusi, kami mendukung ARM64, x64 dan x86.

Anda dapat melakukan panggilan video keluar dengan memberikan ID pengguna di bidang teks dan mengklik tombol Start Call.

Catatan: Panggilan 8:echo123 menghentikan streaming video karena bot echo tidak mendukung streaming video.

Untuk informasi selengkapnya tentang ID (identitas) pengguna lihat panduan Token Akses Pengguna.

Kode sampel WinUI 3

Prasyarat

Untuk menyelesaikan tutorial ini, Anda memerlukan prasyarat berikut:

Menyiapkan

Membuat proyek

Di Visual Studio, buat proyek baru dengan templat Aplikasi Kosong, Dipaketkan (WinUI 3 di Desktop) untuk menyiapkan aplikasi WinUI 3 satu halaman.

Cuplikan layar memperlihatkan jendela Proyek WinUI Baru dalam Visual Studio.

Pasang paket

Klik kanan proyek Anda dan buka Manage Nuget Packages untuk menginstal Azure.Communication.Calling.WindowsClient 1.0.0 atau versi unggul. Pastikan Sertakan Yang Telah Dilepas telah dicentang.

Meminta akses

Cuplikan layar menampilkan permintaan akses ke Internet dan Mikrofon di Visual Studio.

Tambahkan kode berikut ke app.manifest:

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

Menyiapkan kerangka kerja aplikasi

Kita perlu mengonfigurasi tata letak dasar untuk melampirkan logika. Untuk melakukan panggilan keluar, kita perlu TextBox memberikan ID Pengguna dari penerima panggilan. Kita juga butuh tombol Start Call dan tombol Hang Up. Kita juga perlu mempratinjau video lokal dan merender video jarak jauh peserta lain. Jadi kita perlu dua elemen untuk menampilkan aliran video.

Buka MainWindow.xaml dari proyek Anda dan ganti konten dengan implementasi berikut.

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

Buka ke App.xaml.cs (klik kanan dan pilih Tampilkan Kode) dan tambahkan baris ini ke atas:

using CallingQuickstart;

Buka MainWindow.xaml.cs (klik kanan dan pilih Tampilkan Kode) dan ganti konten dengan implementasi berikut:

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

Model objek

Kelas dan antarmuka berikut menghandel beberapa fitur utama Azure Communication Services Calling SDK:

Nama Deskripsi
CallClient CallClient adalah titik masuk utama ke pustaka klien Panggilan.
CallAgent CallAgent digunakan untuk memulai dan menggabungkan panggilan.
CommunicationCall CommunicationCall digunakan untuk mengelola panggilan yang ditempatkan atau digabungkan.
CallTokenCredential CallTokenCredential digunakan sebagai kredensial token untuk membuat instans CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier digunakan untuk mewakili identitas pengguna, yang dapat menjadi salah satu opsi berikut: CommunicationUserIdentifier, PhoneNumberIdentifier atau CallingApplication.

Mengautentikasi klien

Untuk menginisialisasi CallAgent, Anda memerlukan Token Akses Pengguna. Umumnya token ini dihasilkan dari layanan dengan autentikasi khusus untuk aplikasi. Untuk informasi selengkapnya tentang token akses pengguna, periksa panduan Token Akses Pengguna.

Untuk mulai cepat, ganti <AUTHENTICATION_TOKEN> dengan token akses pengguna yang dihasilkan untuk sumber daya Azure Communication Service Anda.

Setelah Anda memiliki token yang menginisialisasi CallAgent instans dengannya, yang memungkinkan kami untuk melakukan dan menerima panggilan. Untuk mengakses kamera pada perangkat, kita juga perlu mendapatkan instans Device Manager.

Tambahkan kode berikut ke fungsi 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;

Memulai panggilan dengan video

Tambahkan implementasi ke CallButton_Click untuk memulai panggilan dengan video. Kita perlu menghitung kamera dengan instans manajer perangkat dan membangun LocalVideoStream. Kita perlu mengatur VideoOptions dengan LocalVideoStream dan meneruskannya dengan startCallOptions untuk mengatur opsi awal untuk panggilan. Dengan melampirkan LocalVideoStream ke MediaPlayerElement, kita dapat melihat pratinjau video lokal.

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;

Menerima panggilan masuk

Tambahkan implementasi ke Agent_OnIncomingCallAsync untuk menjawab panggilan masuk dengan video, teruskan LocalVideoStream ke 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);

Peserta jarak jauh dan streaming video jarak jauh

Semua peserta jarak jauh tersedia melalui koleksi RemoteParticipants pada instans panggilan. Setelah panggilan tersambung, kita dapat mengakses peserta jarak jauh panggilan dan menangani aliran video jarak jauh.

Catatan

Saat pengguna bergabung dalam panggilan, mereka dapat mengakses peserta jarak jauh saat ini melalui RemoteParticipants koleksi. Kejadian OnRemoteParticipantsUpdated ini tidak akan memicu peserta yang ada ini. Kejadian ini hanya akan memicu ketika peserta jarak jauh bergabung atau meninggalkan panggilan saat pengguna sudah dalam panggilan.

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

Merender video jarak jauh

Untuk setiap streaming video jarak jauh, lampirkan ke 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();
        });
    }
}

Pembaruan status panggilan

Kita perlu membersihkan perender video setelah panggilan terputus dan menangani kasus ketika peserta jarak jauh awalnya bergabung dalam panggilan.

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

Mengakhiri panggilan

Akhiri panggilan saat ini ketika tombol Hang Up diklik. Tambahkan implementasi ke HangupButton_Click untuk mengakhiri panggilan dengan callAgent yang kami buat, dan robek pembaruan peserta dan panggil penanganan aktivitas status.

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

Menjalankan kode

Anda dapat membangun dan menjalankan kode di Visual Studio. Untuk platform solusi, kami mendukung ARM64, x64 dan x86.

Anda dapat melakukan panggilan video keluar dengan memberikan ID pengguna di bidang teks dan mengklik tombol Start Call.

Catatan: Panggilan 8:echo123 menghentikan streaming video karena bot echo tidak mendukung streaming video.

Untuk informasi selengkapnya tentang ID (identitas) pengguna lihat panduan Token Akses Pengguna.