Správa videa během hovorů

Zjistěte, jak spravovat videohovory pomocí sady AZURE COMMUNICATION SERVICES SDK. Dozvíte se, jak spravovat příjem a odesílání videa během hovoru.

Požadavky

Instalace sady SDK

Pomocí příkazu npm install nainstalujte Azure Communication Services volání a běžné sady SDK pro JavaScript.

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

Inicializace požadovaných objektů

Instance CallClient se vyžaduje pro většinu operací volání. Pojďme vytvořit novou CallClient instanci. Můžete ho nakonfigurovat pomocí vlastních možností, jako je instance loggeru.

Pokud máte CallClient instanci, můžete instanci CallAgent vytvořit voláním createCallAgent metody na CallClient instanci. Tato metoda asynchronně vrací CallAgent objekt instance.

Metoda createCallAgent používá CommunicationTokenCredential jako argument. Přijímá přístupový token uživatele.

Pro přístup deviceManagerk getDeviceManager instanci můžete použít metodu CallClient .

const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");

// Set the logger's log level
setLogLevel('verbose');

// Redirect log output to wherever desired. To console, file, buffer, REST API, etc...
AzureLogger.log = (...args) => {
    console.log(...args); // Redirect log output to console
};

const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()

Správa zařízení

Abyste mohli začít používat video s voláním, budete potřebovat vědět, jak spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.

V deviceManagernástroji můžete vytvořit výčet místních zařízení, která můžou přenášet vaše zvukové a video streamy v hovoru. Můžete ho také použít k vyžádání oprávnění pro přístup k mikrofonům a kamerám místního zařízení.

Přístup můžete deviceManager získat voláním callClient.getDeviceManager() metody:

const deviceManager = await callClient.getDeviceManager();

Získání místních zařízení

Pro přístup k místním zařízením můžete použít metody výčtu na .deviceManager Výčet je asynchronní akce.

//  Get a list of available video devices for use.
const localCameras = await deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]

// Get a list of available microphone devices for use.
const localMicrophones = await deviceManager.getMicrophones(); // [AudioDeviceInfo, AudioDeviceInfo...]

// Get a list of available speaker devices for use.
const localSpeakers = await deviceManager.getSpeakers(); // [AudioDeviceInfo, AudioDeviceInfo...]

Nastavení výchozího mikrofonu a reproduktoru

V deviceManagernástroji můžete nastavit výchozí zařízení, které použijete k zahájení hovoru. Pokud nejsou nastavené výchozí hodnoty klienta, komunikační služby používají výchozí hodnoty operačního systému.

// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;

// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);

// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;

// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);

Náhled místní kamery

Pomocí a deviceManagerVideoStreamRenderer můžete začít vykreslovat streamy z místní kamery. Tento stream se nebude odesílat ostatním účastníkům. je to místní informační kanál Preview.

const cameras = await deviceManager.getCameras();
const camera = cameras[0];
const localVideoStream = new LocalVideoStream(camera);
const videoStreamRenderer = new VideoStreamRenderer(localVideoStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);

Žádost o oprávnění ke kameře a mikrofonu

Vyzvat uživatele, aby udělil oprávnění ke kameře nebo mikrofonu:

const result = await deviceManager.askDevicePermission({audio: true, video: true});

Tento problém se vyřeší pomocí objektu, který označuje, jestli audio byla udělena oprávnění a video :

console.log(result.audio);
console.log(result.video);

Poznámky

  • Událost videoDevicesUpdated se aktivuje, když jsou videozařízení připojená nebo odpojená.
  • Událost audioDevicesUpdated se aktivuje, když jsou připojená zvuková zařízení.
  • Při vytvoření Správce zařízení zpočátku neví o žádném zařízení, pokud ještě nebyla udělena oprávnění, a proto je jeho seznam zařízení zpočátku prázdný. Pokud pak zavoláme rozhraní API DeviceManager.askPermission(), zobrazí se uživateli výzva k přístupu k zařízení. Pokud uživatel klikne na povolit a udělí přístup, správce zařízení se dozví o zařízeních v systému, aktualizuje jeho seznamy zařízení a vygeneruje události audioDevicesUpdated a videoDevicesUpdated. Řekněme, že pak aktualizujeme stránku a vytvoříme správce zařízení. Správce zařízení bude moct získat informace o zařízeních, protože uživatel už dříve udělil přístup, a proto bude mít zpočátku vyplněné seznamy zařízení a nebude generovat události audioDevicesUpdated ani videoDevicesUpdated.
  • Výčet a výběr mluvčího není podporován v prohlížeči Android Chrome, iOS Safari ani macOS Safari.

Volání pomocí videokamery

Důležité

V současné době je podporován pouze jeden odchozí místní stream videa.

Pokud chcete uskutečnit videohovor, musíte vytvořit výčet místních kamer pomocí getCameras() metody v deviceManager.

Po výběru kamery ji použijte k vytvoření LocalVideoStream instance. Předejte ji uvnitř videoOptions jako položku v rámci localVideoStream pole metodě startCall .

const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
const placeCallOptions = {videoOptions: {localVideoStreams:[localVideoStream]}};
const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const call = callAgent.startCall([userCallee], placeCallOptions);
  • Můžete se také připojit k hovoru s videem pomocí CallAgent.join() rozhraní API a přijímat a volat s videem pomocí Call.Accept() rozhraní API.
  • Když se váš hovor připojí, začne automaticky odesílat stream videa z vybrané kamery druhému účastníkovi.

Spuštění a ukončení odesílání místního videa během hovoru

