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 beheren

De Call Agent instantie helpt u bij het beheren van gesprekken (om deel te nemen aan oproepen of ze 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 connectionStatus-waarde van Call Agent betekent dat de client-SDK verbonden is en meldingen kan ontvangen van de Microsoft-infrastructuur.

Verbinding verbroken - Een Call Agent connectionStatus-waarde van Disconnected geeft aan dat er een probleem is dat voorkomt dat de SDK correct verbinding maakt. Call Agent moet opnieuw worden gemaakt.

  • invalidToken: Als een token is verlopen of ongeldig is, verbreekt de Call Agent instantie de verbinding met deze fout.
  • connectionIssue: als er een probleem is met de client die verbinding maakt met de Microsoft-infrastructuur, wordt na veel nieuwe pogingen Call Agent de fout connectionIssue 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 van 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.

Gebruik de deviceManager opdracht om lokale apparaten op te sommen 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 callClient.getDeviceManager() aan te roepen.

const deviceManager = await callClient.getDeviceManager();

Lokale apparaten ophalen

Voor toegang tot lokale apparaten kunt u de deviceManager enumeratiemethoden getCameras() en getMicrophones gebruiken. 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]);

Fototoestel

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 aan dat verschillende CallAgents verschillende microfoons en luidsprekers gebruiken. Ze mogen niet dezelfde microfoons of luidsprekers delen. Als het delen plaatsvindt, kan UFD (Microphone User Facing Diagnostics) worden geactiveerd en werkt de microfoon niet meer, afhankelijk van de browser en het besturingssysteem.

Lokale video-stream

Als gebruikers video in een gesprek willen verzenden, moet u een LocalVideoStream object maken.

const localVideoStream = new LocalVideoStream(camera);

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

A LocalVideoStream heeft de volgende eigenschappen:

  • source is de apparaatgegevens.

    const source = localVideoStream.source;
    
  • mediaStreamType kan zijn Video, ScreenSharingof RawMedia.

    const type: MediaStreamType = localVideoStream.mediaStreamType;
    

Voorbeeld van lokale camera

U kunt deviceManager en VideoStreamRenderer gebruiken om streams van uw lokale camera weer te geven.

Nadat u LocalVideoStream hebt gemaakt, kunt u het gebruiken om VideoStreamRenderer in te stellen. Zodra u de VideoStreamRenderer hebt gemaakt, roept u de methode createView() aan om een weergave te krijgen die u als subelement 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 u DeviceManager voor het eerst aanmaakt, weet het niets met betrekking tot apparaten als er nog geen toestemmingen zijn verleend. De apparaatnaam is in eerste instantie leeg en bevat geen gedetailleerde apparaatgegevens. U moet DeviceManager.askPermission() oproepen, waarbij om apparaattoegang voor de gebruiker wordt gevraagd. Wanneer de gebruiker toegang toestaat, leert de apparaatbeheerder over de apparaten op het systeem, werkt het de lijsten met apparaten bij en verzendt het de audioDevicesUpdated en videoDevicesUpdated gebeurtenissen. Als een gebruiker de pagina vernieuwt en een apparaatbeheerder maakt, krijgt de apparaatbeheerder informatie over apparaten omdat de gebruiker eerder toegang heeft verleend. Het heeft zijn apparaatlijsten aanvankelijk gevuld en het zendt geen audioDevicesUpdated- of videoDevicesUpdated-events uit.
  • 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 het door binnen videoOptions als een item binnen de localVideoStream array aan de CallAgentstartCall 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 succesvol bent begonnen met het verzenden van video, wordt een LocalVideoStream exemplaar van het type Video toegevoegd aan de localVideoStreams verzameling van een oproepexemplaar.

De videostream zoeken in het gespreksobject

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

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

await call.stopVideo(localVideoStream);

U kunt wisselen naar een ander cameratoestel terwijl u een actieve LocalVideoStream hebt door switchSource op die LocalVideoStream instantie aan te roepen.

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

Als het opgegeven videoapparaat niet beschikbaar is:

  • Als uw video tijdens een gesprek is uitgeschakeld en u de video start met call.startVideo(), veroorzaakt deze methode een SourceUnavailableError en wordt een gebruikersgerichte diagnostische 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:

