Delen via


Video beheren tijdens gesprekken

Meer informatie over het beheren van videogesprekken met de Azure Communication Services SDKS. We leren hoe u het ontvangen en verzenden van video's binnen een gesprek kunt beheren.

Vereisten

Installeer de SDK

Gebruik de npm install opdracht om de Common and Calling SDK voor Azure Communication Services voor JavaScript te installeren:

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

Vereiste objecten initialiseren

Een CallClient exemplaar is vereist voor de meeste aanroepbewerkingen. Wanneer u een nieuw CallClient exemplaar maakt, kunt u deze configureren met aangepaste opties, zoals een Logger exemplaar.

Met het CallClient exemplaar kunt u een CallAgent exemplaar maken door het createCallAgentaan te roepen. Deze methode retourneert asynchroon een CallAgent exemplaarobject.

De createCallAgent methode gebruikt CommunicationTokenCredential als argument. Het accepteert een toegangstoken van een gebruiker.

U kunt de getDeviceManager methode op het CallClient exemplaar gebruiken om toegang te krijgen tot deviceManager.

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 console, file, buffer, REST API, or whatever location you want
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()

Sdk-connectiviteit met Microsoft-infrastructuur het beste beheren

Het Call Agent exemplaar helpt u bij het beheren van gesprekken (om aanroepen deel te nemen of te starten). Als u wilt werken met uw aanroepende SDK, moet u verbinding maken met de Microsoft-infrastructuur om meldingen van binnenkomende oproepen te ontvangen en andere gespreksgegevens te coördineren. Uw Call Agent heeft twee mogelijke statussen:

Verbonden : een Call Agent connectionStatue-waarde van Connected het middel dat de client-SDK is verbonden en meldingen van de Microsoft-infrastructuur kan ontvangen.

Verbinding verbroken - Een Call Agent connectionStatue-waarde van Disconnected statussen is er een probleem dat verhindert dat de SDK verbinding maakt. Call Agent moet opnieuw worden gemaakt.

  • invalidToken: Als een token is verlopen of een ongeldig exemplaar Call Agent wordt verbroken met deze fout.
  • connectionIssue: Als er een probleem is met de client die verbinding maakt met Microsoft infrascture, wordt de connectionIssue fout na veel nieuwe pogingen Call Agent weergegeven.

U kunt controleren of uw lokale Call Agent verbinding heeft met de Microsoft-infrastructuur door de huidige waarde van connectionState de eigenschap te controleren. Tijdens een actieve oproep kunt u naar de connectionStateChanged gebeurtenis luisteren om te bepalen of Call Agent de status Verbonden naar Verbroken is gewijzigd.

const connectionState = callAgentInstance.connectionState;
console.log(connectionState); // it may return either of 'Connected' | 'Disconnected'

const connectionStateCallback = (args) => {
    console.log(args); // it will return an object with oldState and newState, each of having a value of either of 'Connected' | 'Disconnected'
    // it will also return reason, either of 'invalidToken' | 'connectionIssue'
}
callAgentInstance.on('connectionStateChanged', connectionStateCallback);

Apparaatbeheer

Als u video wilt gaan gebruiken met de Calling SDK, moet u apparaten kunnen beheren. Met apparaten kunt u bepalen wat audio en video naar het gesprek verzendt.

Met de deviceManager, kunt u inventariseren lokale apparaten die uw audio- en videostreams in een gesprek kunnen verzenden. U kunt ook toestemming deviceManager vragen voor toegang tot de microfoons en camera's van het lokale apparaat.

U kunt toegang krijgen deviceManager door de methode aan callClient.getDeviceManager() te roepen:

const deviceManager = await callClient.getDeviceManager();

Lokale apparaten ophalen

Voor toegang tot lokale apparaten kunt u de deviceManager opsommingsmethoden getCameras() en getMicrophones. Deze methoden zijn asynchrone acties.

//  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...]

De standaardapparaten instellen

Zodra u weet welke apparaten beschikbaar zijn voor gebruik, kunt u standaardapparaten instellen voor microfoon, luidspreker en camera. Als de standaardinstellingen van de client niet zijn ingesteld, gebruikt de Communication Services SDK standaardinstellingen voor het besturingssysteem.

Microfoon

Toegang tot het gebruikte apparaat

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

Het apparaat instellen voor gebruik

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

Spreker

Toegang tot het gebruikte apparaat

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

Het apparaat instellen voor gebruik

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

Camera

Toegang tot het gebruikte apparaat

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

Het apparaat instellen voor gebruik

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

Elk CallAgent kan een eigen microfoon en luidsprekers kiezen op de bijbehorende DeviceManager. We raden u aan om verschillende CallAgents microfoons en luidsprekers te gebruiken. Ze mogen niet dezelfde microfoons of luidsprekers delen. Als het delen plaatsvindt, kan diagnostische gegevens van de microfoon worden geactiveerd en werkt de microfoon niet meer, afhankelijk van de browser/het besturingssysteem.

Lokale videostream

Als u video wilt kunnen verzenden in een gesprek, moet u een LocalVideoStreamobject maken.

const localVideoStream = new LocalVideoStream(camera);

De camera die als parameter wordt doorgegeven, is een van het VideoDeviceInfo object dat door de deviceManager.getCameras()methode wordt geretourneerd.

A LocalVideoStream heeft de volgende eigenschappen:

  • source: de apparaatgegevens.
const source = localVideoStream.source;
  • mediaStreamType: kan zijn Video, ScreenSharingof RawMedia.
const type: MediaStreamType = localVideoStream.mediaStreamType;

Voorbeeld van lokale camera