Pokud chcete spustit video během hovoru, musíte vytvořit výčet fotoaparátů pomocí getCameras metody na objektu deviceManager . Pak vytvořte novou instanci objektu LocalVideoStream s požadovanou kamerou a předejte LocalVideoStream objekt do startVideo metody existujícího objektu volání:

const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);

Po úspěšném zahájení odesílání videa LocalVideoStream se instance přidá do localVideoStreams kolekce v instanci volání.

call.localVideoStreams[0] === localVideoStream;

Pokud chcete zastavit místní video během hovoru, předejte localVideoStream instanci, která je dostupná v kolekci localVideoStreams :

await call.stopVideo(localVideoStream);
// or
await call.stopVideo(call.localVideoStreams[0]);

Když se video odesílá, můžete přepnout na jiné zařízení kamery, a to vyvoláním switchSourcelocalVideoStream na instanci:

const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);

Pokud je zadané videoza zařízení používáno jiným procesem nebo pokud je v systému zakázané:

  • Pokud je vaše video vypnuté a spustíte video pomocí call.startVideo(), tato metoda vyvolá SourceUnavailableError s a cameraStartFiled nastaví se na hodnotu true.
  • Volání localVideoStream.switchSource() metody způsobí, že cameraStartFailed bude nastavena na hodnotu true. Náš průvodce diagnostikou hovorů obsahuje další informace o tom, jak diagnostikovat problémy související s voláním.

Pokud chcete zkontrolovat nebo ověřit, jestli je místní video zapnuté nebo vypnuté, můžete použít rozhraní API isLocalVideoStarted, které vrátí hodnotu true nebo false:

// Check if local video is on or off
call.isLocalVideoStarted;

Pokud chcete naslouchat změnám místního videa, můžete se přihlásit k odběru a odhlásit odběr události isLocalVideoStartedChanged.

// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
    // Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
    // Callback();
});

Spuštění a ukončení sdílení obrazovky během hovoru

Pokud chcete spustit a zastavit sdílení obrazovky během hovoru, můžete použít asynchronní rozhraní API startScreenSharing a zastavitScreenSharing v uvedeném pořadí:

// Start screen sharing
await call.startScreenSharing();

// Stop screen sharing
await call.stopScreenSharing();

Pokud chcete zkontrolovat nebo ověřit, jestli je sdílení obrazovky zapnuté nebo vypnuté, můžete použít rozhraní API isScreenSharingOn, které vrací hodnotu true nebo false:

// Check if screen sharing is on or off
call.isScreenSharingOn;

Pokud chcete naslouchat změnám sdílené složky obrazovky, můžete se přihlásit k odběru a odhlásit odběr události isScreenSharingOnChanged.

// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
    // Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
    // Callback();
});

Vykreslení streamů videa vzdáleného účastníka

Pokud chcete zobrazit seznam streamů videa a streamů sdílení obrazovky vzdálených účastníků, zkontrolujte videoStreams kolekce:

const remoteVideoStream: RemoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType: MediaStreamType = remoteVideoStream.mediaStreamType;

Pokud chcete vykreslit RemoteVideoStream, musíte se přihlásit k odběru isAvailableChanged události. Pokud se isAvailable vlastnost změní na true, vzdálený účastník odesílá datový proud. Jakmile k tomu dojde, vytvořte novou instanci objektu VideoStreamRenderera pak vytvořte novou VideoStreamRendererView instanci pomocí asynchronní createView metody. Pak se můžete připojit view.target k libovolnému prvku uživatelského rozhraní.

Kdykoli se změní dostupnost vzdáleného streamu, můžete se rozhodnout zničit celý VideoStreamRenderer, konkrétní VideoStreamRendererView nebo si je ponechat, ale výsledkem bude zobrazení prázdného rámečku videa.

// Reference to the html's div where we would display a grid of all remote video stream from all participants.
let remoteVideosGallery = document.getElementById('remoteVideosGallery');

subscribeToRemoteVideoStream = async (remoteVideoStream) => {
   let renderer = new VideoStreamRenderer(remoteVideoStream);
    let view;
    let remoteVideoContainer = document.createElement('div');
    remoteVideoContainer.className = 'remote-video-container';

    /**
     * isReceiving API is currently an @beta feature.
     * To use this api please use 'beta' version of Azure Communication Services Calling Web SDK.
     */
    let loadingSpinner = document.createElement('div');
    // See the css example below for styling the loading spinner.
    loadingSpinner.className = 'loading-spinner';
    remoteVideoStream.on('isReceivingChanged', () => {
        try {
            if (remoteVideoStream.isAvailable) {
                const isReceiving = remoteVideoStream.isReceiving;
                const isLoadingSpinnerActive = remoteVideoContainer.contains(loadingSpinner);
                if (!isReceiving && !isLoadingSpinnerActive) {
                    remoteVideoContainer.appendChild(loadingSpinner);
                } else if (isReceiving && isLoadingSpinnerActive) {
                    remoteVideoContainer.removeChild(loadingSpinner);
                }
            }
        } catch (e) {
            console.error(e);
        }
    });

    const createView = async () => {
        // Create a renderer view for the remote video stream.
        view = await renderer.createView();
        // Attach the renderer view to the UI.
        remoteVideoContainer.appendChild(view.target);
        remoteVideosGallery.appendChild(remoteVideoContainer);
    }

    // Remote participant has switched video on/off
    remoteVideoStream.on('isAvailableChanged', async () => {
        try {
            if (remoteVideoStream.isAvailable) {
                await createView();
            } else {
                view.dispose();
                remoteVideosGallery.removeChild(remoteVideoContainer);
            }
        } catch (e) {
            console.error(e);
        }
    });

    // Remote participant has video on initially.
    if (remoteVideoStream.isAvailable) {
        try {
            await createView();
        } catch (e) {
            console.error(e);
        }
    }
    
    console.log(`Initial stream size: height: ${remoteVideoStream.size.height}, width: ${remoteVideoStream.size.width}`);
    remoteVideoStream.on('sizeChanged', () => {
        console.log(`Remote video stream size changed: new height: ${remoteVideoStream.size.height}, new width: ${remoteVideoStream.size.width}`);
    });
}