Schermdeling starten

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

Notitie

Het verzenden van schermshare wordt alleen ondersteund voor desktopbrowsers.

Zoek de schermdeling in de verzameling LocalVideoStream

Nadat u schermdeling succesvol hebt gestart, wordt een LocalVideoStream exemplaar van het type ScreenSharing toegevoegd aan de localVideoStreams collectie op het aanroep-exemplaar.

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

Stoppen met scherm delen

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. Functies in preview zijn openbaar beschikbaar en kunnen worden gebruikt door alle nieuwe en bestaande Microsoft-klanten.

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

Zie Aanvullende gebruiksvoorwaarden voor Microsoft Azure Previewsvoor meer informatie.

De openbare preview van lokale schermdelen 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 stopped 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 video of een scherm van een externe deelnemer wilt weergeven, is de eerste stap om een referentie naar de RemoteVideoStream te verkrijgen die u wilt weergeven.

U kunt alleen een externe deelnemer weergeven 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 naar 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 Azure Communication Services WebJS SDK biedt een functie met de naam Optimal Video Count (OVC), vanaf versie 1.15.1.

Gebruik deze functie 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 van twee (2) of meer 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 debounceperiode (ongeveer tien (10) seconden) 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, heeft de computer minimaal 16 GB RAM en een vier (4) kern of een hogere CPU nodig die kleiner is dan drie (3) jaar oud.

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

Voorbeeldgebruik: Uw toepassing abonneert zich op wijzigingen van het optimale aantal video's in groepsgesprekken. Een wijziging in het optimale aantal video's wordt verwerkt door een nieuwe renderermethode createView te maken of weergaven dispose te verwijderen en de indeling van de toepassing dienovereenkomstig bij te werken.

Eigenschappen van videostream op afstand

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 naar false verplaatst in de volgende scenario's:

      • Een externe deelnemer die de mobiele browser gebruikt, zet 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 netwerkonderbreking.
      • Een deelnemer op afstand op een mobiel apparaat sluit 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 een desktopcomputer gebruikt en deze in de slaapstand gaat.
    • De vlag wordt naar true verplaatst in de volgende scenario's:

      • Een externe deelnemer die zich in de mobiele browser bevindt en de browser op de achtergrond heeft, brengt deze terug naar voorgrond.
      • Een externe deelnemer die zich in macOS/iOS Safari bevindt, selecteert Hervatten in de adresbalk nadat de video is onderbroken.
      • Een externe deelnemer maakt opnieuw verbinding met het netwerk na een tijdelijke verbroken verbinding.
      • Een deelnemer op afstand op een mobiel apparaat ontgrendelt zijn/haar apparaat en keert terug naar het gesprek in de browser van de mobiele telefoon.
    • 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();

Verwijder videoStreamRenderer 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 is gespecificeerd, wordt de gerenderde stream 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. Functies in preview zijn openbaar beschikbaar en kunnen worden gebruikt door alle nieuwe en bestaande Microsoft-klanten.

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

Zie Aanvullende gebruiksvoorwaarden voor Microsoft Azure Previewsvoor 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:

  • Het verzenden van videostreams moet worden uitgevoerd met twee verschillende CallAgent exemplaren met behulp van verschillende identiteiten. Het codefragment toont twee aanroepagents die worden gebruikt, elk met een eigen aanroepobject.
  • In het codevoorbeeld nemen beide CallAgents deel aan dezelfde aanroep (dezelfde aanroep-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 die een achtergrondvervaging creëren (van @azure/communication-effects)) alleen worden toegepast op één camera en niet op beide tegelijkertijd.

Installeer de SDK

Zoek je projectniveau build.gradle bestand en voeg mavenCentral() toe aan de lijst van repositories 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 neemt CommunicationUserCredential als argument, wat een toegangstoken inkapselt.

Om toegang tot DeviceManager te krijgen, moet u eerst een callAgent instantie 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 gebruiken met bellen, moet u apparaten beheren. Met apparaten kunt u bepalen wat audio en video naar het gesprek verzendt.

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

Roep de deviceManager functie aan om toegang te krijgen tot callClient.getDeviceManager().

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

Lokale apparaten opsommen

