Hantera video under samtal
Lär dig hur du hanterar videosamtal med Azure Communication Services SDKS. Vi får lära oss hur du hanterar mottagande och sändning av video i ett samtal.
Förutsättningar
- Ett Azure-konto med en aktiv prenumeration. Skapa ett konto utan kostnad.
- En distribuerad Communication Services-resurs. Skapa en Communication Services-resurs.
- En användaråtkomsttoken för att aktivera den anropande klienten. Mer information finns i Skapa och hantera åtkomsttoken.
- Valfritt: Slutför snabbstarten för att lägga till röstsamtal i ditt program
Installera SDK:n
npm install
Använd kommandot för att installera Azure Communication Services Common och Calling SDK för JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Initiera nödvändiga objekt
En CallClient
instans krävs för de flesta anropsåtgärder. När du skapar en ny CallClient
instans kan du konfigurera den med anpassade alternativ som en Logger
instans.
Med instansen CallClient
kan du skapa en CallAgent
instans genom att anropa createCallAgent
. Den här metoden returnerar asynkront ett CallAgent
instansobjekt.
Metoden createCallAgent
använder CommunicationTokenCredential
som argument. Den accepterar en användaråtkomsttoken.
Du kan använda getDeviceManager
metoden på instansen CallClient
för att få åtkomst deviceManager
till .
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()
Så här hanterar du SDK-anslutning till Microsoft-infrastruktur på bästa sätt
Instansen Call Agent
hjälper dig att hantera anrop (för att ansluta eller starta samtal). För att kunna arbeta måste din anropande SDK ansluta till Microsofts infrastruktur för att få meddelanden om inkommande samtal och samordna annan samtalsinformation. Du Call Agent
har två möjliga tillstånd:
Ansluten – Ett Call Agent
connectionStatue-värde Connected
innebär att klient-SDK:t är anslutet och kan ta emot meddelanden från Microsofts infrastruktur.
Frånkopplad – Ett Call Agent
connectionStatue-värde för Disconnected
tillstånd det finns ett problem som hindrar SDK:n från att ansluta korrekt. Call Agent
ska återskapas.
invalidToken
: Om en token har upphört att gälla eller om en ogiltigCall Agent
instans kopplas från med det här felet.connectionIssue
: Om det finns ett problem med att klienten ansluter till Microsoft-infrastrukturen, efter att många återförsökCall Agent
har exponeratconnectionIssue
felet.
Du kan kontrollera om din lokala Call Agent
är ansluten till Microsofts infrastruktur genom att granska det aktuella värdet för connectionState
egenskapen. Under ett aktivt anrop kan du lyssna på connectionStateChanged
händelsen för att avgöra om Call Agent
det ändras från Anslutet till frånkopplat tillstånd.
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);
Enhetshantering
Om du vill börja använda video med Calling SDK måste du kunna hantera enheter. Med enheter kan du styra vad som överför ljud och video till samtalet.
deviceManager
Med kan du räkna upp lokala enheter som kan överföra dina ljud- och videoströmmar i ett samtal. Du kan också använda deviceManager
för att begära behörighet att komma åt den lokala enhetens mikrofoner och kameror.
Du kan komma åt deviceManager
genom att callClient.getDeviceManager()
anropa metoden:
const deviceManager = await callClient.getDeviceManager();
Hämta lokala enheter
Om du vill komma åt lokala enheter kan du använda uppräkningsmetoderna deviceManager
getCameras()
och getMicrophones
. Dessa metoder är asynkrona åtgärder.
// 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...]
Ange standardenheterna
När du vet vilka enheter som är tillgängliga att använda kan du ange standardenheter för mikrofon, högtalare och kamera. Om klientens standardvärden inte har angetts använder Communication Services SDK standardinställningarna för operativsystemet.
Mikrofon
Få åtkomst till den enhet som används
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
Ange vilken enhet som ska användas
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
Talare
Få åtkomst till den enhet som används
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Ange vilken enhet som ska användas
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Kamera
Få åtkomst till den enhet som används
// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Ange vilken enhet som ska användas
// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);
Var CallAgent
och en kan välja sin egen mikrofon och högtalare på sin associerade DeviceManager
. Vi rekommenderar att olika CallAgents
använder olika mikrofoner och högtalare. De bör inte dela samma mikrofoner eller högtalare. Om delning sker kan mikrofonanvändarinriktad diagnostik utlösas och mikrofonen slutar fungera beroende på webbläsaren/operativsystemet.
Lokal videoström
För att kunna skicka video i ett anrop måste du skapa ett LocalVideoStream
objekt.
const localVideoStream = new LocalVideoStream(camera);
Kameran som skickas som parameter är ett av de objekt som VideoDeviceInfo
returneras av deviceManager.getCameras()
metoden.
A LocalVideoStream
har följande egenskaper:
source
: Enhetsinformationen.
const source = localVideoStream.source;
mediaStreamType
: Kan varaVideo
,ScreenSharing
ellerRawMedia
.
const type: MediaStreamType = localVideoStream.mediaStreamType;
Förhandsgranskning av lokal kamera
Du kan använda deviceManager
och VideoStreamRenderer
börja återge strömmar från din lokala kamera.
När en LocalVideoStream
har skapats använder du den för att konfigureraVideoStreamRenderer
den. När den har skapats VideoStreamRenderer
anropar du dess createView()
metod för att hämta en vy som du kan lägga till som underordnad på sidan.
Den här strömmen skickas inte till andra deltagare. det är en lokal förhandsgranskningsfeed.
// 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);
Stoppa den lokala förhandsversionen
Om du vill stoppa det lokala förhandsgranskningsanropet gör du dig av med vyn som härleds VideoStreamRenderer
från .
När VideoStreamRenderer har kasserats tar du bort vyn från html-trädet genom att anropa removeChild()
metoden från DOM Node som innehåller din förhandsversion.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Begär behörighet till kamera och mikrofon
Ett program kan inte använda kameran eller mikrofonen utan behörighet. Du kan använda deviceManager för att uppmana en användare att bevilja kamera- och/eller mikrofonbehörigheter:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
När löftet har lösts returnerar metoden med ett DeviceAccess
objekt som anger om audio
och video
behörigheter har beviljats:
console.log(result.audio);
console.log(result.video);
Kommentar
videoDevicesUpdated
händelsen utlöses när videoenheter ansluter/kopplas från.audioDevicesUpdated
händelsen utlöses när ljudenheter är anslutna.- När DeviceManager skapas vet den först inte om några enheter om behörigheter inte har beviljats ännu, så till en början är enhetsnamnet tomt och innehåller inte detaljerad enhetsinformation. Om vi sedan anropar API:et DeviceManager.askPermission() uppmanas användaren att ange enhetsåtkomst. När användaren väljer "tillåt" för att ge åtkomst till enhetshanteraren lär sig om enheterna i systemet uppdaterar du enhetslistorna och sänder händelserna "audioDevicesUpdated" och "videoDevicesUpdated". Om en användare uppdaterar sidan och skapar en enhetshanterare kan enhetshanteraren lära sig mer om enheter eftersom användaren har beviljat åtkomst tidigare. Den har sina enhetslistor fyllda från början och avger inte "audioDevicesUpdated" eller "videoDevicesUpdated" händelser.
- Talaruppräkning/val stöds inte i Android Chrome, iOS Safari eller macOS Safari.
Ringa ett samtal med videokamera
Viktigt!
För närvarande stöds endast en utgående lokal videoström.
Om du vill ringa ett videosamtal måste du räkna upp lokala kameror med hjälp getCameras()
av metoden i deviceManager
.
När du har valt en kamera använder du den för att skapa en LocalVideoStream
instans.
Skicka det som videoOptions
ett objekt i matrisen localVideoStream
till CallAgent
startCall
-metoden.
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);
- Du kan också ansluta ett anrop med video med
CallAgent.join()
API och acceptera och anropa med video medCall.Accept()
API. - När samtalet ansluter börjar det automatiskt skicka en videoström från den valda kameran till den andra deltagaren.
Starta och sluta skicka lokal video under ett samtal
Starta video
Om du vill starta en video under ett anrop måste du räkna upp kameror med hjälp av getCameras
-metoden på deviceManager
objektet.
Skapa sedan en ny instans av LocalVideoStream
med önskad kamera och skicka LocalVideoStream
sedan objektet till startVideo
metoden för ett befintligt anropsobjekt:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Stoppa video
När du har börjat skicka video läggs en LocalVideoStream
instans av typen Video
till i localVideoStreams
samlingen på en samtalsinstans.
Hitta videoströmmen i samtalsobjektet
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );
Stoppa den lokala videon Om du vill stoppa lokal video under ett anrop skickar du den localVideoStream
instans som används för video till stopVideo-metoden för Call
:
await call.stopVideo(localVideoStream);
Du kan växla till en annan kameraenhet när du har en aktiv LocalVideoStream genom att LocalVideoStream
anropa switchSource
den instansen:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Om den angivna videoenheten inte är tillgänglig:
- Om videon är avstängd och du startar en video med ett
call.startVideo()
samtal genererar den här metoden enSourceUnavailableError
diagnostik somcameraStartFailed
är riktad mot användaren och är inställd på sant. - Ett anrop till
localVideoStream.switchSource()
metoden görcameraStartFailed
att värdet är sant. Vår guide för samtalsdiagnostik innehåller ytterligare information om hur du diagnostiserar samtalsrelaterade problem.
Om du vill kontrollera om den lokala videon är på eller av kan du använda Call
metoden isLocalVideoStarted
, som returnerar sant eller falskt:
// Check if local video is on or off
call.isLocalVideoStarted;
Om du vill lyssna efter ändringar i den lokala videon kan du prenumerera och avbryta prenumerationen på händelsen isLocalVideoStartedChanged:
// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
// Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
// Callback();
});
Starta och stoppa skärmdelning under ett samtal
Om du vill starta skärmdelning under ett anrop kan du använda den asynkrona metoden startScreenSharing()
för ett Call
objekt:
Startskärmsdelning
// Start screen sharing
await call.startScreenSharing();
Obs! Att skicka skärmdelning stöds endast i skrivbordswebbläsaren.
Hitta skärmdelningen i samlingen med LocalVideoStream
När du har börjat skicka skärmdelning läggs en LocalVideoStream
instans av typen ScreenSharing
, till i localVideoStreams
samlingen på samtalsinstansen.
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );
Stoppa skärmdelning
Om du vill stoppa skärmdelning under ett anrop kan du använda asynkron API-stoptScreenSharing:
// Stop screen sharing
await call.stopScreenSharing();
Kontrollera skärmens delningsstatus
Om du vill kontrollera om skärmdelningen är på eller av kan du använda isScreenSharingOn API, som returnerar sant eller falskt:
// Check if screen sharing is on or off
call.isScreenSharingOn;
Om du vill lyssna efter ändringar i skärmresursen kan du prenumerera på och avbryta prenumerationen på händelsen isScreenSharingOnChanged:
// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
// Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
// Callback();
});
Viktigt!
Den här funktionen i Azure Communication Services är för närvarande i förhandsversion.
Förhandsversions-API:er och SDK:er tillhandahålls utan ett serviceavtal. Vi rekommenderar att du inte använder dem för produktionsarbetsbelastningar. Vissa funktioner kanske inte stöds, eller så kan de ha begränsade funktioner.
Mer information finns i Kompletterande användningsvillkor för Förhandsversioner av Microsoft Azure.
Förhandsversionen av lokal skärmresurs är allmänt tillgänglig som en del av version 1.15.1-beta.1+.
Förhandsversion av lokal skärmresurs
Du kan använda en VideoStreamRenderer
för att börja återge strömmar från din lokala skärmresurs så att du kan se vad du skickar som en skärmdelningsström.
// 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);
}
});
Rendera video-/skärmdelningsströmmar för fjärrdeltagare
För att rendera en fjärrdeltagares video eller skärmdelning är det första steget att hämta en referens på remoteVideoStream som du vill återge.
Detta kan göras genom att gå igenom matrisen eller videoströmmen (videoStreams
) för RemoteParticipant
. Samlingen fjärrdeltagare nås via objektet Call
.
const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;
Om du vill återge RemoteVideoStream
måste du prenumerera på händelsen isAvailableChanged
. Om egenskapen isAvailable
ändras till true
skickar en fjärrdeltagare en videoström.
När det händer skapar du en ny instans av VideoStreamRenderer
och skapar sedan en ny VideoStreamRendererView
instans med hjälp av den asynkrona createView
metoden.
Du kan sedan ansluta view.target
till valfritt gränssnittselement.
När tillgängligheten för en fjärrström ändras kan du förstöra hela VideoStreamRenderer
eller en specifik VideoStreamRendererView
.
Om du bestämmer dig för att behålla dem visar vyn en tom videoram.
// 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 för att formatera inläsningssnurran över fjärrvideoströmmen.
.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); }
}
Fjärrvideokvalitet
Azure Communication Services WebJS SDK innehåller en funktion som heter Optimal Video Count (OVC), med början i version 1.15.1.
Den här funktionen kan användas för att informera program vid körning om hur många inkommande videor från olika deltagare som kan återges optimalt vid en viss tidpunkt i ett gruppsamtal (2+ deltagare).
Den här funktionen exponerar en egenskap optimalVideoCount
som ändras dynamiskt under anropet baserat på nätverks- och maskinvarufunktionerna i en lokal slutpunkt. Värdet för optimalVideoCount
information om hur många videor från olika deltagarprogram som ska återges vid en viss tidpunkt. Program bör hantera dessa ändringar och uppdatera antalet renderade videor i enlighet med rekommendationen. Det finns en bounce-period (cirka 10 s) mellan varje uppdatering.
Användning Funktionen optimalVideoCount
är en samtalsfunktion. Du måste referera till funktionen OptimalVideoCount
via feature
-metoden för Call
objektet. Du kan sedan ange en lyssnare via on
metoden för att OptimalVideoCountCallFeature
meddelas när optimalVideoCount ändras. Om du vill avbryta prenumerationen på ändringarna kan du anropa off
metoden. Det aktuella maximala antalet inkommande videor som kan återges är 16. För att korrekt stödja 16 inkommande videor datorn bör ha en mimimum av 16GB RAM och en 4-kärnor eller större CPU som inte är äldre än 3 år gammal.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Exempel på användning: Programmet bör prenumerera på ändringar av optimalt videoantal i gruppanrop. En ändring av det optimala videoantalet kan hanteras genom att antingen skapa en ny renderare (createView
metod) eller ta bort vyer (dispose
) och uppdatera programlayouten i enlighet med detta.
Egenskaper för fjärrvideoström
Fjärrvideoströmmar har följande egenskaper:
const id: number = remoteVideoStream.id;
id
: ID för en fjärrvideoström.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
mediaStreamType
: Kan varaVideo
ellerScreenSharing
.
const isAvailable: boolean = remoteVideoStream.isAvailable;
isAvailable
: Definierar om en fjärrdeltagares slutpunkt aktivt skickar en dataström.
const isReceiving: boolean = remoteVideoStream.isReceiving;
isReceiving
:Informerar programmet om fjärrdata för videoströmmar tas emot eller inte.
Flaggan flyttas till
false
i följande scenarier:- En fjärrdeltagare som är i en mobil webbläsare tar webbläsarappen till bakgrunden.
- En fjärrdeltagare eller den användare som tar emot videon har nätverksproblem som drastiskt påverkar videokvaliteten.
- En fjärrdeltagare som är På macOS/iOS Safari väljer "Pausa" från adressfältet.
- En fjärrdeltagare har en nätverkskoppling.
- En fjärrdeltagare på mobilen dödar eller avslutar webbläsaren.
- En fjärrdeltagare på mobilen eller skrivbordet låser enheten. Det här scenariot gäller även om fjärrdeltagaren är på en stationär dator och den försätts i viloläge.
Flaggan flyttas till
true
i följande scenarier:- En fjärransluten deltagare som är i mobil webbläsare och har sin webbläsare bakgrund tar den tillbaka till förgrunden.
- En fjärrdeltagare som är På macOS/iOS Safari väljer "Återuppta" från adressfältet efter att ha pausat videon.
- En fjärrdeltagare återansluter till nätverket efter en tillfällig frånkoppling.
- En fjärrdeltagare på mobilen låser upp sin enhet och återgår till samtalet i sin mobila webbläsare.
Den här funktionen förbättrar användarupplevelsen för återgivning av fjärrvideoströmmar.
Du kan visa en inläsningssnurra över fjärrvideoströmmen när isReceiving-flaggan ändras till false. Du behöver inte implementera inläsningsspinnare, men en inläsningssnurrare är den vanligaste användningen för bättre användarupplevelse.
const size: StreamSize = remoteVideoStream.size;
size
: Strömstorleken med information om videons bredd och höjd.
VideoStreamRenderer-metoder och egenskaper
await videoStreamRenderer.createView();
Skapa en VideoStreamRendererView
instans som kan kopplas i programmets användargränssnitt för att återge fjärrvideoströmmen, använda asynkron createView()
metod, den löser när strömmen är redo att återges och returnerar ett objekt med target
en egenskap som representerar video
element som kan infogas var som helst i DOM-trädet.
videoStreamRenderer.dispose();
Ta bort videoStreamRenderer
och alla associerade VideoStreamRendererView
instanser.
VideoStreamRendererView-metoder och egenskaper
När du skapar en VideoStreamRendererView
kan du ange scalingMode
egenskaperna och isMirrored
. scalingMode
kan vara Stretch
, Crop
eller Fit
. Om isMirrored
anges, vänds den renderade strömmen lodrätt.
const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });
Varje VideoStreamRendererView
instans har en target
egenskap som representerar återgivningsytan. Bifoga den här egenskapen i programmets användargränssnitt:
htmlElement.appendChild(view.target);
Du kan uppdatera scalingMode
genom att updateScalingMode
anropa metoden:
view.updateScalingMode('Crop');
Skicka videoströmmar från två olika kameror i samma anrop från samma skrivbordsenhet.
Viktigt!
Den här funktionen i Azure Communication Services är för närvarande i förhandsversion.
Förhandsversions-API:er och SDK:er tillhandahålls utan ett serviceavtal. Vi rekommenderar att du inte använder dem för produktionsarbetsbelastningar. Vissa funktioner kanske inte stöds, eller så kan de ha begränsade funktioner.
Mer information finns i Kompletterande användningsvillkor för Förhandsversioner av Microsoft Azure.
Skicka videoströmmar från två olika kameror i samma anrop stöds som en del av version 1.17.1-beta.1+ på webbläsare som stöds av skrivbordet.
- Du kan skicka videoströmmar från två olika kameror från en enda skrivbordswebbläsares flik/app, i samma anrop, med följande kodfragment:
// 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();
Begränsningar:
- Detta måste göras med två olika
CallAgent
instanser med olika identiteter. Kodfragmentet visar två samtalsagenter som används, var och en med sitt eget anropsobjekt. - I kodexemplet ansluter båda CallAgents samma anrop (samma anrops-ID). Du kan också ansluta olika samtal med varje agent och skicka en video på ett samtal och en annan video i det andra samtalet.
- Det går inte att skicka samma kamera i båda CallAgent. De måste vara två olika kameror.
- Det finns för närvarande inte stöd för att skicka två olika kameror med en CallAgent.
- På macOS Safari kan videoeffekter med bakgrundsoskärpa (från @azure/communication-effects), endast tillämpas på en kamera och inte båda samtidigt.
Installera SDK:n
Leta upp filen på projektnivå build.gradle
och lägg till mavenCentral()
i listan med lagringsplatser under buildscript
och allprojects
:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Lägg sedan till följande rader i modulnivåfilen build.gradle
i dependencies
avsnittet:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Initiera nödvändiga objekt
Om du vill skapa en CallAgent
instans måste du anropa createCallAgent
metoden på en CallClient
instans. Det här anropet returnerar asynkront ett CallAgent
instansobjekt.
Metoden createCallAgent
tar CommunicationUserCredential
som ett argument som kapslar in en åtkomsttoken.
Om du vill komma åt DeviceManager
måste du skapa en callAgent
instans först. Sedan kan du använda CallClient.getDeviceManager
metoden för att hämta 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();
Om du vill ange ett visningsnamn för anroparen använder du den här alternativa metoden:
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();
Enhetshantering
Om du vill börja använda video med Samtal måste du veta hur du hanterar enheter. Med enheter kan du styra vad som överför ljud och video till samtalet.
DeviceManager
låter dig räkna upp lokala enheter som kan användas i ett anrop för att överföra dina ljud-/videoströmmar. Du kan också begära behörighet från en användare för att få åtkomst till deras mikrofon och kamera med hjälp av det interna webbläsar-API:et.
Du kan komma åt deviceManager
genom att anropa callClient.getDeviceManager()
metoden.
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Räkna upp lokala enheter
Om du vill komma åt lokala enheter kan du använda uppräkningsmetoder på Enhetshanteraren. Uppräkning är en synkron åtgärd.
// Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
Förhandsgranskning av lokal kamera
Du kan använda DeviceManager
och Renderer
börja återge strömmar från din lokala kamera. Den här strömmen skickas inte till andra deltagare. det är en lokal förhandsgranskningsfeed. Det här är en asynkron åtgärd.
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);
Ringa ett 1:1-samtal med videokamera
Varning
För närvarande stöds endast en utgående lokal videoström För att kunna ringa ett samtal med video måste du räkna upp lokala kameror med hjälp av API:et deviceManager
getCameras
.
När du har valt en önskad kamera använder du den för att konstruera en LocalVideoStream
instans och skicka den till videoOptions
som ett objekt i matrisen localVideoStream
till en call
metod.
När samtalet ansluter börjar det automatiskt skicka en videoström från den valda kameran till andra deltagare.
Kommentar
På grund av sekretessproblem delas inte video till samtalet om det inte förhandsgranskas lokalt. Mer information finns i Förhandsversion av lokal kamera.
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);
Starta och sluta skicka lokal video
Om du vill starta en video måste du räkna upp kameror med hjälp av API:et getCameraList
på deviceManager
objektet. Skapa sedan en ny instans av LocalVideoStream
att skicka den önskade kameran och skicka den i API:et startVideo
som ett argument:
VideoDeviceInfo desiredCamera = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();
LocalVideoStream currentLocalVideoStream = new LocalVideoStream(desiredCamera, appContext);
VideoOptions videoOptions = new VideoOptions(currentLocalVideoStream);
Future startVideoFuture = call.startVideo(appContext, currentLocalVideoStream);
startVideoFuture.get();
När du har börjat skicka video läggs en LocalVideoStream
instans till i localVideoStreams
samlingen på samtalsinstansen.
List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).
Om du vill stoppa lokal video skickar du instansen som LocalVideoStream
är tillgänglig i localVideoStreams
samlingen:
call.stopVideo(appContext, currentLocalVideoStream).get();
Du kan växla till en annan kameraenhet medan video skickas genom att switchSource
anropa på en LocalVideoStream
instans:
currentLocalVideoStream.switchSource(source).get();
Rendera videoströmmar för fjärrdeltagare
Om du vill visa en lista över videoströmmar och skärmdelningsströmmar för fjärranslutna deltagare kontrollerar du samlingarna videoStreams
:
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
Om du vill återge en RemoteVideoStream
från en fjärrdeltagare måste du prenumerera på en OnVideoStreamsUpdated
händelse.
I händelsen indikerar ändringen av isAvailable
egenskapen till true att fjärrdeltagare för närvarande skickar en ström. När det händer skapar du en ny instans av en Renderer
och skapar sedan en ny RendererView
med hjälp av asynkront createView
API och kopplar view.target
var som helst i programmets användargränssnitt.
När tillgängligheten för en fjärrström ändras kan du välja att förstöra hela renderaren, en specifik RendererView
eller behålla dem, men detta resulterar i att en tom videoram visas.
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();
}
}
}
Egenskaper för fjärrvideoström
Fjärrvideoström har ett par egenskaper
Id
– ID för en fjärrvideoström
int id = remoteVideoStream.getId();
MediaStreamType
– Kan vara "Video" eller "ScreenSharing"
MediaStreamType type = remoteVideoStream.getMediaStreamType();
isAvailable
– Anger om fjärrdeltagarens slutpunkt aktivt skickar ström
boolean availability = remoteVideoStream.isAvailable();
Återgivningsmetoder och egenskaper
Renderarobjekt efter API:er
- Skapa en
VideoStreamRendererView
instans som kan kopplas senare i programmets användargränssnitt för att återge fjärrvideoström.
// Create a view for a video stream
VideoStreamRendererView.createView()
- Ta bort renderaren och alla
VideoStreamRendererView
som är associerade med den här renderaren. Anropas när du har tagit bort alla associerade vyer från användargränssnittet.
VideoStreamRenderer.dispose()
StreamSize
– storlek (bredd/höjd) för en fjärransluten videoström
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();
RendererView-metoder och egenskaper
När du skapar en VideoStreamRendererView
kan du ange egenskaperna ScalingMode
och mirrored
som ska gälla för den här vyn: Skalningsläget kan vara något av "CROP" | "FIT"
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));
Den skapade RendererView kan sedan kopplas till programmets användargränssnitt med hjälp av följande kodfragment:
layout.addView(rendererView);
Du kan senare uppdatera skalningsläget genom att updateScalingMode
anropa API:et i RendererView-objektet med ett av ScalingMode.CROP | ScalingMode.FIT som argument.
// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)
Konfigurera systemet
Följ de här stegen för att konfigurera systemet.
Skapa Xcode-projektet
I Xcode skapar du ett nytt iOS-projekt och väljer mallen Enkel vyapp . Den här artikeln använder SwiftUI-ramverket, så du bör ange Language till Swift och ange Gränssnitt till SwiftUI.
Du kommer inte att skapa tester i den här artikeln. Avmarkera kryssrutan Inkludera tester .
Installera paketet och beroenden med hjälp av CocoaPods
Skapa en Podfile för ditt program, som i det här exemplet:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Kör
pod install
.Öppna
.xcworkspace
med Xcode.
Begär åtkomst till mikrofonen
För att få åtkomst till enhetens mikrofon måste du uppdatera appens egenskapslista för information med hjälp NSMicrophoneUsageDescription
av . Ange det associerade värdet till en sträng som ingår i dialogrutan som systemet använder för att begära åtkomst från användaren.
Högerklicka på posten Info.plist i projektträdet och välj sedan Öppna som>källkod. Lägg till följande rader i avsnittet på den översta nivån <dict>
och spara sedan filen.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Konfigurera appramverket
Öppna projektets ContentView.swift
fil. Lägg till en import
deklaration överst i filen för att importera AzureCommunicationCalling
biblioteket. Importera dessutom AVFoundation
. Du behöver den för begäranden om ljudbehörighet i koden.
import AzureCommunicationCalling
import AVFoundation
Initiera CallAgent
Om du vill skapa en CallAgent
instans från CallClient
måste du använda en callClient.createCallAgent
metod som asynkront returnerar ett CallAgent
objekt när det har initierats.
Skicka ett CommunicationTokenCredential
objekt för att skapa en anropsklient:
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)
}
Skicka objektet CommunicationTokenCredential
som du skapade till CallClient
och ange visningsnamnet:
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")
}
})
Hantera enheter
Om du vill börja använda video med Samtal måste du veta hur du hanterar enheter. Med enheter kan du styra vad som överför ljud och video till samtalet.
DeviceManager
låter dig räkna upp lokala enheter som kan användas i ett anrop för att överföra ljud- eller videoströmmar. Du kan också begära behörighet från en användare för att få åtkomst till en mikrofon eller kamera. Du kan komma åt deviceManager
objektet callClient
.
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")
}
}
Räkna upp lokala enheter
Om du vill komma åt lokala enheter kan du använda uppräkningsmetoder i enhetshanteraren. Uppräkning är en synkron åtgärd.
// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]
Hämta en lokal kameraförhandsvisning
Du kan använda Renderer
för att börja återge en ström från din lokala kamera. Den här strömmen skickas inte till andra deltagare. det är en lokal förhandsgranskningsfeed. Det här är en asynkron åtgärd.
let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()
Hämta egenskaper för lokal kameraförhandsgranskning
Renderaren har en uppsättning egenskaper och metoder som gör att du kan styra återgivningen.
// 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()
Ringa ett 1:1-samtal med video
Information om hur du hämtar en instans av enhetshanteraren finns i avsnittet om att hantera enheter.
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")
}
}
Rendera videoströmmar för fjärrdeltagare
Fjärrdeltagare kan initiera video- eller skärmdelning under ett samtal.
Hantera videodelnings- eller skärmdelningsströmmar för fjärranslutna deltagare
Granska samlingarna om du vill visa en lista över strömmarna för fjärranslutna videoStreams
deltagare.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Hämta egenskaper för fjärrvideoström
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
Rendera fjärrdeltagareströmmar
Om du vill börja återge fjärrdeltagareströmmar använder du följande kod.
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)
Hämta metoder och egenskaper för fjärrvideoåtergivning
// [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()
Konfigurera systemet
Följ de här stegen för att konfigurera systemet.
Skapa Visual Studio-projektet
För en Universell Windows-plattform app skapar du i Visual Studio 2022 ett nytt projekt för Tom app (Universell Windows). När du har angett projektnamnet kan du välja valfri Windows SDK senare än 10.0.17763.0.
För en WinUI 3-app skapar du ett nytt projekt med mallen Tom app, Paketerad (WinUI 3 i Desktop) för att konfigurera en WinUI 3-app med en enda sida. SDK för Windows-appar version 1.3 eller senare krävs.
Installera paketet och beroendena med hjälp av NuGet Package Manager
Anropande SDK-API:er och bibliotek är offentligt tillgängliga via ett NuGet-paket.
Så här hittar du, laddar ned och installerar det anropande SDK NuGet-paketet:
- Öppna NuGet Package Manager genom att välja Verktyg>NuGet Package Manager>Hantera NuGet-paket för lösning.
- Välj Bläddra och ange sedan Azure.Communication.Calling.WindowsClient i sökrutan.
- Kontrollera att kryssrutan Inkludera förhandsversion är markerad.
- Välj paketet Azure.Communication.Calling.WindowsClient och välj sedan Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 eller en nyare version.
- Markera kryssrutan som motsvarar Azure Communication Services-projektet i den högra rutan.
- Välj Installera.
Begär åtkomst till mikrofonen
Appen kräver åtkomst till kameran för att kunna köras korrekt. I UWP-appar ska kamerafunktionen deklareras i appens manifestfil.
Följande steg illustrerar hur du kan uppnå detta.
- Dubbelklicka på filen med
.appxmanifest
filnamnstilläggetSolution Explorer
i panelen. - Klicka på fliken
Capabilities
. - Markera kryssrutan
Camera
i listan över funktioner.
Skapa användargränssnittsknappar för att placera och lägga på anropet
Den här enkla exempelappen innehåller två knappar. En för att ringa samtalet och en annan för att hänga upp ett uppringt samtal. Följande steg illustrerar hur du lägger till dessa knappar i appen.
Solution Explorer
Dubbelklicka på filen med namnetMainPage.xaml
UWP i panelen ellerMainWindows.xaml
för WinUI 3.- I den centrala panelen letar du efter XAML-koden under förhandsversionen av användargränssnittet.
- Ändra XAML-koden med följande utdrag:
<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>
Konfigurera appen med anropande SDK-API:er
Api:erna för anropande SDK finns i två olika namnområden. Följande steg informerar C#-kompilatorn om dessa namnområden så att Visual Studio Intellisense kan hjälpa till med kodutveckling.
- I panelen
Solution Explorer
klickar du på pilen till vänster i filen med namnetMainPage.xaml
UWP ellerMainWindows.xaml
för WinUI 3. - Dubbelklicka på filen med namnet
MainPage.xaml.cs
ellerMainWindows.xaml.cs
. - Lägg till följande kommandon längst ned i de aktuella
using
instruktionerna.
using Azure.Communication.Calling.WindowsClient;
Behåll MainPage.xaml.cs
eller MainWindows.xaml.cs
öppna. Nästa steg lägger till mer kod i den.
Tillåt appinteraktioner
Användargränssnittsknapparna som tidigare lagts till måste fungera ovanpå en placerad CommunicationCall
. Det innebär att en CommunicationCall
datamedlem ska läggas till i MainPage
klassen eller MainWindow
.
För att den asynkrona åtgärden som skapas CallAgent
ska lyckas bör en CallAgent
datamedlem dessutom läggas till i samma klass.
Lägg till följande datamedlemmar i MainPage
klassen eller MainWindow
:
CallAgent callAgent;
CommunicationCall call;
Skapa knapphanterare
Tidigare lades två användargränssnittsknappar till i XAML-koden. Följande kod lägger till de hanterare som ska köras när en användare väljer knappen. Följande kod ska läggas till efter datamedlemmarna från föregående avsnitt.
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start call
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// End the current call
}
Objektmodell
Följande klasser och gränssnitt hanterar några av de viktigaste funktionerna i Azure Communication Services Calling-klientbiblioteket för UWP.
Name | beskrivning |
---|---|
CallClient |
CallClient är huvudinmatningspunkten till klientbiblioteket För samtal. |
CallAgent |
CallAgent Används för att starta och ansluta anrop. |
CommunicationCall |
CommunicationCall Används för att hantera placerade eller anslutna anrop. |
CommunicationTokenCredential |
CommunicationTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent . |
CallAgentOptions |
CallAgentOptions Innehåller information för att identifiera anroparen. |
HangupOptions |
Informerar HangupOptions om ett samtal ska avslutas till alla dess deltagare. |
Registrera videoschemahanterare
En UI-komponent, till exempel XAML:s MediaElement eller MediaPlayerElement, behöver appen registrera en konfiguration för återgivning av lokala och fjärranslutna videoflöden.
Lägg till följande innehåll mellan taggarna Package
i Package.appxmanifest
:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
Initiera CallAgent
Om du vill skapa en CallAgent
instans från CallClient
måste du använda CallClient.CreateCallAgentAsync
en metod som asynkront returnerar ett CallAgent
objekt när det har initierats.
Om du vill skapa CallAgent
måste du skicka ett CallTokenCredential
objekt och ett CallAgentOptions
objekt. Tänk på att CallTokenCredential
genererar om en felaktig token skickas.
Följande kod bör läggas till i och hjälpfunktionen som ska anropas i appinitiering.
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;
Ändra med en giltig token för autentiseringsuppgifter för resursen <AUTHENTICATION_TOKEN>
. Se dokumentationen för användaråtkomsttoken om en token för autentiseringsuppgifter måste hämtas.
Ringa ett 1:1-samtal med videokamera
De objekt som behövs för att skapa en CallAgent
är nu klara. Det är dags att asynkront skapa CallAgent
och placera ett videosamtal.
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 } }
};
}
Förhandsgranskning av lokal kamera
Vi kan också konfigurera lokal kameraförhandsvisning. Videon kan återges via MediaPlayerElement
:
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
Så här initierar du den lokala förhandsversionen MediaPlayerElement
:
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);
}
}
Rendera fjärrkameraström
Konfigurera en jämn hanterare som OnCallsUpdated
svar på händelse:
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;
}
}
Börja återge fjärrvideoström på 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;
}
}
Avsluta samtal
När ett anrop har placerats HangupAsync
ska -metoden CommunicationCall
för objektet användas för att lägga på anropet.
En instans av HangupOptions
bör också användas för att informera om samtalet måste avslutas till alla deltagare.
Följande kod bör läggas till i 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;
}
}
}
}
Kör koden
Se till att Visual Studio skapar appen för , x86
eller ARM64
och tryck F5
sedan på för x64
att börja köra appen. Därefter klickar du på CommunicationCall
knappen för att ringa ett anrop till den definierade anropare.
Tänk på att första gången appen körs uppmanar systemet användaren att bevilja åtkomst till mikrofonen.