U kunt streams vanaf uw lokale camera gebruiken deviceManager en VideoStreamRenderer weergeven. Zodra een is LocalVideoStream gemaakt, gebruikt u deze om het in te stellenVideoStreamRenderer. Zodra de VideoStreamRenderermethode is gemaakt, wordt de methode aangeroepen createView() om een weergave te krijgen die u als onderliggend element aan uw pagina kunt toevoegen.

Deze stream wordt niet naar andere deelnemers verzonden; het is een lokale preview-feed.

// To start viewing local camera 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);

De lokale preview stoppen

Als u de lokale preview-aanroep wilt stoppen, verwijdert u de weergave die is afgeleid van de VideoStreamRenderer. Nadat de VideoStreamRenderer is verwijderd, verwijdert u de weergave uit de HTML-structuur door de removeChild() methode aan te roepen vanuit het DOM-knooppunt dat uw voorbeeld bevat.

// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);

Toestemming vragen voor camera en microfoon

Een toepassing kan de camera of microfoon niet zonder machtigingen gebruiken. U kunt deviceManager gebruiken om een gebruiker te vragen om camera- en/of microfoonmachtigingen toe te kennen:

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

Zodra de belofte is opgelost, wordt de methode geretourneerd met een DeviceAccess object dat aangeeft of audio en video machtigingen zijn verleend:

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

Opmerkingen

  • videoDevicesUpdated gebeurtenis wordt geactiveerd wanneer videoapparaten zijn aangesloten/losgekoppeld.
  • audioDevicesUpdated gebeurtenis wordt geactiveerd wanneer audioapparaten zijn aangesloten.
  • Wanneer DeviceManager wordt gemaakt, weet het in eerste instantie niet over apparaten als er nog geen machtigingen zijn verleend, dus in eerste instantie is de apparaatnaam leeg en bevat deze geen gedetailleerde apparaatgegevens. Als we de DeviceManager.askPermission() API aanroepen, wordt de gebruiker gevraagd om apparaattoegang. Wanneer de gebruiker de optie Toestaan selecteert om de apparaatbeheerder toegang te verlenen tot de apparaten op het systeem, werkt u de apparaatlijsten bij en verzendt u de gebeurtenissen 'audioDevicesUpdated' en 'videoDevicesUpdated'. Als een gebruiker de pagina vernieuwt en een apparaatbeheerder maakt, kan de apparaatbeheerder meer informatie krijgen over apparaten omdat de gebruiker eerder toegang heeft verleend. Het apparaat bevat in eerste instantie een lijst met apparaten en verzendt geen 'audioDevicesUpdated' of 'videoDevicesUpdated'-gebeurtenissen.
  • Opsomming/selectie van luidsprekers wordt niet ondersteund in Android Chrome, iOS Safari en macOS Safari.

Een gesprek plaatsen met videocamera

Belangrijk

Momenteel wordt slechts één uitgaande lokale videostream ondersteund.

Als u een videogesprek wilt plaatsen, moet u lokale camera's opsommen met behulp van de getCameras() methode in deviceManager.

Nadat u een camera hebt geselecteerd, gebruikt u deze om een LocalVideoStream exemplaar te maken. Geef deze videoOptions door als een item in de localVideoStream matrix aan de CallAgent startCall methode.

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);
  • U kunt ook deelnemen aan een gesprek met video met CallAgent.join() API en video accepteren en aanroepen met Call.Accept() API.
  • Wanneer uw oproep verbinding maakt, wordt er automatisch een videostream van de geselecteerde camera naar de andere deelnemer verzonden.

Lokale video starten en stoppen tijdens een gesprek

Video starten

Als u een video wilt starten tijdens een gesprek, moet u camera's opsommen met behulp van de getCameras methode voor het deviceManager object. Maak vervolgens een nieuw exemplaar van LocalVideoStream met de gewenste camera en geef het LocalVideoStream object door aan de startVideo methode van een bestaand aanroepobject:

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

Video stoppen

Nadat u video hebt verzonden, wordt een LocalVideoStream exemplaar van het type Video toegevoegd aan de localVideoStreams verzameling van een oproepexemplaren.

De videostream zoeken in het gespreksobject

const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );

Stop de lokale video Om lokale video te stoppen tijdens een gesprek, geeft u het localVideoStream exemplaar door dat wordt gebruikt voor video door aan de stopVideo-methode van de Call:

await call.stopVideo(localVideoStream);

U kunt overschakelen naar een ander cameraapparaat terwijl u een actieve LocalVideoStream hebt door deze instantie LocalVideoStream aan te switchSource roepen:

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

Als het opgegeven videoapparaat niet beschikbaar is:

  • Als uw video in een gesprek is uitgeschakeld en u video gaat gebruiken call.startVideo(), wordt met deze methode een SourceUnavailableError diagnostische gegevens voor gebruikers cameraStartFailed ingesteld op waar.
  • Een aanroep van de localVideoStream.switchSource() methode zorgt ervoor dat cameraStartFailed deze wordt ingesteld op true. Onze handleiding voor gespreksdiagnose bevat aanvullende informatie over het diagnosticeren van problemen met betrekking tot oproepen.

Als u wilt controleren of de lokale video is ingeschakeld of uitgeschakeld, kunt u de Call methode isLocalVideoStartedgebruiken, die waar of onwaar retourneert:

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

Als u wilt luisteren naar wijzigingen in de lokale video, kunt u zich abonneren en afmelden voor de gebeurtenis isLocalVideoStartedChanged:

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

Scherm delen starten en stoppen tijdens een gesprek

Als u het delen van het scherm tijdens een gesprek wilt starten, kunt u de asynchrone methode startScreenSharing() voor een Call object gebruiken:

Scherm delen starten

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

