Compartir vía


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 matriz added que contiene los valores que se quitaron de la colección.
  • La carga del evento '<collection>Updated' también tiene una matriz removed 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.

Captura de pantalla que muestra la ventana para crear un proyecto en Xcode.

Instalación del paquete y las dependencias mediante CocoaPods

  1. 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
    
  2. Ejecute pod install.

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

Pasos siguientes