Šablony stylů CSS pro styling načítacího spinneru přes vzdálený stream videa

.remote-video-container {
   position: relative;
}
.loading-spinner {
   border: 12px solid #f3f3f3;
   border-radius: 50%;
   border-top: 12px solid #ca5010;
   width: 100px;
   height: 100px;
   -webkit-animation: spin 2s linear infinite; /* Safari */
   animation: spin 2s linear infinite;
   position: absolute;
   margin: auto;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
   transform: translate(-50%, -50%);
}
@keyframes spin {
   0% { transform: rotate(0deg); }
   100% { transform: rotate(360deg); }
}
/* Safari */
@-webkit-keyframes spin {
   0% { -webkit-transform: rotate(0deg); }
   100% { -webkit-transform: rotate(360deg); }
}

Vlastnosti vzdáleného streamu videa

Vzdálené video streamy mají následující vlastnosti:

  • id: ID vzdáleného streamu videa.
const id: number = remoteVideoStream.id;
  • mediaStreamType: Může být Video nebo ScreenSharing.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
  • isAvailable: Určuje, jestli koncový bod vzdáleného účastníka aktivně odesílá datový proud.
const isAvailable: boolean = remoteVideoStream.isAvailable;
  • isReceiving:

    Poznámka

    Toto rozhraní API se poskytuje jako verze Preview pro vývojáře a může se změnit na základě zpětné vazby, kterou dostaneme. Pokud chcete použít toto rozhraní API, použijte verzi 1.5.4-beta.1 nebo novější verze sady Azure Communication Services Calling Web SDK.

    • Informuje aplikaci o tom, jestli jsou nebo nejsou přijímána vzdálená data streamu videa. Mezi tyto scénáře patří:
      • Prohlížím si video vzdáleného účastníka, který je v mobilním prohlížeči. Vzdálený účastník přenese aplikaci mobilního prohlížeče na pozadí. Nyní vidím RemoteVideoStream.isReceiving příznak jde na false a vidím jeho video s černými snímky / zmrazené. Když vzdálený účastník vrátí mobilní prohlížeč zpět do popředí, nyní vidím RemoteVideoStream.isReceiving příznak zpět na true, a vidím, jak se jeho video přehrává normálně.
      • Dívám se na video vzdáleného účastníka, který je na libovolné platformě. Existují problémy se sítí z obou stran, jeho video začíná vypadat docela opožděně, špatná kvalita, probbaly kvůli problémům se sítí, takže vidím RemoteVideoStream.isReceiving příznak jde na false.
      • Dívám se na video vzdáleného účastníka, který je na macOS/iOS Safari a na panelu Adresa klikne na "Pozastavit" / "Pokračovat" kameru. Uvidím černé / zmrazené video, protože pozastavili svou kameru a uvidím, že příznak RemoteVideoStream.isReceiving přejde na false. Jakmile obnoví přehrávání kamery, pak uvidím, že příznak RemoteVideoStream.isReceiving přejde na true.
      • Dívám se na video vzdáleného účastníka, který je na libovolné platformě. A z jakéhokoli důvodu se jejich síť odpojí. To ve skutečnosti opustí vzdáleného účastníka v hovoru na chvíli a já uvidím jeho video zmrazený / černý rámeček, a špatně vidět RemoteVideoStream.isReceiving příznak přejde na false. Vzdálený účastník může získat síť zpět a znovu připojit a jeho zvuk a video by měl začít normálně tok a uvidím remoteVideoStream.isReceiving příznak na true.
      • Prohlížím si video vzdáleného účastníka, který je v mobilním prohlížeči. Vzdálený účastník ukončí nebo ukončí mobilní prohlížeč. Vzhledem k tomu, že vzdálený účastník byl na mobilu, to vlastně zůstane účastník v hovoru na chvíli a já ho stále uvidím v hovoru a jeho video bude zmrazeno, a tak uvidím RemoteVideoStream.isReceiving příznak přejde na false. V určitém okamžiku služba vyhodí účastníka z hovoru a uvidím, že se odpojil od hovoru.
      • Prohlížím si video vzdáleného účastníka, který je v mobilním prohlížeči a uzamkne zařízení. Uvidíte, že příznak RemoteVideoStream.isReceiving přejde na false a. Jakmile vzdálený účastník odemkne zařízení a přejde na volání acs, pak špatně uvidíte, že příznak se vrátí na true. Stejné chování, když je vzdálený účastník na ploše a plocha se zamkne nebo přejde do režimu spánku
    • Tato funkce zlepšuje uživatelské prostředí pro vykreslování vzdálených datových proudů videa.
    • Pokud se příznak isReceiving změní na false, můžete zobrazit číselník načítání přes vzdálený stream videa. Nemusíte dělat číselník načítání, můžete dělat, co chcete, ale načítání číselník je nejběžnější použití pro lepší uživatelské prostředí.
const isReceiving: boolean = remoteVideoStream.isReceiving;
  • size: Velikost datového proudu. Čím větší je velikost streamu, tím lepší je kvalita videa.
const size: StreamSize = remoteVideoStream.size;

Metody a vlastnosti VideoStreamRenderer