Opmerking: het verzenden van schermshares wordt alleen ondersteund in de bureaubladbrowser.

Het scherm delen zoeken in de verzameling LocalVideoStream

Nadat u het delen van het scherm hebt gestart, wordt er een LocalVideoStream exemplaar van het type ScreenSharingtoegevoegd aan de localVideoStreams verzameling op het aanroepexemplaren.

const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );

Scherm delen stoppen

Als u het delen van het scherm tijdens een aanroep wilt stoppen, kunt u asynchrone API stoptScreenSharing gebruiken:

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

De status van het delen van het scherm controleren

Als u wilt controleren of het delen van het scherm is ingeschakeld of uitgeschakeld, kunt u isScreenSharingOn-API gebruiken, die waar of onwaar retourneert:

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

Als u wilt luisteren naar wijzigingen in de schermshare, kunt u zich abonneren en afmelden voor de gebeurtenis isScreenSharingOnChanged:

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

Belangrijk

Deze functie van Azure Communication Services is momenteel beschikbaar als preview-versie.

Preview-API's en SDK's worden aangeboden zonder een service level agreement. U wordt aangeraden deze niet te gebruiken voor productieworkloads. Sommige functies worden mogelijk niet ondersteund of hebben mogelijk beperkte mogelijkheden.

Raadpleeg aanvullende gebruiksvoorwaarden voor Microsoft Azure Previews voor meer informatie.

Preview van lokale schermshares is beschikbaar als onderdeel van versie 1.15.1-beta.1+.

Voorbeeld van lokale schermshare

U kunt een VideoStreamRenderer bestand gebruiken om streams te genereren vanuit uw lokale schermshare, zodat u kunt zien wat u verzendt als een stream voor het delen van schermen.

// To start viewing local screen share preview
await call.startScreenSharing();
const localScreenSharingStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing' });
const videoStreamRenderer = new VideoStreamRenderer(localScreenSharingStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);

// To stop viewing local screen share preview.
await call.stopScreenSharing();
view.dispose();
htmlElement.removeChild(view.target);

// Screen sharing can also be stoped by clicking on the native browser's "Stop sharing" button.
// The isScreenSharingOnChanged event will be triggered where you can check the value of call.isScreenSharingOn.
// If the value is false, then that means screen sharing is turned off and so we can go ahead and dispose the screen share preview.
// This event is also triggered for the case when stopping screen sharing via Call.stopScreenSharing() API.
call.on('isScreenSharingOnChanged', () => {
    if (!call.isScreenSharingOn) {
        view.dispose();
        htmlElement.removeChild(view.target);
    }
});

Video-/schermen van externe deelnemers weergeven

Als u een externe deelnemer video of scherm delen wilt weergeven, is de eerste stap het verkrijgen van een verwijzing op de RemoteVideoStream die u wilt weergeven. Dit kan worden gedaan door de matrix- of videostream (videoStreams) van de RemoteParticipant. De verzameling externe deelnemers wordt geopend via het Call object.

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

Als u wilt weergeven RemoteVideoStream, moet u zich abonneren op de isAvailableChanged gebeurtenis. Als de isAvailable eigenschap wordt gewijzigd true, verzendt een externe deelnemer een videostream. Maak daarna een nieuw exemplaar van VideoStreamRendereren maak vervolgens een nieuw VideoStreamRendererView exemplaar met behulp van de asynchrone createView methode.
Vervolgens kunt u een ui-element koppelen view.target .

Wanneer de beschikbaarheid van een externe stream verandert, kunt u het geheel VideoStreamRenderer of een specifiek VideoStreamRendererViewbestand vernietigen. Als u besluit deze te behouden, wordt in de weergave een leeg videoframe weergegeven.

// 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';

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

CSS voor het stylen van de laadspinner via de externe videostream.

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

Externe videokwaliteit

De WebJS SDK van Azure Communication Services biedt een functie met de naam Optimal Video Count (OVC), vanaf versie 1.15.1. Deze functie kan worden gebruikt om toepassingen tijdens runtime te informeren over hoeveel binnenkomende video's van verschillende deelnemers optimaal kunnen worden weergegeven op een bepaald moment in een groepsgesprek (2+ deelnemers). Met deze functie wordt een eigenschap optimalVideoCount weergegeven die dynamisch wordt gewijzigd tijdens het aanroepen op basis van de netwerk- en hardwaremogelijkheden van een lokaal eindpunt. De waarde van optimalVideoCount details hoeveel video's van verschillende deelnemerstoepassing op een bepaald moment moeten worden weergegeven. Toepassingen moeten deze wijzigingen afhandelen en het aantal weergegeven video's dienovereenkomstig bijwerken naar de aanbeveling. Er is een uitvalperiode (ongeveer 10 s) tussen elke update.

Gebruik De optimalVideoCount functie is een oproepfunctie. U moet verwijzen naar de functie OptimalVideoCount via de feature methode van het Call object. Vervolgens kunt u een listener instellen via de on methode die OptimalVideoCountCallFeature moet worden gewaarschuwd wanneer de optimalVideoCount wordt gewijzigd. Als u zich wilt afmelden voor de wijzigingen, kunt u de off methode aanroepen. Het huidige maximum aantal binnenkomende video's dat kan worden weergegeven, is 16. Om 16 binnenkomende video's goed te ondersteunen, moet de computer een mimimum van 16 GB RAM en een 4-core of hoger CPU hebben die niet ouder is dan 3 jaar.

const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
    const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})

Voorbeeldgebruik: De toepassing moet zich abonneren op wijzigingen van het optimale aantal video's in groepsgesprekken. Een wijziging in het optimale aantal video's kan worden verwerkt door een nieuwe renderer (createView methode) te maken of weergaven te verwijderen (dispose) en de indeling van de toepassing dienovereenkomstig bij te werken.

