Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Nous vous recommandons de vous abonner aux événements SDK d'appel. Les kits SDK Azure Communication Services sont dynamiques et contiennent des propriétés susceptibles de changer au fil du temps. Vous pouvez vous abonner à ces événements pour être averti avant toute modification. Suivez les instructions de cet article pour vous abonner aux événements du Kit de développement logiciel (SDK) Azure Communication Services.
Événements sur le Kit de développement logiciel (SDK) Azure Communication Calling
Cette section décrit les événements et les modifications apportées aux propriétés auxquelles votre application peut s’abonner. L’abonnement à ces événements permet à votre application d’être informée des changements d’état dans le Kit de développement logiciel (SDK) appelant et de réagir en conséquence.
Le suivi des événements est crucial, car il permet à l’état de votre application de rester synchronisé avec l’état de l’infrastructure d’appel Azure Communication Services. Le suivi des événements vous aide à appliquer des modifications sans implémenter un mécanisme d’extraction sur les objets du Kit de développement logiciel (SDK).
Cette section part du principe que vous avez suivi le guide de démarrage rapide ou que vous avez implémenté une application capable d’effectuer et de recevoir des appels. Si vous n’avez pas terminé le guide de démarrage, consultez Ajouter un appel vocal à votre application.
Chaque objet du Kit de développement logiciel (SDK) JavaScript Calling a properties et collections. Leurs valeurs changent tout au long de la durée de vie de l’objet.
Utilisez la on() méthode pour vous abonner aux événements d’objet. Utilisez la off() méthode pour vous désabonner des événements d’objet.
Propriétés
Vous pouvez vous abonner à l’événement '<property>Changed' pour être informé des changements de valeur de la propriété.
Exemple d’abonnement sur une propriété
Dans cet exemple, nous nous abonnons aux changements de la valeur de la propriété isLocalVideoStarted.
call.on('isLocalVideoStartedChanged', () => {
// At that point the value call.isLocalVideoStarted is updated
console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
});
Collections
Vous pouvez vous abonner à l’événement \<collection>Updated pour recevoir des notifications sur les modifications apportées à une collection d’objets. L’événement \<collection>Updated est déclenché chaque fois que des éléments sont ajoutés ou supprimés de la collection que vous surveillez.
- La charge utile de l’événement
'<collection>Updated'possède un tableauaddedqui contient des valeurs qui ont été ajoutées à la collection. - La charge utile de l’événement
'<collection>Updated'possède également un tableauremovedqui contient des valeurs qui ont été supprimées de la collection.
Exemple d’abonnement sur une collection
Dans cet exemple, nous nous abonnons aux changements de valeurs de l’objet d’appel LocalVideoStream.
call.on('localVideoStreamsUpdated', updateEvent => {
updateEvent.added.forEach(async (localVideoStream) => {
// Contains an array of LocalVideoStream that were added to the call
// Add a preview and start any processing if needed
handleAddedLocalVideoStream(localVideoStream )
});
updateEvent.removed.forEach(localVideoStream => {
// Contains an array of LocalVideoStream that were removed from the call
// Remove the preview and stop any processing if needed
handleRemovedLocalVideoStream(localVideoStream )
});
});
Événements sur l’objet CallAgent
Nom de l’événement : incomingCall
L’événement incomingCall se déclenche lorsque le client reçoit un appel entrant.
Comment votre application réagit-elle à l’événement ?
Votre application doit notifier le destinataire de l’appel entrant. L’invite de notification doit permettre au destinataire d’accepter ou de refuser l’appel.
Exemple de code :
callClient.on('incomingCall', (async (incomingCallEvent) => {
try {
// Store a reference to the call object
incomingCall = incomingCallEvent.incomingCall;
// Update your UI to allow
acceptCallButton.disabled = false;
callButton.disabled = true;
} catch (error) {
console.error(error);
}
});
Nom de l’événement : callsUpdated
L’événement callsUpdated mis à jour se déclenche lorsqu’un appel est supprimé ou ajouté à l’agent d’appel. Cet événement se produit lorsque l’utilisateur passe, reçoit ou met fin à un appel.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour son interface utilisateur en fonction du nombre d’appels actifs pour l’instance CallAgent.
Nom de l’événement : connectionStateChanged
L’événement connectionStateChanged déclenché lorsque l’état de signalement de CallAgent est mis à jour.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour son interface utilisateur en fonction du nouvel état. Les valeurs d’état de connexion possibles sont Connected et Disconnected.
Exemple de code :
callClient.on('connectionStateChanged', (async (connectionStateChangedEvent) => {
if (connectionStateChangedEvent.newState === "Connected") {
enableCallControls() // Enable all UI element that allow user to make a call
}
if (connectionStateChangedEvent.newState === 'Disconnected') {
if (typeof connectionStateChangedEvent.reason !== 'undefined') {
alert(`Disconnected reason: ${connectionStateChangedEvent.reason}`)
}
disableCallControls() // Disable all the UI element that allows the user to make a call
}
});
Événements sur l’objet Call
Nom de l’événement : stateChanged
L’événement stateChanged se déclenche lorsque l’état de l’appel change. Par exemple, lorsqu’un appel passe de connected à disconnected.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour son interface utilisateur en conséquence. Désactiver ou activer les boutons appropriés et d’autres éléments d’interface utilisateur en fonction du nouvel état de l’appel.
Exemple de code :
call.on('stateChanged', (async (connectionStateChangedEvent) => {
if(call.state === 'Connected') {
connectedLabel.hidden = false;
acceptCallButton.disabled = true;
startCallButton.disabled = true;
startVideoButton.disabled = false;
stopVideoButton.disabled = false
} else if (call.state === 'Disconnected') {
connectedLabel.hidden = true;
startCallButton.disabled = false;
console.log(`Call ended, call end reason={code=${call.callEndReason.code}, subCode=${call.callEndReason.subCode}}`);
}
});
Événement : idChanged
L’événement idChanged se déclenche lorsque l’ID d’un appel change. L’ID d’un appel change lorsque l’appel passe de l’état connecting à connected. Une fois l’appel connecté, l’ID de l’appel reste identique.
Comment votre application réagit-elle à l’événement ?
Votre application peut enregistrer le nouvel ID d’appel ou le récupérer à partir de l’objet d’appel ultérieurement si nécessaire.
Exemple de code :
let callId = "";
call.on('idChanged', (async (callIdChangedEvent) => {
callId = call.id; // You can log it as the call ID is useful for debugging call issues
});
Événement : isMutedChanged
L’événement isMutedChanged se déclenche lorsque l’audio local est coupé ou activé.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour le bouton de désactivation / réactivation du son pour qu’il soit dans le bon état.
Exemple de code :
call.on('isMutedChanged', (async (isMutedChangedEvent) => {
microphoneButton.disabled = call.isMuted;
});
Événement : isScreenSharingOnChanged
L’événement isScreenSharingOnChanged se déclenche lorsque le partage d’écran pour l’utilisateur local est activé ou désactivé.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher un aperçu et/ou un avertissement à l’utilisateur si le partage d’écran est activé.
Si le partage d’écran est désactivé, l’application doit supprimer l’aperçu et l’avertissement.
Exemple de code :
call.on('isScreenSharingOnChanged', () => {
if (!this.call.isScreenSharing) {
displayStartScreenSharingButton();
hideScreenSharingWarning()
removeScreenSharingPreview();
} else {
displayScreenSharingWarning()
displayStopScreenSharingButton();
renderScreenSharingPreview();
}
});
Événement : isLocalVideoStartedChanged
L’événement isLocalVideoStartedChanged se déclenche lorsque l’utilisateur active ou désactive sa vidéo locale.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher un aperçu de la vidéo locale et activer ou désactiver le bouton d’activation de l’appareil photo.
Exemple de code :
call.on('isLocalVideoStartedChanged', () => {
showDisableCameraButton(call.isLocalVideoStarted);
});
Événement : remoteParticipantsUpdated
Votre application doit s’abonner aux événements pour chaque ajout RemoteParticipants et se désabonner des événements pour les participants qui quittent l’appel.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher un aperçu de la vidéo locale et activer ou désactiver le bouton d’activation de l’appareil photo.
Exemple de code :
call.on('remoteParticipantsUpdated', (remoteParticipantsUpdatedEvent) => {
remoteParticipantsUpdatedEvent.added.forEach(participant => {
// handleParticipant should
// - subscribe to the remote participants events
// - update the UI
handleParticipant(participant);
});
remoteParticipantsUpdatedEvent.removed.forEach(participant => {
// removeParticipant should
// - unsubscribe from the remote participants events
// - update the UI
removeParticipant(participant);
});
});
Événement : localVideoStreamsUpdated
L’événement localVideoStreamsUpdated se déclenche lorsque la liste des flux vidéo locaux change. Ces modifications se produisent lorsque l’utilisateur démarre ou supprime un flux vidéo.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher des aperçus pour chacun des LocalVideoStream ajouts. Votre application doit supprimer l’aperçu et arrêter le traitement pour chaque LocalVideoStream suppression.
Exemple de code :
call.on('localVideoStreamsUpdated', (localVideoStreamUpdatedEvent) => {
localVideoStreamUpdatedEvent.added.forEach(addedLocalVideoStream => {
// Add a preview and start any processing if needed
handleAddedLocalVideoStream(addedLocalVideoStream)
});
localVideoStreamUpdatedEvent.removed.forEach(removedLocalVideoStream => {
// Remove the preview and stop any processing if needed
this.handleRemovedLocalVideoStream(removedLocalVideoStream)
});
});
Événement : remoteAudioStreamsUpdated
L’événement remoteAudioStreamsUpdated se déclenche lorsque la liste des flux audio distants change. Ces modifications se produisent lorsque les participants distants ajoutent ou suppriment des flux audio à l’appel.
Comment votre application réagit-elle à l’événement ?
Si un flux a été traité et est maintenant supprimé, le traitement doit être arrêté. En revanche, si un flux est ajouté, la réception de l’événement est un bon point de départ pour le traitement du nouveau flux audio.
Événement : totalParticipantCountChanged
Le totalParticipantCountChanged se déclenche lorsque le nombre de totalParticipant a changé lors d’un appel.
Comment votre application réagit-elle à l’événement ?
Si votre application affiche un compteur de participants, votre application peut mettre à jour son compteur de participants lorsque l’événement est reçu.
Exemple de code :
call.on('totalParticipantCountChanged', () => {
participantCounterElement.innerText = call.totalParticipantCount;
});
Événement : roleChanged
Le participant roleChanged se déclenche lorsque les rôles localParticipant changent dans l’appel. Par exemple, lorsque le participant local devient présentateur ACSCallParticipantRolePresenter dans un appel.
Comment votre application réagit-elle à l’événement ?
Votre application doit activer ou désactiver le bouton en fonction du nouveau rôle utilisateur.
Exemple de code :
call.on('roleChanged', () => {
this.roleElement = call.role;
});
Événement : mutedByOthers
L’événement mutedByOthers se produit lorsque le participant local mute d’autres participants dans l’appel.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher un message à l’utilisateur indiquant qu’il est désactivé.
Exemple de code :
call.on('mutedByOthers', () => {
messageBanner.innerText = "You have been muted by other participant in this call";
});
Événement : callerInfoChanged
L’événement callerInfoChanged se produit quand les informations sur l’appelant ont été mises à jour. Cela se produit lorsqu’un appelant modifie son nom d’affichage.
Comment votre application réagit-elle à l’événement ? L’application peut mettre à jour les informations sur l’appelant.
Exemple de code :
call.on('callerInfoChanged', () => {
showCallerInfo(call.callerInfo)
});
Événement : transferorInfoChanged
L’événement transferorInfoChanged se produit quand les informations sur la personne à l’origine du transfert ont été mises à jour. Cela se produit lorsqu’un cédant modifie son nom d'affichage.
Comment votre application réagit-elle à l’événement ? L’application peut mettre à jour les informations sur la personne à l’origine du transfert.
Exemple de code :
call.on('transferorInfoChanged', () => {
showTransferorInfo(call.transferorInfo)
});
Événements sur l’objet RemoteParticipant
Événement : roleChanged
L’événement roleChanged se déclenche lorsque le rôle du RemoteParticipant change dans l’appel. Par exemple, lorsque le RemoteParticipant devient présentateur ACSCallParticipantRolePresenter dans un appel.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour son interface utilisateur en fonction du RemoteParticipant nouveau rôle.
Exemple de code :
remoteParticipant.on('roleChanged', () => {
updateRole(remoteParticipant);
});
Événement : isMutedChanged
L’événement isMutedChanged se déclenche lorsque l’un des RemoteParticipant désactive ou réactive le son de son microphone.
Comment votre application réagit-elle à l’événement ?
Votre application peut afficher une icône près de la vue qui affiche le participant.
Exemple de code :
remoteParticipant.on('isMutedChanged', () => {
updateMuteStatus(remoteParticipant); // Update the UI based on the mute state of the participant
});
Événement : displayNameChanged
Le displayNameChanged lorsque le nom du RemoteParticipant est mis à jour.
Comment votre application réagit-elle à l’événement ?
Votre application doit mettre à jour le nom du participant s’il est affiché dans l’interface utilisateur.
Exemple de code :
remoteParticipant.on('displayNameChanged', () => {
remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
});
remoteParticipant.on('displayNameChanged', (args: {newValue?: string, oldValue?: string, reason?: DisplayNameChangedReason}) => {
remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
console.log(`Display name changed from ${oldValue} to ${newValue} due to ${reason}`);
});
Événement : isSpeakingChanged
Le isSpeakingChanged lorsque l’intervenant dominant d’un appel change.
Comment votre application réagit-elle à l’événement ?
L’interface utilisateur de votre application doit donner la priorité à l’affichage de celui qui est devenu l’orateur RemoteParticipant dominant.
Exemple de code :
remoteParticipant.on('isSpeakingChanged', () => {
showAsRemoteSpeaker(remoteParticipant) // Display a speaking icon near the participant
});
Événement : videoStreamsUpdated
Le videoStreamsUpdated lorsqu’un participant distant ajoute ou retire un VideoStream de l’appel.
Comment votre application réagit-elle à l’événement ?
Si votre application a traité un flux supprimé, votre application doit arrêter le traitement. Lorsqu’un nouveau flux est ajouté, nous vous recommandons de commencer à le rendre ou à le traiter.
Exemple de code :
remoteParticipant.on('videoStreamsUpdated', (videoStreamsUpdatedEvent) => {
videoStreamsUpdatedEvent.added.forEach(addedRemoteVideoStream => {
// Remove a renderer and start processing the stream if any processing is needed
handleAddedRemoteVideoStream(addedRemoteVideoStream)
});
videoStreamsUpdatedEvent.removed.forEach(removedRemoteVideoStream => {
// Remove the renderer and stop processing the stream if any processing is ongoing
this.handleRemovedRemoteVideoStream(removedRemoteVideoStream)
});
});
Événement sur l’objet AudioEffectsFeature
Événement : effectsStarted
Cet événement se produit lorsque l’effet audio sélectionné est appliqué au flux audio. Par exemple, lorsqu’un utilisateur active la Suppression du bruit, le effectsStarted se déclenche.
Comment votre application réagit-elle à l’événement ?
Votre application peut afficher ou activer un bouton qui permet à l’utilisateur de désactiver l’effet audio.
Exemple de code :
audioEffectsFeature.on('effectsStarted', (effects) => {
stopEffectButton.style.visibility = "visible";
});
Événement : effectsStopped
Cet événement se produit lorsque l’effet audio sélectionné est appliqué au flux audio. Par exemple, lorsqu’un utilisateur désactive la Suppression du bruit, le effectsStopped est déclenché.
Comment votre application réagit-elle à l’événement ?
Votre application peut afficher ou activer un bouton qui permet à l’utilisateur d’activer l’effet audio.
Exemple de code :
audioEffectsFeature.on('effectsStopped', (effects) => {
startEffectButton.style.visibility = "visible";
});
Événement : effectsError
Cet événement se produit lorsqu’une erreur se produit lors du démarrage ou de l’application d’un effet audio.
Comment votre application réagit-elle à l’événement ?
Votre application doit afficher une alerte ou un message d’erreur indiquant que l’effet audio ne fonctionne pas comme prévu.
Exemple de code :
audioEffectsFeature.on('effectsError', (error) => {
console.log(`Error with the audio effect ${error}`);
alert(`Error with the audio effect`);
});
Installer le SDK
Recherchez votre fichier build.gradle au niveau du projet et ajoutez mavenCentral() à la liste des référentiels sous buildscript et allprojects :
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Ensuite, dans votre fichier build.gradle au niveau du module, ajoutez les lignes suivantes à la section dependencies :
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Initialiser les objets nécessaires
Pour créer une instance CallAgent, vous devez appeler la méthode createCallAgent sur une instance CallClient. Cet appel retourne de façon asynchrone un objet d’instance CallAgent.
La méthode createCallAgent prend CommunicationUserCredential en tant qu’argument, qui encapsule un jeton d’accès.
Pour accéder à DeviceManager, vous devez d’abord créer une instance callAgent. Vous pouvez ensuite utiliser la méthode CallClient.getDeviceManager pour obtenir 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();
Pour définir un nom d’affichage pour l’appelant, utilisez cette autre méthode :
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();
Maintenant que vous avez installé android SDK, vous pouvez vous abonner à la plupart des propriétés et collections pour être averti lorsque les valeurs changent.
Propriétés
Pour vous abonner à des événements property changed :
// subscribe
PropertyChangedListener callStateChangeListener = new PropertyChangedListener()
{
@Override
public void onPropertyChanged(PropertyChangedEvent args)
{
Log.d("The call state has changed.");
}
}
call.addOnStateChangedListener(callStateChangeListener);
//unsubscribe
call.removeOnStateChangedListener(callStateChangeListener);
Lorsque vous utilisez des écouteurs d’événements qui sont définis dans la même classe, liez l’écouteur à une variable. Pour ajouter ou supprimer des méthodes d'écoute, passez la variable en argument.
Si vous essayez de passer l’écouteur directement comme argument, vous perdrez la référence à cet écouteur. Java crée de nouvelles instances de ces écouteurs et ne fait pas référence à celles créées précédemment. Ils se déclenchent toujours correctement, mais ne peuvent pas être supprimés parce que vous n’avez plus de référence à eux.
Collections
Pour vous abonner à des événements collection updated :
LocalVideoStreamsChangedListener localVideoStreamsChangedListener = new LocalVideoStreamsChangedListener()
{
@Override
public void onLocalVideoStreamsUpdated(LocalVideoStreamsEvent localVideoStreamsEventArgs) {
Log.d(localVideoStreamsEventArgs.getAddedStreams().size());
Log.d(localVideoStreamsEventArgs.getRemovedStreams().size());
}
}
call.addOnLocalVideoStreamsChangedListener(localVideoStreamsChangedListener);
// To unsubscribe
call.removeOnLocalVideoStreamsChangedListener(localVideoStreamsChangedListener);
Configurer votre système
Effectuez les étapes suivantes pour configurer votre système.
Créer le projet Xcode
Dans Xcode, créez un projet iOS et sélectionnez le modèle Single View App. Cet article utilise l’infrastructure SwiftUI. Vous devez donc définir Langage sur Swift et Interface sur SwiftUI.
Vous n’allez pas créer de tests dans cet article. N’hésitez pas à désactiver la case Inclure des tests.
Installer le package et les dépendances à l’aide de CocoaPods
Créez un Podfile pour votre application, comme cet exemple :
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' endExécutez
pod install.Ouvrez
.xcworkspaceen utilisant Xcode.
Demander l’accès au microphone
Pour accéder au microphone de l’appareil, vous devez mettre à jour la liste des propriétés d’informations de votre application à l’aide de NSMicrophoneUsageDescription. Définissez la valeur associée à une chaîne qui est incluse dans la boîte de dialogue utilisée par le système pour demander l’accès à l’utilisateur.
Cliquez avec le bouton droit sur l’entrée Info.plist de l’arborescence du projet, puis sélectionnez Ouvrir en tant que>Code source. Ajoutez les lignes suivantes à la section <dict> tout en haut, puis enregistrez le fichier.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Configurer le framework d’application
Ouvrez le fichier ContentView.swift de votre projet. Ajoutez une déclaration import en haut du fichier pour importer la bibliothèque AzureCommunicationCalling. En outre, importez AVFoundation. Vous en avez besoin pour les demandes d’autorisations audio dans le code.
import AzureCommunicationCalling
import AVFoundation
Initialiser CallAgent
Pour créer une instance de CallAgent à partir de CallClient, vous devez utiliser une méthode callClient.createCallAgent qui retourne de manière asynchrone un objet CallAgent après qu’il a été initialisé.
Pour créer un client d’appel, transmettez un objet 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)
}
Transmettez l’objet CommunicationTokenCredential que vous avez créé à CallClient et définissez le nom complet :
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")
}
})
Maintenant que vous avez installé le Kit de développement logiciel (SDK) iOS, vous pouvez vous abonner à la plupart des propriétés et collections pour être averti lorsque les valeurs changent.
Propriétés
Pour vous abonner aux événements property changed, utilisez le code suivant.
call.delegate = self
// Get the property of the call state by getting on the call's state member
public func call(_ call: Call, didChangeState args: PropertyChangedEventArgs) {
{
print("Callback from SDK when the call state changes, current state: " + call.state.rawValue)
}
// to unsubscribe
self.call.delegate = nil
Collections
Pour vous abonner aux événements collection updated, utilisez le code suivant.
call.delegate = self
// Collection contains the streams that were added or removed only
public func call(_ call: Call, didUpdateLocalVideoStreams args: LocalVideoStreamsUpdatedEventArgs) {
{
print(args.addedStreams.count)
print(args.removedStreams.count)
}
// to unsubscribe
self.call.delegate = nil