VideoStreamRendererView Vytvořte instanci, která se dá připojit v uživatelském rozhraní aplikace k vykreslení vzdáleného streamu videa, pomocí asynchronní createView() metody vyřeší, když je stream připravený k vykreslení, a vrátí objekt s target vlastností, která představuje video prvek, který lze připojit kdekoli ve stromu modelu DOM.

await videoStreamRenderer.createView();

Vyřaďte videoStreamRenderer všechny přidružené VideoStreamRendererView instance:

videoStreamRenderer.dispose();

Metody a vlastnosti VideoStreamRendererView

Při vytváření objektu VideoStreamRendererViewmůžete zadat scalingMode vlastnosti a isMirrored . scalingMode může být Stretch, Cropnebo Fit. Pokud isMirrored je zadána hodnota , vykreslený datový proud se překlopí svisle.

const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });

Každá VideoStreamRendererView instance má target vlastnost, která představuje vykreslovací plochu. Připojte tuto vlastnost v uživatelském rozhraní aplikace:

htmlElement.appendChild(view.target);

Aktualizaci můžete provést scalingMode vyvoláním updateScalingMode metody :

view.updateScalingMode('Crop');

Instalace sady SDK

Vyhledejte soubor build.gradle na úrovni projektu a nezapomeňte ho přidat mavenCentral() do seznamu úložišť v části buildscript a allprojects

buildscript {
    repositories {
    ...
        mavenCentral()
    ...
    }
}
allprojects {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

Potom na úrovni modulu build.gradle přidejte do oddílu dependencies následující řádky.

dependencies {
    ...
    implementation 'com.azure.android:azure-communication-calling:1.0.0'
    ...
}

Inicializace požadovaných objektů

Pokud chcete vytvořit CallAgent instanci, musíte na instanci volat createCallAgent metodu CallClient . To asynchronně vrátí CallAgent objekt instance. Metoda createCallAgent přebírá CommunicationUserCredential jako argument , který zapouzdřuje přístupový token. Pro přístup k objektu DeviceManagermusí být nejprve vytvořena instance callAgent a pak můžete pomocí CallClient.getDeviceManager metody získat DeviceManager.

String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an Activity for instance
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential).get();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();

Pokud chcete nastavit zobrazovaný název volajícího, použijte tuto alternativní metodu:

String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an Activity for instance
CallAgentOptions callAgentOptions = new CallAgentOptions();
callAgentOptions.setDisplayName("Alice Bob");
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential, callAgentOptions).get();

Správa zařízení

Abyste mohli začít používat video s voláním, budete potřebovat vědět, jak spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.

DeviceManager umožňuje vytvořit výčet místních zařízení, která se dají použít při volání k přenosu zvukových proudů a video streamů. Umožňuje také požádat uživatele o oprávnění pro přístup k mikrofonu a kameře pomocí nativního rozhraní API prohlížeče.

Přístup můžete deviceManager získat voláním callClient.getDeviceManager() metody .

Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();

Vytvoření výčtu místních zařízení

Pro přístup k místním zařízením můžete použít metody výčtu na Správce zařízení. Výčet je synchronní akce.

//  Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]

Náhled místní kamery

Pomocí a DeviceManagerRenderer můžete začít vykreslovat streamy z místní kamery. Tento stream nebude odeslán jiným účastníkům. jedná se o místní informační kanál náhledu. Jedná se o asynchronní akci.

VideoDeviceInfo videoDevice = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();

LocalVideoStream currentVideoStream = new LocalVideoStream(videoDevice, appContext);

LocalVideoStream[] localVideoStreams = new LocalVideoStream[1];
localVideoStreams[0] = currentVideoStream;

VideoOptions videoOptions = new VideoOptions(localVideoStreams);

RenderingOptions renderingOptions = new RenderingOptions(ScalingMode.Fit);
VideoStreamRenderer previewRenderer = new VideoStreamRenderer(currentVideoStream, appContext);

VideoStreamRendererView uiView = previewRenderer.createView(renderingOptions);

// Attach the uiView to a viewable location on the app at this point
layout.addView(uiView);

Volání 1:1 s videokamerou

Upozornění

Aktuálně je podporován pouze jeden odchozí místní stream videa: Pokud chcete uskutečnit hovor s videem, musíte pomocí deviceManagergetCameras rozhraní API vytvořit výčet místních fotoaparátů. Jakmile vyberete požadovanou kameru, použijte ji k vytvoření LocalVideoStream instance a předejte ji videoOptions jako položku v localVideoStream poli call metodě. Jakmile se hovor připojí, začne automaticky odesílat video stream z vybrané kamery dalším účastníkům.

Poznámka

Z důvodu ochrany osobních údajů se video nesdílí do hovoru, pokud se jeho náhled nezobrazuje místně. Další podrobnosti najdete v tématu Náhled místní kamery .

VideoDeviceInfo desiredCamera = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();

LocalVideoStream currentVideoStream = new LocalVideoStream(desiredCamera, appContext);

LocalVideoStream[] localVideoStreams = new LocalVideoStream[1];
localVideoStreams[0] = currentVideoStream;

VideoOptions videoOptions = new VideoOptions(localVideoStreams);

// Render a local preview of video so the user knows that their video is being shared
Renderer previewRenderer = new VideoStreamRenderer(currentVideoStream, appContext);
View uiView = previewRenderer.createView(new CreateViewOptions(ScalingMode.FIT));

// Attach the uiView to a viewable location on the app at this point
layout.addView(uiView);

CommunicationUserIdentifier[] participants = new CommunicationUserIdentifier[]{ new CommunicationUserIdentifier("<acs user id>") };

StartCallOptions startCallOptions = new StartCallOptions();
startCallOptions.setVideoOptions(videoOptions);