Eigenschappen van externe videostream

Externe videostreams hebben de volgende eigenschappen:

const id: number = remoteVideoStream.id;
  • id: De id van een externe videostream.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
  • mediaStreamType: Kan zijn Video of ScreenSharing.
const isAvailable: boolean = remoteVideoStream.isAvailable;
  • isAvailable: Hiermee definieert u of een eindpunt van een externe deelnemer actief een stream verzendt.
const isReceiving: boolean = remoteVideoStream.isReceiving;
  • isReceiving:
    • Informeert de toepassing als externe videostreamgegevens worden ontvangen of niet.

    • De vlag wordt in de volgende scenario's verplaatst false :

      • Een externe deelnemer die zich in de mobiele browser bevindt, brengt de browser-app op de achtergrond.
      • Een externe deelnemer of de gebruiker die de video ontvangt, heeft een netwerkprobleem dat de videokwaliteit drastisch beïnvloedt.
      • Een externe deelnemer die zich in macOS/iOS Safari bevindt, selecteert 'Onderbreken' in de adresbalk.
      • Een externe deelnemer heeft een netwerkverbinding.
      • Een externe deelnemer op mobiele apparaten beëindigt of beëindigt de browser.
      • Een externe deelnemer op mobiel of desktop vergrendelt het apparaat. Dit scenario is ook van toepassing als de externe deelnemer zich op een desktopcomputer bevindt en in de slaapstand gaat.
    • De vlag wordt in de volgende scenario's verplaatst true :

      • Een externe deelnemer die zich in de mobiele browser bevindt en de browser achtergrond heeft, brengt deze terug naar de voorgrond.
      • Een externe deelnemer die zich in macOS/iOS Safari bevindt, selecteert op 'Hervatten' in de adresbalk nadat de video is onderbroken.
      • Een externe deelnemer maakt opnieuw verbinding met het netwerk na een tijdelijke verbroken verbinding.
      • Een externe deelnemer op mobiele apparaten ontgrendelt het apparaat en keert terug naar het gesprek in de mobiele browser.
    • Deze functie verbetert de gebruikerservaring voor het weergeven van externe videostreams.

    • U kunt een laadspinner weergeven via de externe videostream wanneer de vlag isReceiving verandert in false. U hoeft geen laadspinner te implementeren, maar een laadspinner is het meest voorkomende gebruik voor een betere gebruikerservaring.

const size: StreamSize = remoteVideoStream.size;
  • size: De streamgrootte met informatie over de breedte en hoogte van de video.

VideoStreamRenderer-methoden en -eigenschappen

await videoStreamRenderer.createView();

Maak een VideoStreamRendererView exemplaar dat kan worden gekoppeld in de gebruikersinterface van de toepassing om de externe videostream weer te geven, gebruik een asynchrone createView() methode, deze wordt omgezet wanneer stream gereed is om weer te geven en retourneert een object met target een eigenschap die het element vertegenwoordigt video dat overal in de DOM-structuur kan worden ingevoegd.

videoStreamRenderer.dispose();

videoStreamRenderer Verwijder alle bijbehorende exemplaren en alle bijbehorende VideoStreamRendererView exemplaren.

VideoStreamRendererView-methoden en -eigenschappen

Wanneer u een VideoStreamRendererViewmaakt, kunt u de scalingMode en isMirrored eigenschappen opgeven. scalingMode kan zijn Stretch, Cropof Fit. Als isMirrored dit is opgegeven, wordt de gerenderde stroom verticaal gespiegeld.

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

Elk VideoStreamRendererView exemplaar heeft een target eigenschap die het renderingoppervlak vertegenwoordigt. Koppel deze eigenschap in de gebruikersinterface van de toepassing:

htmlElement.appendChild(view.target);

U kunt bijwerken scalingMode door de updateScalingMode methode aan te roepen:

view.updateScalingMode('Crop');

Videostreams verzenden vanaf twee verschillende camera's, in dezelfde oproep vanaf hetzelfde desktopapparaat.

Belangrijk

Deze functie van Azure Communication Services is momenteel beschikbaar als preview-versie.

Preview-API's en SDK's worden aangeboden zonder een service level agreement. U wordt aangeraden deze niet te gebruiken voor productieworkloads. Sommige functies worden mogelijk niet ondersteund of hebben mogelijk beperkte mogelijkheden.

Raadpleeg aanvullende gebruiksvoorwaarden voor Microsoft Azure Previews voor meer informatie.

Het verzenden van videostreams vanaf twee verschillende camera's in dezelfde oproep wordt ondersteund als onderdeel van versie 1.17.1-beta.1+ op desktop ondersteunde browsers.

  • U kunt videostreams vanaf twee verschillende camera's verzenden vanuit één tabblad/app in de desktopbrowser, in dezelfde aanroep, met het volgende codefragment:
// Create your first CallAgent with identity A
const callClient1 = new CallClient();
const callAgent1 = await callClient1.createCallAgent(tokenCredentialA);
const deviceManager1 = await callClient1.getDeviceManager();

// Create your second CallAgent with identity B
const callClient2 = new CallClient();
const callAgent2 = await callClient2.createCallAgent(tokenCredentialB);
const deviceManager2 = await callClient2.getDeviceManager();

// Join the call with your first CallAgent
const camera1 = await deviceManager1.getCameras()[0];
const callObj1 = callAgent1.join({ groupId: ‘123’}, { videoOptions: { localVideoStreams: [new LocalVideoStream(camera1)] } });

