Suscripción a eventos de SDK
Los SDK de Azure Communication Services son dinámicos y contienen muchas propiedades. Como desarrollador, en caso de modificaciones, es posible que quiera saber cuándo y, lo que es más importante, qué cambia. Aquí se explica cómo.
Eventos en el SDK de Azure Communication Calling
En esta guía se describen los distintos eventos o propiedades a los que la aplicación puede suscribirse. La suscripción a esos eventos permite que la aplicación se informe sobre el cambio de estado en el SDK de llamada y reaccionar en consecuencia.
El seguimiento de los eventos es crucial porque permite que el estado de su aplicación se mantenga sincronizado con el estado del marco de ACSCalling, todo ello sin necesidad de implementar un mecanismo de extracción en los objetos del SDK.
En esta guía se da por supuesto que ha realizado el inicio rápido o que ha implementado una aplicación que puede realizar y recibir llamadas. Si no ha finalizado la guía de introducción rápida, haga referencia a nuestro Inicio rápido.
Cada objeto del SDK de llamada de JavaScript tiene properties
y collections
. Sus valores cambian a lo largo de la duración del objeto.
Use el método on()
para suscribirse a los eventos de los objetos y el método off()
para finalizar la suscripción.
Propiedades
Puede suscribirse al evento '<property>Changed'
para escuchar los cambios de valor en la propiedad.
Ejemplo de suscripción en una propiedad
En este ejemplo, se suscribe a los cambios en el valor de la propiedad isLocalVideoStarted
.
call.on('isLocalVideoStartedChanged', () => {
// At that point the value call.isLocalVideoStarted is updated
console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
});
Colecciones
Puede suscribirse al evento "<collection>Updated" para recibir notificaciones sobre los cambios en una colección de objetos. El evento "<collection>Updated" se desencadena cada vez que se agregan o quitan elementos de la colección que está supervisando.
- La carga del evento
'<collection>Updated'
tiene una matrizadded
que contiene los valores que se quitaron de la colección. - La carga del evento
'<collection>Updated'
también tiene una matrizremoved
que contiene los valores que se quitaron de la colección.
Suscripción de ejemplo en una colección
En este ejemplo, nos suscribimos a los cambios en los valores del objeto Llamada 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 )
});
});
Eventos en el objeto CallAgent
Nombre del evento: incomingCall
El evento incomingCall
se desencadena cuando el cliente recibe una llamada entrante.
¿Cómo debería reaccionar su aplicación ante el evento?
La aplicación debe notificar al usuario la llamada entrante. El aviso de notificación debe proponer al usuario que acepte o rechace la llamada.
Código de ejemplo:
callClient.on('incomingCall', (async (incomimgCallEvent) => {
try {
// Store a reference to the call object
incomingCall = incomimgCallEvent.incomingCall;
// Update your UI to allow
acceptCallButton.disabled = false;
callButton.disabled = true;
} catch (error) {
console.error(error);
}
});
Nombre del evento: callsUpdated
El evento callsUpdated
actualizado se desencadena cuando se quita o se agrega una llamada al agente de llamada. Este evento se produce cuando el usuario realiza, recibe o finaliza una llamada.
¿Cómo debería reaccionar su aplicación ante el evento? La aplicación debería actualizar su interfaz de usuario en función del número de llamadas activas para la instancia de CallAgent.
Nombre del evento: connectionStateChanged
El evento connectionStateChanged
se desencadena cuando se actualiza el estado de señalización del CallAgent
.
¿Cómo debería reaccionar su aplicación ante el evento?
La aplicación debería actualizar su interfaz de usuario en función del nuevo estado. Los posibles valores de estado de conexión son Connected
y Disconnected
Código de ejemplo:
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
}
});
Eventos en el objeto Call
Nombre del evento: stateChanged
El evento stateChanged
se desencadena cuando cambia el estado de la llamada. Por ejemplo, cuando una llamada va de connected
a disconnected
.
¿Cómo debería reaccionar su aplicación ante el evento?
La aplicación debería actualizar su interfaz de usuario en consecuencia. Deshabilitar o habilitar los botones adecuados y otros elementos de la interfaz de usuario en función del nuevo estado de llamada.
Código de ejemplo:
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}}`);
}
});
Evento: idChanged
El evento idChanged
se desencadena cuando cambia el identificador de una llamada. El id. de una llamada cambia cuando la llamada pasa del estado connecting
al connected
. Una vez conectada la llamada, el identificador de la llamada sigue siendo idéntico.
¿Cómo podría la aplicación reaccionar al evento?
La aplicación debería guardar el nuevo identificador de llamada, pero también se puede recuperar del objeto de llamada más adelante cuando sea necesario.
Código de ejemplo:
let callId = "";
call.on('idChanged', (async (callIdChangedEvent) => {
callId = call.id; // You can log it as the call ID is useful for debugging call issues
});
Evento: isMutedChanged
El evento isMutedChanged
se desencadena cuando el audio local está silenciado o des-silencia.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación debería actualizar el botón de silenciar / reactivar audio con el estado adecuado.
Código de ejemplo:
call.on('isMutedChanged', (async (isMutedChangedEvent) => {
microphoneButton.disabled = call.isMuted;
});
Evento: isScreenSharingOnChanged
El evento isScreenSharingOnChanged
se desencadena cuando se habilita o deshabilita la pantalla compartida para el usuario local.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación debería mostrar una vista preliminar y/o una advertencia al usuario si la pantalla compartida se activó. Si se desactivó el uso compartido de la pantalla, la aplicación debería eliminar la vista previa y la advertencia.
Código de ejemplo:
call.on('isScreenSharingOnChanged', () => {
if (!this.call.isScreenSharing) {
displayStartScreenSharingButton();
hideScreenSharingWarning()
removeScreenSharingPreview();
} else {
displayScreenSharingWarning()
displayStopScreenSharingButton();
renderScreenSharingPreview();
}
});
Evento: isLocalVideoStartedChanged
El evento isLocalVideoStartedChanged
se desencadena cuando el usuario habilita o deshabilita su vídeo local.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación debería mostrar una vista previa del vídeo local y habilitar o deshabilitar el botón de activación de la cámara.
Código de ejemplo:
call.on('isLocalVideoStartedChanged', () => {
showdDisableCameraButton(call.isLocalVideoStarted);
});
Evento: remoteParticipantsUpdated
La aplicación debe suscribirse al evento para cada RemoteParticipants
agregado y cancelar la suscripción de eventos para los participantes que han dejado la llamada.
¿Cómo podría la aplicación reaccionar al evento? Su aplicación debería mostrar una vista previa del vídeo local y habilitar o deshabilitar el botón de activación de la cámara.
Código de ejemplo:
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
// - unsubcribe from the remote participants events
// - update the UI
removeParticipant(participant);
});
});
Evento: localVideoStreamsUpdated
El evento localVideoStreamsUpdated
se desencadena cuando cambia la lista de transmisión de vídeo local. Estos cambios se producen cuando el usuario inicia o quita una transmisión de vídeo.
¿Cómo podría la aplicación reaccionar al evento?
La aplicación debería mostrar vistas previas para cada uno de los LocalVideoStream
agregados. La aplicación debería quitar la vista previa y detener el procesamiento para cada LocalVideoStream
quitado.
Código de ejemplo:
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)
});
});
Evento: remoteAudioStreamsUpdated
El evento remoteAudioStreamsUpdated
se desencadena cuando cambia la lista de secuencias de audio remotas. Estos cambios se producen cuando los participantes remotos agregan o quitan transmisiones de audio en la llamada.
¿Cómo podría la aplicación reaccionar al evento?
Si se estaba procesando una transmisión y ahora se ha quitado, debería detenerse el procesamiento. Por otra parte, si se agrega una transmisión, la recepción del evento es un buen lugar para iniciar el procesamiento de la nueva transmisión de audio.
Evento: totalParticipantCountChanged
totalParticipantCountChanged
se desencadena cuando el número de totalParticipant ha cambiado en una llamada.
¿Cómo podría la aplicación reaccionar al evento?
Si la aplicación muestra un contador de participantes, la aplicación puede actualizar su contador de participantes cuando se recibe el evento.
Código de ejemplo:
call.on('totalParticipantCountChanged', () => {
participantCounterElement.innerText = call.totalParticipantCount;
});
Evento: roleChanged
El participante roleChanged
se desencadena cuando el rol de localParticipant cambia en la llamada. Un ejemplo sería cuando el participante local se convierte en moderador ACSCallParticipantRolePresenter
en una llamada.
¿Cómo podría la aplicación reaccionar al evento? Su aplicación debería habilitar o deshabilitar el botón en función del nuevo rol del usuario.
Código de ejemplo:
call.on('roleChanged', () => {
this.roleElement = call.role;
});
Evento: mutedByOthers
El evento mutedByOthers
se produce cuando otros participantes de la llamada son silenciados por el participante local.
¿Cómo podría la aplicación reaccionar al evento? Su aplicación debería mostrar un mensaje al usuario notificándole que ha sido silenciado.
Código de ejemplo:
call.on('mutedByOthers', () => {
messageBanner.innerText = "You have been muted by other participant in this call";
});
Evento: callerInfoChanged
El evento callerInfoChanged
se produce cuando se actualizó la información del autor de la llamada.
¿Cómo podría la aplicación reaccionar al evento? La aplicación puede actualizar la información del autor de la llamada.
Código de ejemplo:
call.on('callerInfoChanged', () => {
showCallerInfo(call.callerInfo)
});
Evento: transferorInfoChanged
El evento transferorInfoChanged
se produce cuando se actualizó la información del transferente.
¿Cómo podría la aplicación reaccionar al evento? La aplicación puede actualizar la información del transferor.
Código de ejemplo:
call.on('transferorInfoChanged', () => {
showTransferorInfo(call.transferorInfo)
});
Eventos en el objeto RemoteParticipant
Evento: roleChanged
El evento roleChanged
se desencadena cuando cambia el rol RemotePartipant
en la llamada. Un ejemplo sería cuando RemoteParticipant se convierte en moderador ACSCallParticipantRolePresenter
en una llamada.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación debería actualizar su interfaz de usuario en función del nuevo rol de RemoteParticipant
.
Código de ejemplo:
remoteParticipant.on('roleChanged', () => {
updateRole(remoteParticipant);
});
Evento: isMutedChanged
El evento isMutedChanged
se desencadena cuando uno de los RemoteParticipant
silencia o reactiva el audio de su micrófono.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación puede mostrar un icono cerca de la vista que muestra al participante.
Código de ejemplo:
remoteParticipant.on('isMutedChanged', () => {
updateMuteStatus(remoteParticipant); // Update the UI based on the mute state of the participant
});
Evento: displayNameChanged
displayNameChanged
cuando se actualiza el nombre del RemoteParticipant
.
¿Cómo podría la aplicación reaccionar al evento?
Su aplicación debería actualizar el nombre del participante si se está mostrando en la interfaz de usuario.
Código de ejemplo:
remoteParticipant.on('displayNameChanged', () => {
remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
});
Evento: isSpeakingChanged
isSpeakingChanged
cuando cambia el hablante dominante en una llamada.
¿Cómo podría la aplicación reaccionar al evento?
La interfaz de usuario de su aplicación debería dar prioridad a mostrar el RemotePartipant
que se convirtió en hablante dominante.
Código de ejemplo:
remoteParticipant.on('isSpeakingChanged', () => {
showAsRemoteSpeaker(remoteParticipant) // Display a speaking icon near the participant
});
Evento: videoStreamsUpdated
videoStreamsUpdated
cuando un participante remoto agrega o quita un VideoStream en la llamada.
¿Cómo podría la aplicación reaccionar al evento?
Si la aplicación estaba procesando una transmisión que se quita. La aplicación debería detener el procesamiento. Cuando se agrega una nueva transmisión, es posible que la aplicación quiera representarla o procesarla.
Código de ejemplo:
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)
});
});
Evento en el objeto AudioEffectsFeature
Evento: effectsStarted
Este evento se produce cuando el efecto de audio seleccionado se aplica a la transmisión de audio. Por ejemplo, cuando alguien activa la supresión de ruido, se activará la effectsStarted
.
¿Cómo podría la aplicación reaccionar al evento?
La aplicación puede mostrar o habilitar un botón que permita al usuario deshabilitar el efecto de audio.
Código de ejemplo:
audioEffectsFeature.on('effectsStarted', (effects) => {
stopEffectButton.style.visibility = "visible";
});
Evento: effectsStopped
Este evento se produce cuando el efecto de audio seleccionado se aplica a la transmisión de audio. Por ejemplo, cuando alguien desactiva la supresión de ruido, se activará effectsStopped
.
¿Cómo podría la aplicación reaccionar al evento?
La aplicación puede mostrar o habilitar un botón que permita al usuario habilitar el efecto de audio.
Código de ejemplo:
audioEffectsFeature.on('effectsStopped', (effects) => {
startEffectButton.style.visibility = "visible";
});
Evento: effectsError
Este evento se produce cuando se produce un error mientras se inicia o se aplica un efecto de audio.
¿Cómo podría la aplicación reaccionar al evento?
La aplicación debería mostrar una alerta o un mensaje de error que indica que el efecto de audio no funciona según lo previsto.
Código de ejemplo:
audioEffectsFeature.on('effectsError', (error) => {
console.log(`Error with the audio effect ${error}`);
alert(`Error with the audio effect`);
});
Instalación del SDK
Busque el archivo build.gradle
de nivel de proyecto y agregue mavenCentral()
a la lista de repositorios en buildscript
y allprojects
:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Luego, en el archivo build.gradle
de nivel de módulo, agregue las siguientes líneas a la sección dependencies
:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Inicialización de los objetos necesarios
Para crear una instancia de CallAgent
, debe llamar al método createCallAgent
en una instancia de CallClient
. Esta llamada devuelve un objeto de instancia de CallAgent
de manera asincrónica.
El método createCallAgent
toma CommunicationUserCredential
como argumento, que encapsula un token de acceso.
Para acceder a DeviceManager
, primero debe crear una instancia de callAgent
. A continuación, puede usar el método CallClient.getDeviceManager
para obtener 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();
Para establecer un nombre para mostrar para el autor de la llamada, use este método alternativo:
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();
Con su Android SDK, puede suscribirse a la mayoría de las propiedades y colecciones que se van a notificar al cambiar los valores.
Propiedades
Para suscribirse a eventos 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);
Cuando use clientes de escucha de eventos definidos dentro de la misma clase, enlace el cliente de escucha a una variable. Pase la variable como argumento para agregar y quitar métodos del cliente de escucha.
Si intenta pasar el cliente de escucha directamente como argumento, perderá la referencia a ese cliente de escucha. Java crea nuevas instancias de estos clientes de escucha y no hace referencia a las creadas anteriormente. Se seguirán apagando correctamente, pero no se pueden quitar porque ya no tendrá una referencia a ellos.
Colecciones
Para suscribirse a eventos 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);
Configuración del sistema
Siga estos pasos para configurar el sistema.
Creación del proyecto de Xcode
En Xcode, cree un nuevo proyecto de iOS y seleccione la plantilla Aplicación de una vista. En este artículo se usa el marco SwiftUI, por lo que debe establecer el Lenguaje en Swift y la Interfaz en SwiftUI.
No va a crear pruebas en este artículo. Puede desactivar la casilla Incluir pruebas.
Instalación del paquete y las dependencias mediante CocoaPods
Cree un Podfile para la aplicación, como en este ejemplo:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Ejecute
pod install
.Abra
.xcworkspace
mediante Xcode.
Solicitud de acceso al micrófono
Para acceder al micrófono del dispositivo, debe actualizar la lista de propiedades de información de la aplicación mediante NSMicrophoneUsageDescription
. Establezca el valor asociado en una cadena que se incluye en el cuadro de diálogo empleado por el sistema para solicitar acceso al usuario.
Haga clic con el botón derecho en la entrada Info.plist del árbol del proyecto y seleccione Abrir como>Código fuente. Agregue las líneas siguientes a la sección <dict>
de nivel superior y guarde el archivo.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Instalación del marco de la aplicación
Abra el archivo ContentView.swift
del proyecto. Agregue una declaración import
a la parte superior del archivo para importar la biblioteca AzureCommunicationCalling
. Además, importe AVFoundation
. Lo necesitará para las solicitudes de permiso de audio en el código.
import AzureCommunicationCalling
import AVFoundation
Inicialización de CallAgent
Para crear una instancia de CallAgent
a partir de CallClient
, debe usar el método callClient.createCallAgent
, que devuelve de manera asincrónica un objeto CallAgent
después de que se inicializa.
Para crear un cliente de llamada, pase un objeto 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)
}
Pase el objeto CommunicationTokenCredential
que ha creado a CallClient
y establezca el nombre para mostrar:
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")
}
})
Con nuestro SDK de iOS, puede suscribirse a la mayoría de las propiedades y colecciones para recibir una notificación cuando los valores cambien.
Propiedades
Para suscribirse a eventos property changed
, use el código siguiente.
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
Colecciones
Para suscribirse a eventos collection updated
, use el código siguiente.
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