Call call = callAgent.startCall(context, participants, startCallOptions);

Spuštění a ukončení odesílání místního videa

Pokud chcete spustit video, musíte vytvořit výčet fotoaparátů pomocí getCameraList rozhraní API pro deviceManager objekt. Pak vytvořte novou instanci LocalVideoStream předání požadované kamery a předejte ji v startVideo rozhraní API jako argument:

VideoDeviceInfo desiredCamera = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();

LocalVideoStream currentLocalVideoStream = new LocalVideoStream(desiredCamera, appContext);

VideoOptions videoOptions = new VideoOptions(currentLocalVideoStream);

Future startVideoFuture = call.startVideo(appContext, currentLocalVideoStream);
startVideoFuture.get();

Jakmile úspěšně začnete odesílat video, LocalVideoStream přidá se instance do localVideoStreams kolekce v instanci volání.

List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).

Pokud chcete zastavit místní video, předejte instanci dostupnou LocalVideoStream v localVideoStreams kolekci:

call.stopVideo(appContext, currentLocalVideoStream).get();

Během odesílání videa můžete přepnout na jiné zařízení fotoaparátu vyvoláním switchSourceLocalVideoStream na instanci:

currentLocalVideoStream.switchSource(source).get();

Vykreslení video streamů vzdáleného účastníka

Pokud chcete zobrazit seznam streamů videa a streamů sdílení obrazovky vzdálených účastníků, zkontrolujte videoStreams kolekce:

List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants();
RemoteParticipant remoteParticipant = remoteParticipants.get(0); // Please make sure there are remote participants in the list before calling get(0).

List<RemoteVideoStream> remoteStreams = remoteParticipant.getVideoStreams();
RemoteVideoStream remoteParticipantStream = remoteStreams.get(0); // Please make sure there are video streams in the list before calling get(0).

MediaStreamType streamType = remoteParticipantStream.getType(); // of type MediaStreamType.Video or MediaStreamType.ScreenSharing

Pokud chcete vykreslit RemoteVideoStream událost vzdáleného účastníka, musíte se přihlásit k odběru OnVideoStreamsUpdated události.

Změna isAvailable vlastnosti na true v rámci události značí, že vzdálený účastník právě odesílá datový proud. Jakmile k tomu dojde, vytvořte novou instanci objektu Renderera pak vytvořte novou RendererView pomocí asynchronního createView rozhraní API a připojte view.target ji kdekoli v uživatelském rozhraní vaší aplikace.

Kdykoli se změní dostupnost vzdáleného streamu, můžete se rozhodnout zničit celý renderer, konkrétní RendererView nebo zachovat, ale to bude mít za následek zobrazení prázdného rámečku videa.

VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteParticipantStream, appContext);
VideoStreamRendererView uiView = remoteVideoRenderer.createView(new RenderingOptions(ScalingMode.FIT));
layout.addView(uiView);

remoteParticipant.addOnVideoStreamsUpdatedListener(e -> onRemoteParticipantVideoStreamsUpdated(p, e));

void onRemoteParticipantVideoStreamsUpdated(RemoteParticipant participant, RemoteVideoStreamsEvent args) {
    for(RemoteVideoStream stream : args.getAddedRemoteVideoStreams()) {
        if(stream.getIsAvailable()) {
            startRenderingVideo();
        } else {
            renderer.dispose();
        }
    }
}

Vlastnosti vzdáleného streamu videa

Vzdálený stream videa má několik vlastností.

  • Id - ID vzdáleného video streamu
int id = remoteVideoStream.getId();
  • MediaStreamType - Může to být Video nebo ScreenSharing.
MediaStreamType type = remoteVideoStream.getMediaStreamType();
  • isAvailable – Označuje, jestli koncový bod vzdáleného účastníka aktivně odesílá stream.
boolean availability = remoteVideoStream.isAvailable();

Metody a vlastnosti rendereru

Objekt Rendereru sledující rozhraní API

  • Vytvořte VideoStreamRendererView instanci, kterou můžete později připojit v uživatelském rozhraní aplikace a vykreslit vzdálený stream videa.
// Create a view for a video stream
VideoStreamRendererView.createView()
  • Odstraňte renderer a všechny VideoStreamRendererView přidružené k tomuto vykreslovacímu modulu. Má být volána, pokud jste z uživatelského rozhraní odebrali všechna přidružená zobrazení.
VideoStreamRenderer.dispose()
  • StreamSize - velikost (šířka/výška) vzdáleného video streamu
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();

Metody a vlastnosti RendererView

Při vytváření objektu VideoStreamRendererViewScalingMode můžete zadat vlastnosti a mirrored , které budou platit pro toto zobrazení: Režim měřítka může být | 'FIT'

VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));

Vytvořený objekt RendererView se pak dá připojit k uživatelskému rozhraní aplikace pomocí následujícího fragmentu kódu:

layout.addView(rendererView);

Později můžete režim škálování aktualizovat vyvoláním updateScalingMode rozhraní API u objektu RendererView pomocí některého z | ScalingMode.CROP ScalingMode.FIT jako argument.

// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)

Nastavení systému

Vytvoření projektu Xcode

V Xcode vytvořte nový projekt pro iOS a vyberte šablonu Aplikace s jedním zobrazením . V tomto rychlém startu se používá architektura SwiftUI, takže byste měli nastavit Jazyk na Swift a Uživatelské rozhraní na SwiftUI.

Během tohoto rychlého startu nebudete vytvářet testy jednotek ani testy uživatelského rozhraní. Zrušte zaškrtnutí textových polí Zahrnout testy jednotek a Zahrnout testy uživatelského rozhraní .