// Join the same call with your second CallAgent and make it use a different camera
const camera2 = (await deviceManager2.getCameras()).filter((camera) => { return camera !== camera1 })[0];
const callObj2 = callAgent2.join({ groupId: '123' }, { videoOptions: { localVideoStreams: [new LocalVideoStream(camera2)] } });

//Mute the microphone and speakers of your second CallAgent’s Call, so that there is no echos/noises.
await callObj2.muteIncomingAudio();
await callObj2.mute();

Beperkingen:

  • Dit moet worden gedaan met twee verschillende CallAgent exemplaren die verschillende identiteiten gebruiken. Het codefragment toont twee aanroepagents die worden gebruikt, elk met een eigen aanroepobject.
  • In het codevoorbeeld nemen beide CallAgents deel aan dezelfde aanroep (dezelfde oproep-id's). U kunt ook deelnemen aan verschillende gesprekken met elke agent en één video verzenden tijdens één gesprek en een andere video in de andere oproep.
  • Het verzenden van dezelfde camera in beide CallAgents wordt niet ondersteund. Ze moeten twee verschillende camera's zijn.
  • Het verzenden van twee verschillende camera's met één CallAgent wordt momenteel niet ondersteund.
  • Op macOS Safari kunnen video-effecten op de achtergrond vervagen (van @azure/communication-effects), kunnen alleen worden toegepast op één camera en niet op beide tegelijk.

Installeer de SDK

Zoek het bestand op projectniveau build.gradle en voeg deze toe aan mavenCentral() de lijst met opslagplaatsen onder buildscript en allprojects:

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

Voeg vervolgens in het bestand op moduleniveau build.gradle de volgende regels toe aan de dependencies sectie:

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

De vereiste objecten initialiseren

Als u een CallAgent exemplaar wilt maken, moet u de createCallAgent methode voor een CallClient exemplaar aanroepen. Hiermee wordt asynchroon een CallAgent exemplaarobject geretourneerd.

De createCallAgent methode wordt CommunicationUserCredential gebruikt als een argument, dat een toegangstoken inkapselt.

Als u toegang DeviceManagerwilt krijgen, moet u eerst een callAgent exemplaar maken. Vervolgens kunt u de CallClient.getDeviceManager methode gebruiken om op te halen 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();

Als u een weergavenaam voor de aanroeper wilt instellen, gebruikt u deze alternatieve methode:

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

Apparaatbeheer

Als u video wilt gaan gebruiken met Bellen, moet u weten hoe u apparaten beheert. Met apparaten kunt u bepalen wat audio en video naar het gesprek verzendt.

DeviceManager hiermee kunt u lokale apparaten opsommen die kunnen worden gebruikt in een gesprek om uw audio-/videostreams te verzenden. Hiermee kunt u ook toestemming vragen van een gebruiker om toegang te krijgen tot hun microfoon en camera met behulp van de systeemeigen browser-API.

U kunt toegang krijgen deviceManager via de aanroepmethode callClient.getDeviceManager() .

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

Lokale apparaten opsommen

Voor toegang tot lokale apparaten kunt u opsommingsmethoden op de Apparaatbeheer gebruiken. Opsomming is een synchrone actie.

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

Voorbeeld van lokale camera

U kunt streams vanaf uw lokale camera gebruiken DeviceManager en Renderer weergeven. Deze stream wordt niet naar andere deelnemers verzonden; het is een lokale preview-feed. Dit is een asynchrone actie.

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

Een 1:1-gesprek met videocamera plaatsen

Waarschuwing

Op dit moment wordt slechts één uitgaande lokale videostream ondersteund om een gesprek met video te plaatsen dat u lokale camera's moet inventariseren met behulp van de deviceManager getCameras API. Zodra u een gewenste camera selecteert, gebruikt u deze om een LocalVideoStream exemplaar te maken en door te geven videoOptions als een item in de localVideoStream matrix aan een call methode. Zodra de oproep verbinding maakt, wordt automatisch een videostream van de geselecteerde camera naar andere deelnemers verzonden.

Notitie

Vanwege privacyproblemen wordt video niet gedeeld met de oproep als deze niet lokaal wordt bekeken. Zie voorbeeld van lokale camera voor meer informatie.

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

Lokale video starten en stoppen

Als u een video wilt starten, moet u camera's inventariseren met behulp van de getCameraList API op deviceManager object. Maak vervolgens een nieuw exemplaar van het doorgeven van LocalVideoStream de gewenste camera en geef deze als argument door in de startVideo API:

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

Zodra u video hebt verzonden, wordt er een LocalVideoStream exemplaar toegevoegd aan de localVideoStreams verzameling op het oproepexemplaren.

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

Als u lokale video wilt stoppen, geeft u het exemplaar door dat beschikbaar is in localVideoStreams de LocalVideoStream verzameling:

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

U kunt overschakelen naar een ander cameraapparaat terwijl video wordt verzonden door een LocalVideoStream instantie aan te switchSource roepen:

currentLocalVideoStream.switchSource(source).get();

Videostreams van externe deelnemers weergeven

Bekijk de verzamelingen om de videostreams en schermdelingsstreams van externe deelnemers videoStreams weer te geven:

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

Als u een RemoteVideoStream van een externe deelnemer wilt weergeven, moet u zich abonneren op een OnVideoStreamsUpdated gebeurtenis.

Binnen de gebeurtenis geeft de wijziging van isAvailable de eigenschap aan waar aan dat externe deelnemer momenteel een stream verzendt. Als dat gebeurt, maakt u een nieuw exemplaar van een Renderer, maakt u vervolgens een nieuwe RendererView met behulp van asynchrone createView API en voegt u overal in de gebruikersinterface van uw toepassing toe view.target .

Wanneer de beschikbaarheid van een externe stream verandert, kunt u ervoor kiezen om de hele Renderer te vernietigen, een specifieke RendererView of behouden, maar dit resulteert in het weergeven van een leeg videoframe.

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

Eigenschappen van externe videostream

Externe videostream heeft een aantal eigenschappen

  • Id - Id van een externe videostream
int id = remoteVideoStream.getId();
  • MediaStreamType - Kan 'Video' of 'ScreenSharing' zijn
MediaStreamType type = remoteVideoStream.getMediaStreamType();
  • isAvailable - Geeft aan of het eindpunt van een externe deelnemer actief stream verzendt
boolean availability = remoteVideoStream.isAvailable();

Renderermethoden en -eigenschappen

Renderer-object na API's

  • Maak een VideoStreamRendererView exemplaar dat later kan worden gekoppeld in de gebruikersinterface van de toepassing om externe videostream weer te geven.
// Create a view for a video stream
VideoStreamRendererView.createView()
  • Renderer en alle VideoStreamRendererView die aan deze renderer zijn gekoppeld, verwijderen. Worden aangeroepen wanneer u alle gekoppelde weergaven uit de gebruikersinterface hebt verwijderd.
VideoStreamRenderer.dispose()
  • StreamSize - grootte (breedte/hoogte) van een externe videostream
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();

RendererView-methoden en -eigenschappen

Wanneer u een VideoStreamRendererView exemplaar maakt, kunt u de ScalingMode eigenschappen mirrored opgeven die van toepassing zijn op deze weergave: de schaalmodus kan een van de 'CROP' | 'FIT'

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

De gemaakte RendererView kan vervolgens worden gekoppeld aan de gebruikersinterface van de toepassing met behulp van het volgende codefragment:

layout.addView(rendererView);

U kunt de schaalmodus later bijwerken door API aan te updateScalingMode roepen op het RendererView-object met een van ScalingMode.CROP | ScalingMode.FIT als argument.

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

Uw systeem instellen

Volg deze stappen om uw systeem in te stellen.

Het Xcode-project maken

Maak in Xcode een nieuw iOS-project en selecteer de sjabloon Single View-app (Toepassing met één weergave). In dit artikel wordt het SwiftUI-framework gebruikt, dus u moet taal instellen op Swift en interface instellen op SwiftUI.

U gaat geen tests maken in dit artikel. Schakel het selectievakje Inclusief tests uit.

Schermopname van het venster voor het maken van een project in Xcode.

Het pakket en afhankelijkheden installeren met CocoaPods

  1. Maak een Podfile voor uw toepassing, zoals in dit voorbeeld:

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

  3. Open .xcworkspace met behulp van Xcode.

Toegang tot de microfoon aanvragen

Voor toegang tot de microfoon van het apparaat moet u de lijst met gegevenseigenschappen van uw app bijwerken met behulp van NSMicrophoneUsageDescription. Stel de gekoppelde waarde in op een tekenreeks die is opgenomen in het dialoogvenster dat het systeem gebruikt om toegang van de gebruiker aan te vragen.

Klik met de rechtermuisknop op de vermelding Info.plist van de projectstructuur en selecteer Open As>Source Code. Voeg de volgende regels toe in de sectie op het hoogste niveau <dict> en sla het bestand op.

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

Stel het app-framework in

Open het projectbestand ContentView.swift . Voeg een import declaratie toe aan het begin van het bestand om de AzureCommunicationCalling bibliotheek te importeren. Daarnaast importeert u AVFoundation. U hebt deze nodig voor audiomachtigingsaanvragen in de code.

import AzureCommunicationCalling
import AVFoundation

CallAgent initialiseren

Als u een CallAgent exemplaar CallClientwilt maken, moet u een callClient.createCallAgent methode gebruiken die asynchroon een CallAgent object retourneert nadat het is geïnitialiseerd.

Als u een aanroepclient wilt maken, geeft u een CommunicationTokenCredential object door:

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

Geef het CommunicationTokenCredential object door waarnaar u hebt gemaakt CallClienten stel de weergavenaam in:

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

Apparaten beheren

Als u video wilt gaan gebruiken met Bellen, moet u weten hoe u apparaten beheert. Met apparaten kunt u bepalen wat audio en video naar het gesprek verzendt.

DeviceManager hiermee kunt u lokale apparaten opsommen die kunnen worden gebruikt in een gesprek om audio- of videostreams te verzenden. Hiermee kunt u ook toestemming vragen van een gebruiker om toegang te krijgen tot een microfoon of camera. U kunt toegang krijgen tot deviceManager het callClient object.

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

Lokale apparaten opsommen

Voor toegang tot lokale apparaten kunt u opsommingsmethoden gebruiken in apparaatbeheer. Opsomming is een synchrone actie.

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

Een voorbeeld van een lokale camera downloaden

U kunt een Renderer stream vanaf uw lokale camera weergeven. Deze stream wordt niet naar andere deelnemers verzonden; het is een lokale preview-feed. Dit is een asynchrone actie.

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

Eigenschappen van lokale cameravoorbeeld ophalen

De renderer heeft een set eigenschappen en methoden waarmee u de rendering kunt beheren.

// 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()

Een 1:1-gesprek met video plaatsen

Zie de sectie over het beheren van apparaten om een apparaatbeheerexemplaren op te halen.

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

Videostreams van externe deelnemers weergeven

Externe deelnemers kunnen tijdens een gesprek video of scherm delen initiëren.

Streams voor video delen of scherm delen van externe deelnemers afhandelen

Als u de streams van externe deelnemers wilt weergeven, inspecteert u de videoStreams verzamelingen.

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

Eigenschappen van externe videostream ophalen

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

Externe deelnemersstreams weergeven

Als u externe deelnemersstreams wilt weergeven, gebruikt u de volgende code.

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)