Gebruik opsommingsmethoden voor apparaatbeheer om toegang te krijgen tot lokale apparaten. 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 DeviceManager en Renderer gebruiken om streams van uw lokale camera weer te geven. Deze stream wordt niet naar andere deelnemers verzonden. Het is een lokale preview-feed. Het weergeven van een stream 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

Momenteel wordt slechts één uitgaande lokale videostream ondersteund. Als u een oproep met video wilt plaatsen, moet u lokale camera's inventariseren met behulp van de deviceManagergetCameras API. Zodra u een camera hebt geselecteerd, 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 het gesprek is verbonden, wordt automatisch een videostream van de geselecteerde camera naar andere deelnemers verzonden.

Notitie

Vanwege privacyproblemen wordt video niet gedeeld met het gesprek als deze niet lokaal wordt gepreviewd. 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 verzenden starten en stoppen

Als u een video wilt starten, moet u camera's inventariseren met behulp van de getCameraList bewerking op deviceManager object. Maak vervolgens een nieuw exemplaar van LocalVideoStream door de gewenste camera door te geven, 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 het u is gelukt video te verzenden, wordt er een LocalVideoStream exemplaar toegevoegd aan de localVideoStreams verzameling op het oproepexemplaar.

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 LocalVideoStream de localVideoStreams verzameling:

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

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

currentLocalVideoStream.switchSource(source).get();

Videostreams van externe deelnemers weergeven

Inspecteer de videoStreams-verzamelingen om de videostreams en schermdelingsstreams van externe deelnemers te bekijken.

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 eigenschap naar waarheidswaarde aan dat de 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 te verwijderen, of ze te behouden, wat echter resulteert in het tonen 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 videostream op afstand

Externe videostream heeft de volgende eigenschappen:

  • Id - Id van een externe videostream.

    int id = remoteVideoStream.getId();
    
  • MediaStreamType - Kan zijn Video of ScreenSharing.

    MediaStreamType type = remoteVideoStream.getMediaStreamType();
    
  • isAvailable - Geeft aan of het eindpunt van externe deelnemers actief stream verzendt.

    boolean availability = remoteVideoStream.isAvailable();
    

Renderermethoden en -eigenschappen

Het Renderer object gebruikt de volgende methoden.

  • Als u een externe videostream wilt weergeven, maakt u een VideoStreamRendererView exemplaar dat later kan worden gekoppeld aan de gebruikersinterface van de toepassing.

    // Create a view for a video stream
    VideoStreamRendererView.createView()
    
  • Renderer en alle VideoStreamRendererView die aan deze renderer zijn gekoppeld, verwijderen. Roep deze aan nadat u alle bijbehorende weergaven uit de gebruikersinterface hebt verwijderd.

    VideoStreamRenderer.dispose()
    
  • Als u de grootte (breedte/hoogte) van een externe videostream wilt instellen, gebruikt u StreamSize.

    StreamSize renderStreamSize = VideoStreamRenderer.getSize();
    int width = renderStreamSize.getWidth();
    int height = renderStreamSize.getHeight();
    

RendererView-methoden en -eigenschappen

Wanneer u een VideoStreamRendererView maakt, kunt u de ScalingMode en mirrored eigenschappen opgeven die van toepassing zijn op deze weergave.

De schaalmodus kan ofwel CROP of FIT zijn.

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 met behulp van de updateScalingMode bewerking op het RendererView object met een argument van of ScalingMode.CROPScalingMode.FIT.

// 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. Voel je vrij om het selectievakje Inclusief tests uit te schakelen.

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

Om een CallAgent instantie van CallClient te 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 dat u hebt gemaakt door aan CallClient, en 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 op 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 voorvertoning van een lokale camera bekijken

U kunt Renderer gebruiken om te beginnen met het weergeven van een stream vanaf uw lokale camera. Deze stream is niet voor andere deelnemers; 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 de lokale camerapreview ophalen

De renderer bevat 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 apparaatbeheerexemplaar te vinden.

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.

Afhandelen van video- en schermdelingsstreams van externe deelnemers

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

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