Snímek obrazovky znázorňující okno pro vytvoření projektu v Xcode

Instalace balíčku a závislostí pomocí CocoaPods

  1. Vytvořte soubor Podfile pro vaši aplikaci takto:

    platform :ios, '13.0'
    use_frameworks!
    target 'AzureCommunicationCallingSample' do
        pod 'AzureCommunicationCalling', '~> 1.0.0'
    end
    
  2. Spusťte pod install.

  3. Otevřete .xcworkspace pomocí Xcode.

Žádost o přístup k mikrofonu

Pokud chcete získat přístup k mikrofonu zařízení, musíte aktualizovat seznam vlastností informací aplikace pomocí NSMicrophoneUsageDescription. Přidruženou string hodnotu nastavíte na hodnotu, která bude zahrnuta v dialogovém okně, které systém používá k vyžádání přístupu od uživatele.

Klikněte pravým tlačítkem na Info.plist položku stromu projektu a vyberte Otevřít jako>zdrojový kód. Do oddílu nejvyšší úrovně <dict> přidejte následující řádky a pak soubor uložte.

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>

Nastavení architektury aplikace

Otevřete soubor ContentView.swift vašeho projektu a přidejte import do horní části souboru deklaraci pro import AzureCommunicationCalling knihovny. Kromě toho importujte AVFoundation. Budete ho potřebovat pro žádosti o oprávnění ke zvuku v kódu.

import AzureCommunicationCalling
import AVFoundation

Inicializace agenta volání

Chcete-li vytvořit CallAgent instanci z CallClient, musíte použít metodu callClient.createCallAgent , která asynchronně vrací CallAgent objekt po jeho inicializaci.

Pokud chcete vytvořit klienta volání, musíte předat CommunicationTokenCredential objekt.

import AzureCommunication

let tokenString = "token_string"
var userCredential: CommunicationTokenCredential?
do {
    let options = CommunicationTokenRefreshOptions(initialToken: token, refreshProactively: true, tokenRefresher: self.fetchTokenSync)
    userCredential = try CommunicationTokenCredential(withOptions: options)
} catch {
    updates("Couldn't created Credential object", false)
    initializationDispatchGroup!.leave()
    return
}

// tokenProvider needs to be implemented by Contoso, which fetches a new token
public func fetchTokenSync(then onCompletion: TokenRefreshOnCompletion) {
    let newToken = self.tokenProvider!.fetchNewToken()
    onCompletion(newToken, nil)
}

Předejte CommunicationTokenCredential objekt, který jste vytvořili, do CallClienta nastavte zobrazovaný název.

self.callClient = CallClient()
let callAgentOptions = CallAgentOptions()
options.displayName = " iOS Azure Communication Services User"

self.callClient!.createCallAgent(userCredential: userCredential!,
    options: callAgentOptions) { (callAgent, error) in
        if error == nil {
            print("Create agent succeeded")
            self.callAgent = callAgent
        } else {
            print("Create agent failed")
        }
})

Správa zařízení

Abyste mohli začít používat video s voláním, budete potřebovat vědět, jak spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.

DeviceManager umožňuje vytvořit výčet místních zařízení, která se dají použít při volání k přenosu zvukových nebo video streamů. Umožňuje také požádat uživatele o oprávnění pro přístup k mikrofonu nebo kameře. K objektu callClient máte přístupdeviceManager.

self.callClient!.getDeviceManager { (deviceManager, error) in
        if (error == nil) {
            print("Got device manager instance")
            self.deviceManager = deviceManager
        } else {
            print("Failed to get device manager instance")
        }
    }

Výčet místních zařízení

Pro přístup k místním zařízením můžete použít metody výčtu ve správci zařízení. Výčet je synchronní akce.

// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]

Získání náhledu místní kamery

Pomocí příkazu můžete Renderer začít vykreslovat stream z místní kamery. Tento stream se nebude odesílat ostatním účastníkům. je to místní informační kanál Preview. Jedná se o asynchronní akci.

let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()

Získání vlastností náhledu místní kamery

Vykreslovací modul má sadu vlastností a metod, které umožňují řídit vykreslování.

// Constructor can take in LocalVideoStream or RemoteVideoStream
let localRenderer = VideoStreamRenderer(localVideoStream:localVideoStream)
let remoteRenderer = VideoStreamRenderer(remoteVideoStream:remoteVideoStream)

// [StreamSize] size of the rendering view
localRenderer.size

// [VideoStreamRendererDelegate] an object you provide to receive events from this Renderer instance
localRenderer.delegate

// [Synchronous] create view
try! localRenderer.createView()

// [Synchronous] create view with rendering options
try! localRenderer!.createView(withOptions: CreateViewOptions(scalingMode: ScalingMode.fit))

// [Synchronous] dispose rendering view
localRenderer.dispose()

Volání 1:1 s videem

Pokud chcete získat instanci správce zařízení, přečtěte si část o správě zařízení.

let firstCamera = self.deviceManager!.cameras.first
self.localVideoStreams = [LocalVideoStream]()
self.localVideoStreams!.append(LocalVideoStream(camera: firstCamera!))
let videoOptions = VideoOptions(localVideoStreams: self.localVideoStreams!)

let startCallOptions = StartCallOptions()
startCallOptions.videoOptions = videoOptions

let callee = CommunicationUserIdentifier('UserId')
self.callAgent?.startCall(participants: [callee], options: startCallOptions) { (call, error) in
    if error == nil {
        print("Successfully started outgoing video call")
        self.call = call
    } else {
        print("Failed to start outgoing video call")
    }
}

Vykreslení streamů videa vzdáleného účastníka

Vzdálení účastníci můžou během hovoru zahájit sdílení videa nebo obrazovky.