Externe videoweergavemethoden en -eigenschappen ophalen

// [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()

Uw systeem instellen

Volg deze stappen om uw systeem in te stellen.

Het Visual Studio-project maken

Voor een Universeel Windows-platform-app maakt u in Visual Studio 2022 een nieuw leeg app-project (Universal Windows). Nadat u de projectnaam hebt ingevoerd, kunt u een Windows SDK kiezen die hoger is dan 10.0.17763.0.

Maak voor een WinUI 3-app een nieuw project met de sjabloon Blank App, Packaged (WinUI 3 in Desktop) om een WinUI 3-app met één pagina in te stellen. Windows-app SDK versie 1.3 of hoger is vereist.

Installeer het pakket en afhankelijkheden met behulp van NuGet Pakketbeheer

De Aanroepende SDK-API's en -bibliotheken zijn openbaar beschikbaar via een NuGet-pakket.

Het NuGet-pakket voor aanroepende SDK zoeken, downloaden en installeren:

  1. Open NuGet Pakketbeheer door Tools>NuGet Pakketbeheer> Manage NuGet Packages for Solution te selecteren.
  2. Selecteer Bladeren en voer vervolgens Azure.Communication.Calling.WindowsClient in het zoekvak in.
  3. Zorg ervoor dat het selectievakje Voorlopige versie opnemen is ingeschakeld.
  4. Selecteer het pakket Azure.Communication.Calling.WindowsClient en selecteer vervolgens Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 of een nieuwere versie.
  5. Schakel het selectievakje in dat overeenkomt met het Azure Communication Services-project in het rechterdeelvenster.
  6. Selecteer Installeren.

