Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Lernen Sie, wie Sie Videoanrufe mit den Azure Communication Services SDKS verwalten können. Sie lernen, wie Sie den Empfang und das Senden von Videos während eines Anrufs verwalten können.
Voraussetzungen
- Ein Azure-Konto mit einem aktiven Abonnement. Sie können kostenlos ein Konto erstellen.
- Eine bereitgestellte Communication Services-Ressource. Erstellen Sie eine Communication Services-Ressource.
- Ein Benutzerzugriffstoken zum Aktivieren des Anrufclients. Weitere Informationen finden Sie unter Erstellen und Verwalten von Zugriffstoken.
- Optional: Arbeiten Sie den Schnellstart zum Hinzufügen von Sprachanrufen zu Ihrer Anwendung durch.
Das SDK installieren
Verwenden Sie den Befehl npm install
, um die Common und Calling SDKs von Azure Communication Services für JavaScript zu installieren:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Initialisieren erforderlicher Objekte
Für die meisten Anrufvorgänge ist eine CallClient
-Instanz erforderlich. Wenn Sie eine neue CallClient
-Instanz erstellen, können Sie diese mit benutzerdefinierten Optionen wie einer Logger
-Instanz konfigurieren.
Mit der CallClient
-Instanz können Sie eine CallAgent
-Instanz erstellen, indem Sie die createCallAgent
aufrufen. Durch diese Methode wird ein CallAgent
-Instanzobjekt asynchron zurückgegeben.
Die Methode createCallAgent
verwendet CommunicationTokenCredential
als Argument, welches ein Benutzerzugriffstoken akzeptiert.
Sie können die Methode getDeviceManager
für die Instanz CallClient
verwenden, um auf deviceManager
zuzugreifen.
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()
Verwalten der SDK-Konnektivität mit der Microsoft-Infrastruktur
Die Call Agent
-Instanz unterstützt Sie bei der Verwaltung von Anrufen (Annehmen oder Starten von Anrufen). Damit Ihr Calling SDK funktioniert, muss eine Verbindung mit der Microsoft-Infrastruktur hergestellt werden, um Benachrichtigungen über eingehende Anrufe zu erhalten und andere Anrufdetails zu koordinieren. Ihre Call Agent
-Instanz kann zwei Status haben:
Connected (Verbunden) – Der connectionState-Wert Call Agent
für Connected
bedeutet, dass das Client-SDK verbunden ist und Benachrichtigungen von der Microsoft-Infrastruktur empfangen kann.
Disconnected (Getrennt) – Der connectionState-Wert Call Agent
für Disconnected
weist darauf hin, dass das SDK nicht ordnungsgemäß verbunden werden kann.
Call Agent
muss neu erstellt werden.
-
invalidToken
: Wenn ein Token abgelaufen oder ungültig ist, trennt sich dieCall Agent
-Instanz aufgrund dieses Fehlers. -
connectionIssue
: Wenn ein Problem mit der Verbindung zwischen dem Client und der Microsoft-Infrastruktur auftritt, gibtCall Agent
nach mehreren Versuchen denconnectionIssue
-Fehler zurück.
Sie können überprüfen, ob Ihre lokale Call Agent
-Instanz mit der Microsoft-Infrastruktur verbunden ist, indem Sie den aktuellen Wert der connectionState
-Eigenschaft prüfen. Während eines aktiven Anrufs können Sie auf das connectionStateChanged
-Ereignis lauschen, um zu bestimmen, ob sich der Call Agent
-Status von Connected in Disconnected ändert.
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);
Geräteverwaltung
Wenn Sie Video mit dem Calling SDK verwenden möchten, müssen Sie Geräte verwalten können. Geräte ermöglichen es Ihnen, zu steuern, was Audio und Video an den Anruf überträgt.
Verwenden Sie die deviceManager
Informationen zum Aufzählen lokaler Geräte, die Audio- und Videodatenströme in einem Anruf übertragen können. Außerdem können Sie mit deviceManager
die Berechtigung für den Zugriff auf die Mikrofone und Kameras des lokalen Geräts anfordern.
Sie können auf deviceManager
zugreifen, indem Sie die Methode callClient.getDeviceManager()
aufrufen:
const deviceManager = await callClient.getDeviceManager();
Abrufen lokaler Geräte
Für den Zugriff auf lokale Geräte können Sie die deviceManager
-Enumerationsmethoden getCameras()
und getMicrophones
verwenden. Diese Methoden sind asynchrone Aktionen.
// 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...]
Festlegen der Standardgeräte
Sobald Sie wissen, welche Geräte zur Verfügung stehen, können Sie Standardgeräte für Mikrofon, Lautsprecher und Kamera festlegen. Wenn keine Clientstandardwerte festgelegt sind, verwendet das Communication Services SDK die Standardwerte des Betriebssystems.
Mikrofon
Zugreifen auf das verwendete Gerät
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
Festlegen des zu verwendenden Geräts
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
Referent
Zugreifen auf das verwendete Gerät
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Festlegen des zu verwendenden Geräts
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Kamera
Zugreifen auf das verwendete Gerät
// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Festlegen des zu verwendenden Geräts
// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);
Jeder CallAgent
kann sein eigenes Mikrofon und seine eigenen Lautsprecher auf seinem zugeordneten DeviceManager
auswählen. Es wird empfohlen, dass verschiedene CallAgents
unterschiedliche Mikrofone und Lautsprecher verwenden. Sie sollten nicht dieselben Mikrofone oder Lautsprecher gemeinsam nutzen. Eine gemeinsame Nutzung kann dazu führen, dass eine benutzerseitige Diagnose (UFD) des Mikrofons ausgelöst wird und das Mikrofon je nach Browser bzw. Betriebssystem nicht mehr funktioniert.
Lokaler Videostream
Damit Benutzer Video in einem Anruf senden können, müssen Sie ein LocalVideoStream
Objekt erstellen.
const localVideoStream = new LocalVideoStream(camera);
Die als Parameter übergebene Kamera ist ein VideoDeviceInfo
Objekt, das von der deviceManager.getCameras()
Methode zurückgegeben wird.
Ein LocalVideoStream
hat folgende Eigenschaften:
source
ist die Geräteinformationen.const source = localVideoStream.source;
mediaStreamType
kannVideo
,ScreenSharing
oderRawMedia
sein.const type: MediaStreamType = localVideoStream.mediaStreamType;
Vorschau auf lokaler Kamera
Sie können deviceManager
und VideoStreamRenderer
verwenden, um mit dem Rendern von Streams über Ihre lokale Kamera zu beginnen.
Verwenden Sie sie nach dem Erstellen von LocalVideoStream
, um VideoStreamRenderer
einzurichten. Sobald Sie das VideoStreamRenderer
erstellt haben, rufen Sie dessen createView()
Methode auf, um eine Ansicht zu erhalten, die Sie Ihrer Seite als untergeordnetes Element hinzufügen können.
Dieser Datenstrom wird nicht an andere Teilnehmer gesendet. Es ist ein lokaler Vorschaufeed.
// 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);
Beenden der lokalen Vorschau
Um den lokalen Vorschauanruf zu beenden, löschen Sie die von VideoStreamRenderer
abgeleitete Ansicht.
Entfernen Sie nach dem Löschen des Videostream-Renderers die Ansicht aus der HTML-Struktur, indem Sie die removeChild()
-Methode über den DOM-Knoten aufrufen, der Ihre Vorschau enthält.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Anfordern der Berechtigung für Kamera und Mikrofon
Eine Anwendung kann die Kamera oder das Mikrofon nicht ohne Berechtigungen verwenden. Sie können den Geräte-Manager verwenden, um Benutzer aufzufordern, Berechtigungen für die Kamera und/oder für das Mikrofon zu erteilen:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
Nach Auflösung der Zusage gibt die Methode ein DeviceAccess
-Objekt zurück, das angibt, ob audio
- und video
-Berechtigungen erteilt wurden:
console.log(result.audio);
console.log(result.video);
Hinweise
-
Das
videoDevicesUpdated
-Ereignis wird ausgelöst, wenn Videogeräte angeschlossen/entfernt werden. -
Das
audioDevicesUpdated
-Ereignis wird ausgelöst, wenn Audiogeräte angeschlossen werden. - Wenn Sie
DeviceManager
zum ersten Mal erstellen, hat es keine Kenntnis über Geräte, sofern nicht bereits Berechtigungen erteilt wurden. Der Gerätename ist zunächst leer und enthält keine detaillierten Geräteinformationen. Sie müssenDeviceManager.askPermission()
aufrufen, um den Benutzer zur Gewährung des Gerätezugriffs aufzufordern. Wenn der Benutzer den Zugriff zulässt, lernt der Geräte-Manager mehr über die Geräte auf dem System, aktualisiert die Gerätelisten und sendet dieaudioDevicesUpdated
- undvideoDevicesUpdated
-Ereignisse. Wenn ein Benutzer die Seite aktualisiert und einen Geräte-Manager erstellt, lernt der Geräte-Manager mehr über Geräte, da der Benutzer zuvor Zugriff gewährt hat. Die Gerätelisten des Geräte-Managers sind bereits ausgefüllt und der Geräte-Manager löst keineaudioDevicesUpdated
- odervideoDevicesUpdated
-Ereignisse aus. - Die Enumeration/Auswahl von Sprechern wird unter Android Chrome, iOS Safari und macOS Safari nicht unterstützt.
Einen Videoanruf tätigen
Wichtig
Derzeit wird nur ein ausgehender lokaler Videostream unterstützt.
Zum Tätigen eines Videoanrufs müssen lokale Kameras mithilfe der Methode getCameras()
in deviceManager
aufgezählt werden.
Nachdem Sie eine Kamera ausgewählt haben, verwenden Sie sie, um eine LocalVideoStream
-Instanz zu erstellen.
Übergeben Sie sie in videoOptions
als Element innerhalb des localVideoStream
-Arrays an die CallAgent
startCall
-Methode.
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
const placeCallOptions = {videoOptions: {localVideoStreams:[localVideoStream]}};
const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const call = callAgent.startCall([userCallee], placeCallOptions);
- Sie können auch mit der
CallAgent.join()
-API an einem Videoanruf teilnehmen und mit derCall.Accept()
-API Videoanrufe akzeptieren und tätigen. - Sobald die Anrufverbindung hergestellt ist, wird automatisch ein Videostream von der ausgewählten Kamera an den anderen Teilnehmer gesendet.
Starten und Beenden des Sendens eines lokalen Videosignals während eines Anrufs
Video starten
Um während eines Anrufs ein Video zu starten, müssen Sie Kameras mit der getCameras
-Methode für das deviceManager
-Objekt aufzählen.
Erstellen Sie dann eine neue Instanz von LocalVideoStream
mit der gewünschten Kamera, und übergeben Sie anschließend das Objekt LocalVideoStream
an die Methode startVideo
eines vorhandenen Anrufobjekts:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Video beenden
Sobald Videodaten erfolgreich gesendet werden, wird eine LocalVideoStream
-Instanz vom Typ Video
der localVideoStreams
-Sammlung für eine Anrufinstanz hinzugefügt.
Suchen des Videostreams im Call-Objekt
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );
Beenden des lokalen Videos Um das lokale Video während eines Anrufs zu beenden, übergeben Sie die localVideoStream
-Instanz, die für Video verwendet wird, an die stopVideo-Methode des Call
-Objekts:
await call.stopVideo(localVideoStream);
Sie können zu einem anderen Kameragerät wechseln, während ein lokaler Videostream aktiv ist, indem Sie switchSource
für die entsprechende LocalVideoStream
-Instanz aufrufen:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Falls das angegebene Videogerät nicht verfügbar ist, gilt Folgendes:
- Wenn Ihr Video deaktiviert ist und Sie ein Video mithilfe von
call.startVideo()
beginnen, löst diese Methode eineSourceUnavailableError
aus und legt diecameraStartFailed
-Benutzerdiagnose auf „true“ fest. - Ein Aufruf an die
localVideoStream.switchSource()
-Methode bewirkt, dasscameraStartFailed
auf „true“ festgelegt wird. Unser Leitfaden zur Anrufdiagnose enthält zusätzliche Informationen zum Diagnostizieren von Problemen im Zusammenhang mit Anrufen.
Um zu überprüfen, ob das lokale Video aktiviert oder deaktiviert ist, können Sie die Call
-Methode isLocalVideoStarted
verwenden. Diese gibt entweder „true“ oder „false“ zurück:
// Check if local video is on or off
call.isLocalVideoStarted;
Zum Lauschen auf Änderungen am lokalen Video können Sie das isLocalVideoStartedChanged-Ereignis abonnieren bzw. kündigen:
// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
// Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
// Callback();
});
Starten und Beenden der Bildschirmfreigabe in einem Anruf
Um die Bildschirmfreigabe während eines Anrufs zu starten, können Sie die asynchrone Methode startScreenSharing()
für ein Call
-Objekt verwenden:
Starten der Bildschirmfreigabe
// Start screen sharing
await call.startScreenSharing();
Hinweis
Das Senden von Bildschirmfreigaben wird nur für Desktopbrowser unterstützt.
Suchen der Bildschirmfreigabe in der Auflistung von „LocalVideoStream“
Nachdem Sie erfolgreich mit dem Senden der Bildschirmfreigabe begonnen haben, wird eine LocalVideoStream
-Instanz des Typs ScreenSharing
der localVideoStreams
-Sammlung in der Anrufinstanz hinzugefügt.
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );
Beenden der Bildschirmfreigabe
Um die Bildschirmfreigabe während eines Aufrufs zu beenden, können Sie asynchrone API stoptScreenSharing verwenden:
// Stop screen sharing
await call.stopScreenSharing();
Überprüfen des Status der Bildschirmfreigabe
Zur Überprüfung, ob die Bildschirmfreigabe aktiviert oder deaktiviert ist, können Sie die isScreenSharingOn-API verwenden, die TRUE oder FALSE zurückgibt:
// Check if screen sharing is on or off
call.isScreenSharingOn;
Zum Lauschen auf Änderungen an der Bildschirmfreigabe können Sie das isScreenSharingOnChanged-Ereignis abonnieren bzw. kündigen:
// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
// Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
// Callback();
});
Wichtig
Dieses Feature von Azure Communication Services befindet sich derzeit in der Vorschau. Features in der Vorschau sind öffentlich verfügbar und können von allen neuen und vorhandenen Microsoft-Kunden verwendet werden.
Vorschau-APIs und -SDKs werden ohne Vereinbarung zum Servicelevel bereitgestellt. Es wird empfohlen, diese nicht für Produktionsworkloads zu verwenden. Bestimmte Features werden möglicherweise nicht unterstützt oder Funktionen sind eingeschränkt.
Weitere Informationen finden Sie unter Zusätzliche Nutzungsbestimmungen für Microsoft Azure-Vorschauen.
Die lokale Bildschirmfreigabevorschau ist in der öffentlichen Vorschau und ist im Rahmen von Version 1.15.1-beta.1 und höher verfügbar.
Lokale Bildschirmfreigabevorschau
Sie können einen Videostream-Renderer (VideoStreamRenderer
) verwenden, um mit dem Rendern von Streams Ihrer lokalen Bildschirmfreigabe beginnen, damit Sie sehen können, was Sie als Bildschirmfreigabestream senden.
// 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);
}
});
Darstellung von Video- und Bildschirminhaltsstreams für entfernte Teilnehmer
Beim Rendern des Videos oder der Bildschirmfreigabe eines Remoteteilnehmers besteht der erste Schritt darin, einen Verweis auf den Remotevideostream abzurufen, den Sie rendern möchten.
Sie können Remote-Teilnehmende nur rendern, indem Sie das Array oder den Videostream (videoStreams
) von RemoteParticipant
durchlaufen. Der Zugriff auf die Remoteteilnehmerauflistung erfolgt über das Call
-Objekt.
const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;
Um RemoteVideoStream
zu rendern, müssen Sie das isAvailableChanged
-Ereignis abonnieren. Wenn sich die isAvailable
-Eigenschaft in true
ändert, sendet ein Remoteteilnehmer einen Videostream.
Erstellen Sie danach eine neue Instanz von VideoStreamRenderer
, und erstellen Sie dann eine neue VideoStreamRendererView
Instanz mithilfe der asynchronen createView
Methode. Sie können dann view.target
an ein beliebiges Benutzeroberflächenelement anfügen.
Wenn sich die Verfügbarkeit eines Remote-Streams ändert, können Sie entweder den gesamten VideoStreamRenderer
oder einen spezifischen VideoStreamRendererView
zerstören. Wenn Sie beschließen, sie beizubehalten, zeigt die Ansicht einen leeren Videoframe an.
// 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}`);
});
}
Das CSS zum Formatieren des Wartekreisels für den Ladevorgang über den Remotevideostream.
.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); }
}
Remote-Videoqualität
Das Azure Communication Services WebJS SDK bietet ab Version 1.15.1 ein Feature namens Optimal Video Count (OVC).
Verwenden Sie dieses Feature, um Anwendungen zur Laufzeit darüber zu informieren, wie viele eingehende Videos von verschiedenen Teilnehmern zu einem bestimmten Zeitpunkt in einem Gruppenanruf von zwei (2) oder mehr Teilnehmern optimal gerendert werden können.
Dieses Feature macht eine Eigenschaft optimalVideoCount
verfügbar, die während des Anrufs dynamisch geändert wird, basierend auf den Netzwerk- und Hardwarefunktionen eines lokalen Endpunkts. Der Wert von optimalVideoCount
gibt an, wie viele Videos aus einer anderen Teilnehmeranwendung zu einem bestimmten Zeitpunkt gerendert werden sollen. Anwendungen müssen diese Änderungen behandeln und die Anzahl gerenderter Videos entsprechend der Empfehlung aktualisieren. Zwischen den Updates gibt es einen Entprellzeitraum von etwa zehn (10) Sekunden.
Verwendung
Das optimalVideoCount
Feature ist eine Anruffunktion. Sie müssen über die OptimalVideoCount
-Methode des feature
-Objekts auf das Call
-Feature verweisen.
Anschließend können Sie einen Listener über die on
-Methode des Features für die optimale Videoanzahl (OptimalVideoCountCallFeature
) festlegen, um benachrichtigt zu werden, wenn sich die optimale Videoanzahl ändert. Wenn Sie die Änderungen nicht mehr abonnieren möchten, können Sie die off
-Methode aufrufen.
Die aktuelle maximale Anzahl eingehender Videos, die gerendert werden können, beträgt 16. Um 16 eingehende Videos ordnungsgemäß zu unterstützen, benötigt der Computer mindestens 16 GB RAM und einen vier (4) Kern oder eine höhere CPU, die weniger als drei (3) Jahre alt ist.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Beispielnutzung: Ihre Anwendung abonniert Änderungen der optimalen Videoanzahl in Gruppenanrufen. Eine Änderung der optimalen Videoanzahl wird behandelt, indem entweder eine neue Renderermethode createView
erstellt oder Ansichten dispose
gelöscht und das Anwendungslayout entsprechend aktualisiert wird.
Eigenschaften von Fernvideostreams
Remote-Videostreams haben die folgenden Eigenschaften:
const id: number = remoteVideoStream.id;
-
id
: ID eines Remotevideostreams.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
-
mediaStreamType
: Dies kannVideo
oderScreenSharing
sein.
const isAvailable: boolean = remoteVideoStream.isAvailable;
-
isAvailable
: Gibt an, ob der Endpunkt des Remoteteilnehmers aktiv einen Stream sendet.
const isReceiving: boolean = remoteVideoStream.isReceiving;
isReceiving
:Informiert die Anwendung darüber, ob Remotevideostreamdaten empfangen werden oder nicht.
In den folgenden Szenarien ändert sich das Flag in
false
:- Ein Remoteteilnehmer, der einen mobilen Browser verwendet, versetzt die Browser-App in den Hintergrund.
- Ein Remoteteilnehmer oder der Benutzer, der das Video empfängt, hat Netzwerkprobleme, die die Videoqualität stark beeinträchtigen.
- Ein Teilnehmer aus der Ferne, der macOS/iOS Safari nutzt, wählt in der Adressleiste "Pause" aus.
- Die Netzwerkverbindung eines Remoteteilnehmers wurde getrennt.
- Ein Remoteteilnehmer mit mobilem Gerät beendet den Browser.
- Ein Teilnehmer aus der Ferne sperrt sein mobiles Gerät oder seinen Computer. Dieses Szenario gilt auch, wenn sich der Remoteteilnehmer auf einem Desktopcomputer befindet und dieser in den Ruhemodus wechselt.
In den folgenden Szenarien ändert sich das Flag in
true
:- Ein Remoteteilnehmer, der einen mobilen Browser verwendet und diesen in den Hintergrund versetzt hatte, bringt ihn wieder in den Vordergrund.
- Ein Remoteteilnehmer, der sich auf macOS/iOS Safari befindet, wählt " Fortsetzen " aus der Adressleiste aus, nachdem das Video anhält.
- Ein Remoteteilnehmer stellt nach einer vorübergehenden Verbindungstrennung erneut eine Verbindung mit dem Netzwerk her.
- Ein Remoteteilnehmer mit mobilem Gerät entsperrt sein Gerät und kehrt zu dem Anruf im mobilen Browser zurück.
Dieses Feature verbessert das Nutzungserlebnis für das Rendern von Remotevideostreams.
Sie können einen Wartekreisel für den Ladevorgang über den Remotevideostream anzeigen, wenn sich das Flag „isReceiving“ ändert. Sie müssen keinen Ladespinner implementieren, aber ein Ladespinner ist die häufigste Anwendung für eine bessere Benutzererfahrung.
const size: StreamSize = remoteVideoStream.size;
size
: Die Streamgröße mit Informationen zur Breite und Höhe des Videos.
Methoden und Eigenschaften von VideoStreamRenderer
await videoStreamRenderer.createView();
Erstellen Sie eine VideoStreamRendererView
-Instanz, die auf der Benutzeroberfläche der Anwendung angefügt werden kann, um den Remotevideostream zu rendern. Verwenden Sie die asynchrone Methode createView()
. Sie wird aufgelöst, wenn der Stream zum Rendern bereit ist, und gibt ein Objekt mit der Eigenschaft target
zurück. Dieses stellt ein video
-Element dar, das an beliebiger Stelle in die DOM-Struktur eingefügt werden kann.
videoStreamRenderer.dispose();
Löschen Sie videoStreamRenderer
und alle zugeordneten VideoStreamRendererView
-Instanzen.
Methoden und Eigenschaften von VideoStreamRendererView
Beim Erstellen von VideoStreamRendererView
können Sie die Eigenschaften scalingMode
und isMirrored
angeben.
scalingMode
kann Stretch
, Crop
oder Fit
sein. Bei Angabe von isMirrored
wird der gerenderte Stream vertikal umgedreht.
const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });
Jede VideoStreamRendererView
-Instanz verfügt über eine target
-Eigenschaft, die die Renderingoberfläche darstellt. Fügen Sie diese Eigenschaft in der Benutzeroberfläche der Anwendung an:
htmlElement.appendChild(view.target);
Sie können scalingMode
aktualisieren, indem Sie die Methode updateScalingMode
aufrufen:
view.updateScalingMode('Crop');
Senden Sie Videostreams von zwei verschiedenen Kameras im selben Anruf von demselben Desktopgerät.
Wichtig
Dieses Feature von Azure Communication Services befindet sich derzeit in der Vorschau. Features in der Vorschau sind öffentlich verfügbar und können von allen neuen und vorhandenen Microsoft-Kunden verwendet werden.
Vorschau-APIs und -SDKs werden ohne Vereinbarung zum Servicelevel bereitgestellt. Es wird empfohlen, diese nicht für Produktionsworkloads zu verwenden. Bestimmte Features werden möglicherweise nicht unterstützt oder Funktionen sind eingeschränkt.
Weitere Informationen finden Sie unter Zusätzliche Nutzungsbestimmungen für Microsoft Azure-Vorschauen.
Das Senden von Videostreams von zwei verschiedenen Kameras im gleichen Anruf wird im Rahmen der Version 1.17.1-beta.1+ in unterstützten Desktopbrowsern unterstützt.
Sie können Videostreams von zwei verschiedenen Kameras von einem einzigen Tab oder einer Desktop-App im gleichen Gespräch mit dem folgenden Codeausschnitt senden.
// 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();
Einschränkungen:
- Das Senden von Videostreams muss mit zwei verschiedenen
CallAgent
Instanzen erfolgen, die unterschiedliche Identitäten verwenden. Der Codeschnipsel zeigt die Verwendung von zwei Anruf-Agents mit jeweils eigenem Call-Objekt. - Im Codebeispiel treten beide CallAgents demselben Anruf (gleiche Anruf-IDs) bei. Sie können auch mit den Agents jeweils an verschiedenen Anrufen teilnehmen und ein Video an den einen Anruf und das andere Video an den anderen Anruf senden.
- Das Senden derselben Kamera in beiden CallAgents wird nicht unterstützt. Es müssen zwei verschiedene Kameras sein.
- Das Senden von zwei verschiedenen Kameras mit einem CallAgent wird derzeit nicht unterstützt.
- Auf macOS Safari können Videoeffekte für Hintergrundunschärfe (von @azure/communication-effects)) nur auf eine Kamera angewendet werden, und nicht auf beide gleichzeitig.
Das SDK installieren
Wählen Sie Ihre Datei build.gradle
auf Projektebene aus, und fügen Sie mavenCentral()
der Liste der Repositorys unter buildscript
und allprojects
hinzu:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Fügen Sie anschließend in der Datei build.gradle
auf Modulebene die folgenden Zeilen im Abschnitt dependencies
hinzu:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Initialisieren der erforderlichen Objekte
Zum Erstellen einer CallAgent
-Instanz müssen Sie die createCallAgent
-Methode für eine CallClient
-Instanz aufrufen. Dieser Aufruf gibt asynchron ein CallAgent
-Instanzobjekt zurück.
Die createCallAgent
-Methode verwendet CommunicationUserCredential
als Argument, womit ein Zugriffstoken gekapselt wird.
Um auf DeviceManager
zuzugreifen, müssen Sie zuerst eine callAgent
-Instanz erstellen. Anschließend können Sie die CallClient.getDeviceManager
-Methode zum Abrufen von DeviceManager
verwenden.
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();
Zum Festlegen eines Anzeigenamens für den Anrufer verwenden Sie diese alternative 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();
Geräteverwaltung
Um Video mit Anrufen zu verwenden, müssen Sie Geräte verwalten. Mithilfe von Geräten können Sie steuern, was Audio und Video an den Anruf überträgt.
Mit dem DeviceManager
Objekt können Sie lokale Geräte auflisten, die in einem Anruf zum Übertragen Ihrer Audio-/Videodatenströme verwendet werden. Außerdem können Sie mithilfe der systemeigenen Browser-API die Berechtigung eines Benutzers anfordern, auf sein Mikrofon und seine Kamera zuzugreifen.
Um auf deviceManager
zuzugreifen, rufen Sie die callClient.getDeviceManager()
-Methode auf.
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Aufzählen lokaler Geräte
Um auf lokale Geräte zuzugreifen, verwenden Sie Enumerationsmethoden im Geräte-Manager. Enumeration ist ein synchroner Vorgang.
// Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
Vorschau auf lokaler Kamera
Sie können DeviceManager
und Renderer
verwenden, um mit dem Rendern von Streams über Ihre lokale Kamera zu beginnen. Dieser Datenstrom wird nicht an andere Teilnehmer gesendet. Es ist ein lokaler Vorschaufeed. Das Rendern eines Datenstroms ist eine asynchrone Aktion.
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);
Tätigen eines 1:1-Anrufs mit Videokamera
Warnung
Derzeit wird nur ein ausgehender lokaler Videostream unterstützt. Um einen Anruf mit Video zu tätigen, müssen Sie lokale Kameras mithilfe der deviceManager
getCameras
API aufzählen.
Sobald Sie eine Kamera ausgewählt haben, erzeugen Sie damit eine LocalVideoStream
-Instanz und übergeben diese an videoOptions
als Element im localVideoStream
-Array an eine call
-Methode. Sobald der Anruf eine Verbindung herstellt, beginnt er automatisch, einen Videostream von der ausgewählten Kamera an andere Teilnehmer zu senden.
Hinweis
Aufgrund von Datenschutzbedenken wird das Video nicht für den Anruf freigegeben, wenn es nicht lokal in der Vorschau angezeigt wird. Weitere Informationen finden Sie unter "Lokale Kameravorschau".
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);
Starten und Beenden des Sendens von lokalem Video
Um ein Video zu starten, müssen Sie Kameras mithilfe des getCameraList
Vorgangs auf deviceManager
dem Objekt aufzählen. Erstellen Sie dann eine neue Instanz von LocalVideoStream
zur Übergabe der gewünschten Kamera, und übergeben Sie sie in der startVideo
-API als 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();
Nachdem Sie erfolgreich mit dem Senden von Videos begonnen haben, wird der Sammlung in der LocalVideoStream
Anrufinstanz eine localVideoStreams
Instanz hinzugefügt.
List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).
Um das lokale Video zu stoppen, übergeben Sie die LocalVideoStream
-Instanz, die in der localVideoStreams
-Sammlung verfügbar ist.
call.stopVideo(appContext, currentLocalVideoStream).get();
Sie können während des Sendens von Video auf ein anderes Kameragerät umschalten, indem Sie switchSource
für eine LocalVideoStream
-Instanz aufrufen:
currentLocalVideoStream.switchSource(source).get();
Rendern von Videostreams von Remoteteilnehmern
Um die Video- und Bildschirmübertragungs-Streams der Remoteteilnehmer aufzulisten, sehen Sie sich die videoStreams
-Sammlungen an:
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
Um einen RemoteVideoStream
von einem Remoteteilnehmer zu rendern, müssen Sie ein OnVideoStreamsUpdated
-Ereignis abonnieren.
Innerhalb des Ereignisses zeigt der Wechsel der isAvailable
-Eigenschaft zu „true“ an, dass der Remoteteilnehmer gerade einen Stream sendet. Sobald dies geschieht, erstellen Sie eine neue Instanz eines Renderer
, dann erstellen Sie eine neue RendererView
mithilfe der asynchronen createView
-API, und fügen Sie view.target
an beliebiger Stelle in der Benutzeroberfläche Ihrer Anwendung an.
Wenn sich die Verfügbarkeit eines Remotedatenstroms ändert, können Sie sich entscheiden, das gesamte Renderer
zu zerstören, ein bestimmtes RendererView
zu zerstören oder sie beizubehalten, was jedoch dazu führt, dass ein leerer Videoframe angezeigt wird.
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();
}
}
}
Eigenschaften von Fernvideostreams
Der Remotevideostream verfügt über die folgenden Eigenschaften:
Id
- ID eines Remotevideostreams.int id = remoteVideoStream.getId();
MediaStreamType
- Kann seinVideo
oderScreenSharing
.MediaStreamType type = remoteVideoStream.getMediaStreamType();
isAvailable
– Gibt an, ob der Remoteteilnehmerendpunkt datenstrom aktiv sendet.boolean availability = remoteVideoStream.isAvailable();
Methoden und Eigenschaften des Renderers
Das Renderer
Objekt verwendet die folgenden Methoden.
Zum Rendern des Remotevideostreams erstellen Sie eine
VideoStreamRendererView
Instanz, die später in der Anwendungs-UI angefügt werden kann.// Create a view for a video stream VideoStreamRendererView.createView()
Löscht den Renderer und alle mit ihm verknüpften
VideoStreamRendererView
-Instanzen. Rufen Sie sie auf, nachdem Sie alle zugeordneten Ansichten aus der Benutzeroberfläche entfernt haben.VideoStreamRenderer.dispose()
Um die Größe (Breite/Höhe) eines Remotevideostreams festzulegen, verwenden Sie
StreamSize
.StreamSize renderStreamSize = VideoStreamRenderer.getSize(); int width = renderStreamSize.getWidth(); int height = renderStreamSize.getHeight();
Methoden und Eigenschaften von RendererView
Beim Erstellen eines VideoStreamRendererView
können Sie die ScalingMode
- und mirrored
-Eigenschaften angeben, die für diese Ansicht gelten.
Der Skalierungsmodus kann entweder CROP
oder FIT
sein.
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));
Das erstellte RendererView-Objekt kann dann mit dem folgenden Ausschnitt an die Benutzeroberfläche der Anwendung angefügt werden:
layout.addView(rendererView);
Sie können den Skalierungsmodus später mithilfe des updateScalingMode
-Vorgangs für das RendererView
-Objekt mit einem Argument von entweder ScalingMode.CROP
oder ScalingMode.FIT
aktualisieren.
// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)
Einrichten des Systems
Führen Sie die unten angegebenen Schritte aus, um Ihr System einzurichten.
Erstellen des Xcode-Projekts
Erstellen Sie in Xcode ein neues iOS-Projekt, und wählen Sie die Vorlage Single View App (Einzelansicht-App) aus. In diesem Artikel wird das SwiftUI-Framework verwendet. Legen Sie daher Sprache auf Swift und Schnittstelle auf SwiftUI fest.
Sie werden in diesem Artikel keine Tests erstellen. Sie können das Kontrollkästchen Tests einschließen deaktivieren.
Installieren des Pakets und der Abhängigkeiten mithilfe von CocoaPods
Erstellen Sie eine Podfile-Datei für die Anwendung, wie in diesem Beispiel:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Führen Sie
pod install
aus.Öffnen Sie
.xcworkspace
mithilfe von Xcode.
Anfordern des Zugriffs auf das Mikrofon
Um auf das Mikrofon des Geräts zuzugreifen, müssen Sie die Liste der Informationseigenschaften Ihrer App mithilfe von NSMicrophoneUsageDescription
aktualisieren. Legen Sie den zugehörigen Wert auf eine Zeichenfolge fest. Diese wird in den Dialog aufgenommen, mit dem das System den Zugriff beim Benutzer anfordert.
Klicken Sie mit der rechten Maustaste auf den Eintrag info.plist in der Projektstruktur, und wählen Sie dann Öffnen als>Quellcode aus. Fügen Sie im Abschnitt <dict>
der obersten Ebene die folgenden Zeilen hinzu, und speichern Sie dann die Datei.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Einrichten des App-Frameworks
Öffnen Sie die Datei ContentView.swift
Ihres Projekts. Fügen Sie am Anfang der Datei eine import
-Deklaration hinzu, um die AzureCommunicationCalling
-Bibliothek zu importieren. Importieren Sie außerdem AVFoundation
. Sie ist für Audioberechtigungsanforderungen im Code erforderlich.
import AzureCommunicationCalling
import AVFoundation
Initialisieren von „CallAgent“
Um eine CallAgent
-Instanz auf der Grundlage von CallClient
zu erstellen, müssen Sie eine Methode vom Typ callClient.createCallAgent
verwenden, die asynchron ein Objekt vom Typ CallAgent
zurückgibt, nachdem es initialisiert wurde.
Übergeben Sie für die Erstellung eines Anrufclients ein Objekt vom Typ CommunicationTokenCredential
:
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)
}
Übergeben Sie das von Ihnen erstellte CommunicationTokenCredential
-Objekt an CallClient
, und legen Sie den Anzeigenamen fest:
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")
}
})
Verwalten von Geräten
Um mit der Verwendung von Video mit Anrufen zu beginnen, müssen Sie wissen, wie Sie Geräte verwalten. Geräte ermöglichen es Ihnen, zu steuern, was Audio und Video an den Anruf überträgt.
DeviceManager
ermöglicht das Aufzählen lokaler Geräte, die in einem Anruf zur Übertragung von Audio- oder Videostreams verwendet werden können. Außerdem können Sie die Berechtigung eines Benutzers für den Zugriff auf ein Mikrofon oder eine Kamera anfordern. Auf deviceManager
kann im Objekt callClient
zugegriffen werden.
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")
}
}
Aufzählen lokaler Geräte
Für den Zugriff auf lokale Geräte können Enumerationsmethoden für den Geräte-Manager verwendet werden. Enumeration ist ein synchroner Vorgang.
// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]
Vorschau der lokalen Kamera anzeigen
Sie können mit Renderer
mit dem Rendern eines Streams von Ihrer lokalen Kamera beginnen. Dieser Stream ist nicht für andere Teilnehmer gedacht. es ist ein lokaler Vorschaufeed. Dies ist ein asynchroner Vorgang.
let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()
Lokale Kamera-Vorschau-Eigenschaften abrufen
Der Renderer enthält eine Reihe von Eigenschaften und Methoden, mit denen Sie das Rendering steuern können.
// 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()
Führen Sie einen 1:1-Anruf mit Video durch
Wie Sie eine Geräte-Manager-Instanz erhalten, erfahren Sie im Abschnitt zur Geräteverwaltung.
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")
}
}
Rendern von Videostreams von Remoteteilnehmern
Remoteteilnehmer können während eines Anrufs eine Video- oder Bildschirmfreigabe initiieren.
Behandeln von Video- oder Bildschirmfreigabestreams von Remoteteilnehmern
Untersuchen Sie die Sammlungen vom Typ videoStreams
, um die Streams von Remoteteilnehmern aufzulisten.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Abrufen von Eigenschaften von Remotevideostreams
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
Streams von Remote-Teilnehmern rendern
Verwenden Sie den folgenden Code, um das Rendern von Streams von Remoteteilnehmern zu starten:
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)
Abrufen von Methoden und Eigenschaften des Fernvideo-Renderers
// [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()
Einrichten des Systems
Führen Sie die unten angegebenen Schritte aus, um Ihr System einzurichten.
Erstellen des Visual Studio-Projekts
Erstellen Sie für eine UWP-App (Universelle Windows-Plattform) in Visual Studio 2022 ein neues Projekt vom Typ Leere App (universelles Windows). Nachdem Sie den Projektnamen eingegeben haben, können Sie ein beliebiges Windows SDK höher als Version 10.0.17763.0 auswählen.
Für eine WinUI 3-App erstellen Sie ein neues Projekt mit der Vorlage Leere App, Gepackt (WinUI 3 in Desktop), um eine WinUI 3-Single-Page-Webanwendung einzurichten. Windows-App SDK-Version 1.3 oder höher ist erforderlich.
Installieren Sie das Paket und die Abhängigkeiten mit dem NuGet-Paket-Manager
Die Calling SDK-APIs und -Bibliotheken sind über ein NuGet-Paket öffentlich verfügbar.
So können Sie das NuGet-Paket für das Calling SDK suchen, herunterladen und installieren:
- Öffnen Sie den NuGet-Paket-Manager, indem Sie Tools>NuGet-Paket-Manager>NuGet-Pakete für Lösung verwalten auswählen.
- Wählen Sie Durchsuchen aus, und geben Sie dann Azure.Communication.Calling.WindowsClient in das Suchfeld ein.
- Stellen Sie sicher, dass das Kontrollkästchen Vorabversion einbeziehen aktiviert ist.
- Wählen Sie das Paket Azure.Communication.Calling.WindowsClient und dann Azure.Communication.Calling.WindowsClient1.4.0-beta.1 oder eine neuere Version aus.
- Aktivieren Sie das Kontrollkästchen für das Azure Communication Services-Projekt im rechten Bereich.
- Wählen Sie Installieren aus.
Anfordern des Zugriffs auf das Mikrofon
Die App benötigt Zugriff auf die Kamera. In UWP-Apps (Universelle Windows-Plattform) müssen Sie die Kamerafunktion in der App-Manifestdatei deklarieren.
- Öffnen Sie das Projekt in Visual Studio.
- Doppelklicken Sie im Projektmappen-Explorer auf die Datei mit der
.appxmanifest
-Erweiterung. - Klicken Sie auf die Registerkarte "Funktionen ".
- Aktivieren Sie in der Liste der Funktionen das Kontrollkästchen
Camera
.
Erstellen von UI-Schaltflächen zum Annehmen und Beenden des Anrufs
Diese Beispiel-App enthält zwei Schaltflächen. Eine Taste zum Tätigen des Anrufs und eine weitere Taste zum Beenden eines getätigten Anrufs.
- Doppelklicken Sie im Projektmappen-Explorer auf die Datei mit dem Namen
MainPage.xaml
für UWP bzw. aufMainWindows.xaml
für WinUI 3. - Suchen Sie im zentralen Panel in der Vorschau der Benutzeroberfläche nach dem XAML-Code.
- Ändern Sie den XAML-Code mithilfe des folgenden Auszugs:
<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>
Einrichten der App mit Calling SDK-APIs
Die Calling SDK-APIs befinden sich in zwei verschiedenen Namespaces.
Führen Sie die folgenden Schritte aus, um den C#-Compiler über diese Namespaces zu informieren und die IntelliSense-Version von Visual Studio zur Unterstützung der Codeentwicklung zu aktivieren.
- Klicken Sie im Projektmappen-Explorer auf den Pfeil links neben der Datei mit dem Namen
MainPage.xaml
für UWP bzw.MainWindows.xaml
für WinUI 3. - Doppelklicken Sie auf die Datei namens
MainPage.xaml.cs
oderMainWindows.xaml.cs
. - Fügen Sie am Ende der aktuellen
using
-Anweisungen die folgenden Befehle hinzu.
using Azure.Communication.Calling.WindowsClient;
MainPage.xaml.cs
oder MainWindows.xaml.cs
offen halten. Im nächsten Schritt wird weiterer Code hinzugefügt.
Aktivieren von App-Interaktionen
Die hinzugefügten Schaltflächen sind von CommunicationCall
abhängig. Dies bedeutet, dass Sie ein CommunicationCall
Datenmitglied zur MainPage
- oder MainWindow
-Klasse hinzufügen müssen.
Außerdem müssen Sie den asynchronen Vorgang ermöglichen, sodass die Erstellung von CallAgent
erfolgreich ist. Fügen Sie der gleichen Klasse ein CallAgent
-Datenelement hinzu.
Fügen Sie der Klasse MainPage
oder MainWindow
die folgenden Datenelemente hinzu:
CallAgent callAgent;
CommunicationCall call;
Erstellen von Schaltflächenhandlern
Zuvor haben wir dem XAML-Code zwei UI-Schaltflächen hinzugefügt. Der folgende Code fügt die Handler hinzu, die ausgeführt werden sollen, wenn ein Benutzer die Schaltfläche auswählt.
Fügen Sie den folgenden Code nach den Datenelementen aus dem vorherigen Abschnitt hinzu.
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
Die folgenden Klassen und Schnittstellen befassen sich mit einigen der wichtigsten Features der Azure Communication Services-Clientbibliothek „Calling“ für UWP.
Name | BESCHREIBUNG |
---|---|
CallClient |
CallClient ist der Haupteinstiegspunkt der Calling-Client-Bibliothek. |
CallAgent |
CallAgent dient zum Starten und Verbinden von Anrufen. |
CommunicationCall |
CommunicationCall dient zum Verwalten von Anrufen, die getätigt wurden oder an denen teilgenommen wurde. |
CommunicationTokenCredential |
CommunicationTokenCredential dient als Token-Zugangsdaten zum Instanziieren von CallAgent . |
CallAgentOptions |
Die CallAgentOptions enthält Informationen zum Identifizieren des Anrufers. |
HangupOptions |
HangupOptions gibt an, ob ein Anruf für alle Teilnehmer beendet werden soll. |
Registrieren des Videoschemahandlers
Eine UI-Komponente wie XAML MediaElement
oder MediaPlayerElement
erfordert, dass die App eine Konfiguration für das Rendern lokaler und Remotevideofeeds registriert.
Fügen Sie den folgenden Inhalt zwischen den Package
-Tags von Package.appxmanifest
hinzu:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
Initialisieren von „CallAgent“
Zum Erzeugen einer CallAgent
-Instanz anhand von CallClient
müssen Sie die Methode CallClient.CreateCallAgentAsync
verwenden, die ein CallAgent
-Objekt asynchron zurückgibt, nachdem es initialisiert wurde.
Zum Erstellen von CallAgent
müssen Sie ein CallTokenCredential
-Objekt und ein CallAgentOptions
-Objekt übergeben. Denken Sie daran, dass CallTokenCredential
eine Ausnahme auslöst, wenn ein falsch formatiertes Token übergeben wird.
Fügen Sie den folgenden Code in eine Hilfsfunktion ein, damit er während der Initialisierung ausgeführt wird.
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;
Ändern Sie das <AUTHENTICATION_TOKEN>
mit einem gültigen Anmeldeinformationstoken für Ihre Ressource. Weitere Informationen zum Abrufen eines Zugangstokens finden Sie unter Benutzerzugriffstoken.
Tätigen eines 1:1-Anrufs mit Videokamera
Die Objekte, die zum Erstellen von CallAgent
erforderlich sind, sind jetzt bereit. Erstellen Sie anschließend CallAgent
asynchron und tätigen Sie einen Videoanruf.
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 } }
};
}
Vorschau auf lokaler Kamera
Sie können optional die lokale Kameravorschau einrichten. Sie können das Video über MediaPlayerElement
rendern.
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
So initialisieren Sie die lokale MediaPlayerElement
-Vorschau:
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);
}
}
Rendern des Remotekamerastreams
Richten Sie einen Ereignishandler als Reaktion auf das Ereignis OnCallsUpdated
ein:
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;
}
}
Starten Sie das Rendern des Remotevideostreams für 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;
}
}
Beenden eines Anrufs
Nachdem ein Anruf getätigt wurde, verwenden Sie die HangupAsync
Methode des CommunicationCall
Objekts, um den Anruf zu beenden.
Verwenden Sie eine Instanz, HangupOptions
um teilnehmer zu informieren, ob der Anruf beendet werden muss.
Fügen Sie den folgenden Code 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;
}
}
}
}
Ausführen des Codes
- Stellen Sie sicher, dass Visual Studio die App für
x64
,x86
oderARM64
erstellt. - Drücken Sie F5 , um mit der Ausführung der App zu beginnen.
- Klicken Sie auf die Schaltfläche "CommunicationCall ", um einen Anruf an den definierten Empfänger zu tätigen.
Wenn die App zum ersten Mal ausgeführt wird, fordert das System den Benutzer auf, zugriff auf das Mikrofon zu gewähren.