Zpracování streamů sdílení videa nebo obrazovky vzdálených účastníků

Pokud chcete zobrazit seznam datových proudů vzdálených účastníků, zkontrolujte videoStreams kolekce.

var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]

Získání vlastností vzdáleného streamu videa

var type: MediaStreamType = remoteParticipantVideoStream.type // 'MediaStreamTypeVideo'
var isAvailable: Bool = remoteParticipantVideoStream.isAvailable // indicates if remote stream is available
var id: Int = remoteParticipantVideoStream.id // id of remoteParticipantStream

Vykreslování datových proudů vzdálených účastníků

Pokud chcete začít vykreslovat streamy vzdálených účastníků, použijte následující kód.

let renderer = VideoStreamRenderer(remoteVideoStream: remoteParticipantVideoStream)
let targetRemoteParticipantView = renderer?.createView(withOptions: CreateViewOptions(scalingMode: ScalingMode.crop))
// To update the scaling mode later
targetRemoteParticipantView.update(scalingMode: ScalingMode.fit)

Získání metod a vlastností vzdáleného vykreslovače videa

// [Synchronous] dispose() - dispose renderer and all `RendererView` associated with this renderer. To be called when you have removed all associated views from the UI.
remoteVideoRenderer.dispose()

Nastavení

Vytvoření projektu sady Visual Studio

V případě aplikace pro UPW vytvořte v sadě Visual Studio 2019 nový Blank App (Universal Windows) projekt. Po zadání názvu projektu můžete vybrat libovolnou sadu Windows SDK větší než 10.0.17134.

V případě aplikace WinUI 3 vytvořte pomocí šablony nový projekt Blank App, Packaged (WinUI 3 in Desktop) , který nastaví jednostránkovou aplikaci WinUI 3. Windows App SDK verze 1.2 Preview 2 a vyšší je povinná.

Instalace balíčku a závislostí pomocí Správce balíčků NuGet

Rozhraní API a knihovny sady SDK pro volání jsou veřejně dostupné prostřednictvím balíčku NuGet. Následující kroky ilustrují, jak najít, stáhnout a nainstalovat balíček NuGet pro volání sady SDK.

  1. Otevřete Správce balíčků NuGet (Tools ->NuGet Package Manager ->Manage NuGet Packages for Solution)
  2. Klikněte na Browse a zadejte Azure.Communication.Calling do vyhledávacího pole.
  3. Ujistěte se, že Include prerelease je toto políčko zaškrtnuté.
  4. Klikněte na Azure.Communication.Calling balíček a vyberte Azure.Communication.Calling1.0.0-beta.33 nebo novější verzi.
  5. Zaškrtněte políčko odpovídající projektu CS na pravé straně karty.
  6. Klikněte na Install tlačítko.

Žádost o přístup k mikrofonu

Aby aplikace správně fungovala, bude vyžadovat přístup ke kameře. V aplikacích pro UPW by funkce kamery měla být deklarována v souboru manifestu aplikace. Následující kroky ukazují, jak toho dosáhnout.

  1. Na panelu Solution Explorer poklikejte na soubor s .appxmanifest příponou.
  2. Klikněte na Capabilities kartu.
  3. Zaškrtněte Camera políčko v seznamu možností.

Vytvoření tlačítek uživatelského rozhraní pro umístění a zavěsit hovor

Tato jednoduchá ukázková aplikace bude obsahovat dvě tlačítka. Jeden pro odeslání hovoru a druhý pro zavěsit umístěný hovor. Následující kroky ilustrují, jak tato tlačítka přidat do aplikace.

  1. Na panelu Solution Explorer poklikejte na soubor s názvem MainPage.xaml UPW nebo MainWindows.xaml WinUI 3.
  2. Na centrálním panelu vyhledejte kód XAML v náhledu uživatelského rozhraní.
  3. Upravte kód XAML následujícím výňatkem:
<TextBox x:Name="CalleeTextBox" Text="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Row="0" Height="40" Margin="10,10,10,10" />
<StackPanel Orientation="Horizontal">
    <Button x:Name="CallButton" Content="Start Call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="200"/>
    <Button x:Name="HangupButton" Content="Hang Up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="200"/>
</StackPanel>

Nastavení aplikace pomocí rozhraní API sady SDK pro volání

Rozhraní API pro volání sady SDK jsou ve dvou různých oborech názvů. Následující kroky informují kompilátor jazyka C# o těchto oborech názvů, což umožňuje intellisense sady Visual Studio pomáhat s vývojem kódu.

  1. Na panelu Solution Explorer klikněte na šipku na levé straně souboru s názvem MainPage.xaml UPW nebo MainWindows.xaml WinUI 3.
  2. Poklikejte na soubor s názvem MainPage.xaml.cs nebo MainWindows.xaml.cs.
  3. Do dolní části aktuálních using příkazů přidejte následující příkazy.
using Azure.Communication;
using Azure.Communication.Calling;

Ponechejte prosím MainPage.xaml.cs nebo MainWindows.xaml.cs otevřete. V dalších krocích se do něj přidá další kód.

Povolit interakce s aplikacemi

Dříve přidaná tlačítka uživatelského rozhraní musí fungovat nad umístěným Callrozhraním . To znamená, že Call datový člen by měl být přidán do MainPage třídy nebo MainWindow . Kromě toho, aby asynchronní operace vytvoření CallAgent mohla být úspěšná, CallAgent měl by být do stejné třídy přidán také datový člen.

Do třídy nebo MainWindow přidejte následující datové členyMainPage:

CallAgent callAgent;
Call call;

Vytváření obslužných rutin tlačítek