Toegang tot de microfoon aanvragen

Voor de app moet toegang tot de camera goed worden uitgevoerd. In UWP-apps moet de cameramogelijkheid worden gedeclareerd in het manifestbestand van de app.

In de volgende stappen ziet u hoe u dat kunt bereiken.

  1. Dubbelklik in het Solution Explorer deelvenster op het bestand met .appxmanifest extensie.
  2. Klik op het Capabilities tabblad.
  3. Schakel het Camera selectievakje in de lijst met mogelijkheden in.

Ui-knoppen maken om het gesprek te plaatsen en op te hangen

Deze eenvoudige voorbeeld-app bevat twee knoppen. Een voor het plaatsen van de oproep en een andere om een geplaatst gesprek op te hangen. In de volgende stappen ziet u hoe u deze knoppen aan de app toevoegt.

  1. Dubbelklik in het Solution Explorer deelvenster op het bestand met de naam MainPage.xaml UWP of MainWindows.xaml voor WinUI 3.
  2. Zoek in het centrale deelvenster naar de XAML-code onder de preview-versie van de gebruikersinterface.
  3. Wijzig de XAML-code door het volgende fragment:
<TextBox x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" />
<StackPanel>
    <Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" />
    <Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" />
</StackPanel>

De app instellen met SDK-API's voor aanroepen

De CALLING SDK-API's bevinden zich in twee verschillende naamruimten. De volgende stappen informeren de C#-compiler over deze naamruimten, zodat De IntelliSense van Visual Studio kan helpen bij het ontwikkelen van code.

  1. Klik in het Solution Explorer deelvenster op de pijl aan de linkerkant van het bestand met de naam MainPage.xaml UWP of MainWindows.xaml voor WinUI 3.
  2. Dubbelklik op bestand met de naam MainPage.xaml.cs of MainWindows.xaml.cs.
  3. Voeg de volgende opdrachten onder aan de huidige using instructies toe.
using Azure.Communication.Calling.WindowsClient;

Houd MainPage.xaml.cs of MainWindows.xaml.cs open. In de volgende stappen wordt er meer code aan toegevoegd.

App-interacties toestaan

De knoppen van de gebruikersinterface die eerder zijn toegevoegd, moeten boven op een geplaatste CommunicationCallknop werken. Dit betekent dat een CommunicationCall gegevenslid moet worden toegevoegd aan de MainPage of MainWindow klasse. Daarnaast moet een CallAgent gegevenslid worden toegevoegd aan dezelfde klasse om de asynchrone bewerking CallAgent te laten slagen.

Voeg de volgende gegevensleden toe aan de MainPage of MainWindow klasse:

CallAgent callAgent;
CommunicationCall call;

Knophandlers maken

Voorheen werden twee UI-knoppen toegevoegd aan de XAML-code. Met de volgende code worden de handlers toegevoegd die moeten worden uitgevoerd wanneer een gebruiker de knop selecteert. De volgende code moet worden toegevoegd na de gegevensleden uit de vorige sectie.

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

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

Objectmodel

De volgende klassen en interfaces verwerken enkele van de belangrijkste functies van de Clientbibliotheek voor aanroepen van Azure Communication Services voor UWP.

Name Beschrijving
CallClient Het CallClient is het belangrijkste toegangspunt voor de clientbibliotheek voor aanroepen.
CallAgent Het CallAgent wordt gebruikt om oproepen te starten en eraan deel te nemen.
CommunicationCall Het CommunicationCall wordt gebruikt voor het beheren van geplaatste of gekoppelde oproepen.
CommunicationTokenCredential De CommunicationTokenCredential wordt gebruikt als de tokenreferentie om de CallAgent.
CallAgentOptions De CallAgentOptions bevat informatie om de beller te identificeren.
HangupOptions De HangupOptions meldingen als een oproep moet worden beëindigd aan alle deelnemers.

Videoschema-handler registreren