Eigenschappen van videostream op afstand 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 Universele Windows Platform-app maakt u in Visual Studio 2022 een nieuw lege app (Universele Windows)-project. 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 de Calling SDK zoeken, downloaden en installeren:

  1. Open NuGet Pakketbeheer door Hulpmiddelen>NuGet Pakketbeheer>NuGet-pakketten voor Oplossing beheren 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.WindowsClient1.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 is toegang tot de camera vereist. In UWP-apps (Universal Windows Platform) moet u de cameramogelijkheid declareren in het manifestbestand van de app.

  1. Open het project in Visual Studio.
  2. Dubbelklik in het deelvenster Solution Explorer op het bestand met .appxmanifest de extensie.
  3. Klik op het tabblad Mogelijkheden .
  4. Schakel het Camera selectievakje in de lijst met mogelijkheden in.

UI-knoppen maken om het gesprek te starten en op te hangen

Deze voorbeeld-app bevat twee knoppen. Een voor het plaatsen van de oproep en een andere om een geplaatst gesprek op te hangen.

  1. Dubbelklik in het deelvenster Solution Explorer 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 met behulp van 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.

Voer de volgende stappen uit om de C#-compiler te informeren over deze naamruimten, zodat Visual Studio's IntelliSense kan helpen bij het ontwikkelen van code.

  1. Klik in het deelvenster Solution Explorer 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 stap wordt meer code toegevoegd.

App-interacties inschakelen

De ui-knoppen die we hebben toegevoegd, moeten boven op een geplaatste CommunicationCallknop werken. Dit betekent dat u een CommunicationCall gegevenslid moet toevoegen aan de MainPage of MainWindow klasse. U moet ook de asynchrone bewerking waarmee CallAgent wordt gemaakt activeren om te slagen. Voeg een CallAgent gegevenslid toe aan dezelfde klasse.

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

CallAgent callAgent;
CommunicationCall call;

Knophandlers maken

Eerder hebben we 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.

Voeg de volgende code toe 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.

Naam Beschrijving
CallClient Het CallClient is het belangrijkste toegangspunt tot de oproepclientbibliotheek.
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 token-inloggegevens om de CallAgent te initialiseren.
CallAgentOptions De CallAgentOptions bevat informatie om de beller te identificeren.
HangupOptions De HangupOptions geeft aan of een oproep aan alle deelnemers moet worden beëindigd.

Videoschema-handler registreren

Een UI-onderdeel, zoals XAML's MediaElement of MediaPlayerElement, vereist dat de app 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 instantie van CallClient wilt maken, moet u de CallClient.CreateCallAgentAsync methode gebruiken 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 een uitzondering veroorzaakt als er een ongeldig token wordt doorgegeven.

Voeg de volgende code binnen en helperfunctie toe, zodat deze wordt uitgevoerd tijdens de initialisatie.

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. Zie het token voor gebruikerstoegang voor meer informatie over het ophalen van een referentietoken.

Een 1:1-gesprek met videocamera plaatsen

De objecten die nodig zijn om een CallAgent te maken, zijn nu gereed. Maak vervolgens asynchroon CallAgent en plaats een videogesprek.

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 GetStartCallOptionsAsync();
    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 LocalOutgoingVideoStream(this.viceManager.Cameras.FirstOrDefault() as VideoDeviceDetails); // Create a default video stream

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

Voorbeeld van lokale camera

We kunnen eventueel een lokale cameravoorvertoning instellen. U kunt de video weergeven via MediaPlayerElement:

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

De lokale preview MediaPlayerElement initialiseren:

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 selectedCamera = CameraList.SelectedItem as VideoDeviceDetails;
    cameraStream = new LocalOutgoingVideoStream(selectedCamera);

    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, gebruikt u de HangupAsync methode van het CommunicationCall object om de aanroep op te hangen.

Gebruik een instantie van HangupOptions om deelnemers te informeren als de oproep moet worden beëindigd.

Voeg de volgende code toe in HangupButton_Click.

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

  1. Zorg ervoor dat Visual Studio de app bouwt voor x64, x86of ARM64.
  2. Druk op F5 om de app uit te voeren.
  3. Klik op de knop CommunicationCall om een oproep naar de gedefinieerde ontvanger te plaatsen.

De eerste keer dat de app wordt uitgevoerd, vraagt het systeem de gebruiker toegang te verlenen tot de microfoon.

Volgende stappen