Dříve se do kódu XAML přidala dvě tlačítka uživatelského rozhraní. Následující kód přidá obslužné rutiny, které se mají spustit, když uživatel vybere tlačítko. Následující kód by měl být přidán za datové členy z předchozí části.

private async void CallButton_Click(object sender, RoutedEventArgs e)
{
    // Start call
}

private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
    // End the current call
}

Objektový model

Následující třídy a rozhraní zpracovávají některé z hlavních funkcí klientské knihovny Azure Communication Services Volání pro UPW.

Název Description
CallClient CallClient je hlavním vstupním bodem pro volání klientské knihovny.
CallAgent CallAgent se používá ke spuštění a připojení k hovorům.
Call Volání se používá ke správě umístěných nebo připojených volání.
CommunicationTokenCredential CommunicationTokenCredential se používá jako přihlašovací údaje tokenu k vytvoření instance agenta CallAgent.
CallAgentOptions CallAgentOptions obsahuje informace k identifikaci volajícího.
HangupOptions Funkce HangupOptions informuje, jestli má být hovor ukončen všem účastníkům.

Zaregistrovat obslužnou rutinu videa

Komponenta uživatelského rozhraní, jako je MediaElement XAML nebo MediaPlayerElement, bude vyžadovat, aby aplikace zaregistrovala konfiguraci pro vykreslování místních a vzdálených video kanálů. Přidejte následující obsah mezi Package značky :Package.appxmanifest

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

Inicializace agenta CallAgent

Chcete-li vytvořit CallAgent instanci z CallClient musíte použít CallClient.CreateCallAgent metodu CallAgent , která asynchronně vrací objekt po jeho inicializaci.

Chcete-li vytvořit CallAgent, musíte předat CommunicationTokenCredential objekt a CallAgentOptions objekt. Mějte na paměti, že CommunicationTokenCredential při předání poškozeného tokenu dojde k vyvolání.

Následující kód by měl být přidán do pomocné funkce a měl by se volat při inicializaci aplikace.

var callClient = new CallClient();
this.deviceManager = await callClient.GetDeviceManager();

var tokenCredential = new CommunicationTokenCredential("<AUTHENTICATION_TOKEN>");
var callAgentOptions = new CallAgentOptions()
{
    DisplayName = "<DISPLAY_NAME>"
};

this.callAgent = await callClient.CreateCallAgent(tokenCredential, callAgentOptions);
this.callAgent.OnCallsUpdated += Agent_OnCallsUpdatedAsync;
this.callAgent.OnIncomingCall += Agent_OnIncomingCallAsync;

<AUTHENTICATION_TOKEN> Musí se nahradit platným tokenem přihlašovacích údajů pro váš prostředek. Pokud je potřeba získat token přihlašovacích údajů, projděte si dokumentaci k tokenu přístupu uživatele .

Volání 1:1 pomocí videokamery

Objekty potřebné k vytvoření CallAgent jsou teď připravené. Je čas asynchronně vytvořit CallAgent a uskutečnit videohovor.

Následující kód by měl být přidán po zpracování výjimky z předchozího kroku.

var startCallOptions = new StartCallOptions();

if ((LocalVideo.Source == null) && (this.deviceManager.Cameras?.Count > 0))
{
    var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
    if (videoDeviceInfo != null)
    {
        // <Initialize local camera preview>
        startCallOptions.VideoOptions = new VideoOptions(new[] { localVideoStream });
    }
}

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;

Náhled místní kamery

Volitelně můžeme nastavit náhled místní kamery. Video je možné vykreslit prostřednictvím UPW MediaElement:

<Grid Grid.Row="1">
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <MediaElement x:Name="LocalVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="0" VerticalAlignment="Center"/>
    <MediaElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center"/>
</Grid>

Inicializace místního náhledu MedialElement:

var localVideoStream = new LocalVideoStream(videoDeviceInfo);

var localUri = await localVideoStream.MediaUriAsync();

await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
    LocalVideo.Source = localUri;
    LocalVideo.Play();
});

Nebo ve MediaPlayerElement WinUI 3:

<Grid Grid.Row="1">
    <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"/>
    <MediaPlayerElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center"/>
</Grid>

Inicializace místního náhledu MediaPlayerElement:

var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
if (videoDeviceInfo != null)
{
    var localVideoStream = new LocalVideoStream(videoDeviceInfo);

    var localUri = await localVideoStream.MediaUriAsync();

    this.DispatcherQueue.TryEnqueue(() => {
        LocalVideo.Source = MediaSource.CreateFromUri(localUri);
        LocalVideo.MediaPlayer.Play();
    });
}

Vykreslení vzdáleného streamu kamery

Nastavte obslužnou rutinu sudých v reakci na OnCallsUpdated událost:

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

Spusťte vykreslování vzdáleného streamu MediaElement videa pro aplikaci pro UPW:

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

Nebo můžete vykreslit vzdálený stream MediaPlayerElement videa pro aplikaci Win32 3:

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

Ukončení hovoru

Jakmile je volání umístěné, HangupAsync metoda objektu Call by měla být použita k zavěsit volání.

Instance by HangupOptions také měla být použita k informování o tom, jestli musí být hovor ukončen všem účastníkům.

Do souboru by měl být přidán HangupButton_Clicknásledující kód .

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

Spuštění kódu

Ujistěte se, že Visual Studio sestaví aplikaci pro x64, x86 nebo ARM64a pak stisknutím klávesy F5 spusťte aplikaci. Potom kliknutím na Call tlačítko zavolejte volanou.

Mějte na paměti, že při prvním spuštění aplikace systém vyzve uživatele k udělení přístupu k mikrofonu.

Další kroky