Een UI-onderdeel, zoals MediaElement of MediaPlayerElement van XAML, hebt u de app nodig die een configuratie registreert voor het weergeven van lokale en externe videofeeds. Voeg de volgende inhoud toe tussen de Package tags van:Package.appxmanifest

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

De CallAgent initialiseren

Als u een CallAgent exemplaar CallClientwilt maken, moet u een methode gebruiken CallClient.CreateCallAgentAsync die asynchroon een CallAgent object retourneert zodra het is geïnitialiseerd.

Als u wilt maken CallAgent, moet u een CallTokenCredential object en een CallAgentOptions object doorgeven. Houd er rekening mee dat CallTokenCredential er een ongeldig token wordt doorgegeven.

De volgende code moet worden toegevoegd in de helperfunctie die moet worden aangeroepen in de initialisatie van de app.

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.CallsUpdated += Agent_OnCallsUpdatedAsync;
this.callAgent.IncomingCallReceived += Agent_OnIncomingCallAsync;

Wijzig het <AUTHENTICATION_TOKEN> met een geldig referentietoken voor uw resource. Raadpleeg de documentatie van het gebruikerstoegangstoken als er een referentietoken moet worden opgehaald.

Een 1:1-gesprek met videocamera plaatsen

De objecten die nodig zijn om een te CallAgent maken, zijn nu gereed. Het is tijd om asynchroon een videogesprek te maken CallAgent en te plaatsen.

private async void CallButton_Click(object sender, RoutedEventArgs e)
{
    var callString = CalleeTextBox.Text.Trim();

    if (!string.IsNullOrEmpty(callString))
    {
        if (callString.StartsWith("8:")) // 1:1 Azure Communication Services call
        {
            this.call = await StartAcsCallAsync(callString);
        }
    }

    if (this.call != null)
    {
        this.call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
        this.call.StateChanged += OnStateChangedAsync;
    }
}

private async Task<CommunicationCall> StartAcsCallAsync(string acsCallee)
{
    var options = await GetStartCallOptionsAsynnc();
    var call = await this.callAgent.StartCallAsync( new [] { new UserCallIdentifier(acsCallee) }, options);
    return call;
}

var micStream = new LocalOutgoingAudioStream(); // Create a default local audio stream
var cameraStream = new LocalOutgoingVideoStreamde(this.viceManager.Cameras.FirstOrDefault() as VideoDeviceDetails); // Create a default video stream

private async Task<StartCallOptions> GetStartCallOptionsAsynnc()
{
    return new StartCallOptions() {
        OutgoingAudioOptions = new OutgoingAudioOptions() { IsMuted = true, Stream = micStream  },
        OutgoingVideoOptions = new OutgoingVideoOptions() { Streams = new OutgoingVideoStream[] { cameraStream } }
    };
}

Voorbeeld van lokale camera

We kunnen eventueel lokale cameravoorbeeld instellen. De video kan worden weergegeven via MediaPlayerElement:

<Grid>
    <MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
    <MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>

De lokale preview MediaPlayerElementinitialiseren:

private async void CameraList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (cameraStream != null)
    {
        await cameraStream?.StopPreviewAsync();
        if (this.call != null)
        {
            await this.call?.StopVideoAsync(cameraStream);
        }
    }
    var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
    cameraStream = new LocalOutgoingVideoStream(selectedCamerea);

    var localUri = await cameraStream.StartPreviewAsync();
    LocalVideo.Source = MediaSource.CreateFromUri(localUri);

    if (this.call != null) {
        await this.call?.StartVideoAsync(cameraStream);
    }
}

Externe camerastream weergeven

Stel zelfs handler in als reactie op OnCallsUpdated gebeurtenis:

private async void 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 void OnRemoteParticipantsUpdatedAsync(object sender, ParticipantsUpdatedEventArgs args)
{
    await OnParticipantChangedAsync(
        args.RemovedParticipants.ToList<RemoteParticipant>(),
        args.AddedParticipants.ToList<RemoteParticipant>());
}

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

Start het weergeven van externe videostream op MediaPlayerElement:

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

                        /* Or WinUI 3
                        this.DispatcherQueue.TryEnqueue(() => {
                            RemoteVideo.Source = MediaSource.CreateFromUri(uri);
                            RemoteVideo.MediaPlayer.Play();
                        });
                        */

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

Een gesprek beëindigen

Zodra een aanroep is geplaatst, moet de HangupAsync methode van het CommunicationCall object worden gebruikt om de aanroep op te hangen.

Er moet ook een instantie van HangupOptions worden gebruikt om te informeren of de oproep moet worden beëindigd voor alle deelnemers.

De volgende code moet binnen HangupButton_Clickworden toegevoegd.

var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
    var call = this.callAgent?.Calls?.FirstOrDefault();
    if (call != null)
    {
        foreach (var localVideoStream in call.OutgoingVideoStreams)
        {
            await call.StopVideoAsync(localVideoStream);
        }

        try
        {
            if (cameraStream != null)
            {
                await cameraStream.StopPreviewAsync();
            }

            await call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
        }
        catch(Exception ex) 
        { 
            var errorCode = unchecked((int)(0x0000FFFFU & ex.HResult));
            if (errorCode != 98) // Sample error code, sam_status_failed_to_hangup_for_everyone (98)
            {
                throw;
            }
        }
    }
}

De code uitvoeren

Zorg ervoor dat Visual Studio de app bouwt voor x64, x86 of ARM64klik F5 vervolgens om de app uit te voeren. Klik daarna op de CommunicationCall knop om een oproep naar de opgegeven aanroep te plaatsen.

Houd er rekening mee dat de eerste keer dat de app wordt uitgevoerd, de gebruiker wordt gevraagd om toegang te verlenen tot de microfoon.

Volgende stappen