Publicación y suscripción con el SDK de transmisión para iOS de IVS | Transmisión en tiempo real - Amazon IVS

Publicación y suscripción con el SDK de transmisión para iOS de IVS | Transmisión en tiempo real

Este documento explica los pasos necesarios para publicar y suscribirse a una fase mediante el SDK de transmisión para iOS de la transmisión en tiempo real de IVS.

Conceptos

Los siguientes tres conceptos básicos subyacen a la funcionalidad de transmisión en tiempo real: escenario, estrategia y renderizador. El objetivo del diseño es minimizar la cantidad de lógica necesaria por parte del cliente para crear un producto que funcione.

Escenario

La clase IVSStage es el principal punto de interacción entre la aplicación host y el SDK. La clase representa el escenario como tal y se usa para entrar y salir de él. Para crear un escenario o incorporarse a él, es necesaria una cadena de símbolos válida y que no haya vencido del plano de control (representada como token). Entrar a un escenario y salir de él es sencillo.

let stage = try IVSStage(token: token, strategy: self) try stage.join() stage.leave()

También se pueden adjuntar IVSStageRenderer y IVSErrorDelegate en la clase IVSStage:

let stage = try IVSStage(token: token, strategy: self) stage.errorDelegate = self stage.addRenderer(self) // multiple renderers can be added

Strategy (Estrategia)

El protocolo IVSStageStrategy proporciona una forma para que la aplicación host comunique el estado deseado del escenario al SDK. Es necesario implementar las siguientes tres funciones: shouldSubscribeToParticipant, shouldPublishParticipant y streamsToPublishForParticipant. Todas se analizan a continuación.

Suscripción a participantes

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType

Cuando un participante remoto se une a un escenario, el SDK consulta a la aplicación host sobre el estado de suscripción deseado para ese participante. Las opciones son .none, .audioOnly y .audioVideo. Al devolver un valor para esta función, la aplicación host no tiene que preocuparse por el estado de la publicación, el estado actual de la suscripción ni el estado de la conexión del escenario. Si se devuelve .audioVideo, el SDK espera a que el participante remoto publique antes de suscribirse y actualiza la aplicación host a través del renderizador durante todo el proceso.

Este es un ejemplo de implementación:

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioVideo }

Esta es la implementación completa de esta función para una aplicación host que siempre quiere que todos los participantes se vean entre sí; por ejemplo, una aplicación de videochat.

También son posibles implementaciones más avanzadas. Utilice la propiedad attributes en IVSParticipantInfo para suscribirse de forma selectiva a los participantes en función de los atributos proporcionados por el servidor:

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { switch participant.attributes["role"] { case "moderator": return .none case "guest": return .audioVideo default: return .none } }

Esto se puede utilizar para crear un escenario en el que los moderadores puedan monitorear a todos los invitados sin que ellos mismos los vean ni los escuchen. La aplicación host podría utilizar una lógica empresarial adicional para permitir que los moderadores se vean entre sí, pero permanezcan invisibles para los invitados.

Configuración de la suscripción a participantes

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration

Si se está subscribiendo a un participante remoto (consulte Suscripción a participantes), el SDK consulta a la aplicación host sobre una configuración de la subscrición personalizada para ese participante. Esta configuración es opcional y permite a la aplicación host controlar determinados aspectos del comportamiento de los suscriptores. Para obtener información sobre lo que se puede configurar, consulte SubscribeConfiguration en la documentación de referencia del SDK.

Este es un ejemplo de implementación:

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration { let config = IVSSubscribeConfiguration() try! config.jitterBuffer.setMinDelay(.medium()) return config }

Esta implementación actualiza el retraso mínimo del búfer de fluctuación para todos los participantes suscritos al valor preestablecido MEDIUM.

Como en el caso de shouldSubscribeToParticipant, también son posibles implementaciones más avanzadas. El valor de ParticipantInfo proporcionado se puede utilizar para actualizar selectivamente la configuración de suscripción para participantes específicos.

Se recomienda utilizar los comportamientos predeterminados. Especifique la configuración personalizada solo si hay un comportamiento en particular que desee cambiar.

Publicación

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool

Una vez realizada la conexión al escenario, el SDK consulta la aplicación host para ver si un participante en particular tiene que publicar. Esto solo se invoca en los participantes locales que tienen permiso para publicar en función del token proporcionado.

Este es un ejemplo de implementación:

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return true }

Esto es para una aplicación de videochat estándar en la que los usuarios siempre quieren publicar. Pueden activar y desactivar el sonido y el video para ocultarse o verse y escucharse al instante. (También pueden usar la opción de publicar o anular la publicación, pero esto es mucho más lento. Es preferible silenciar o activar el sonido en casos de uso en los que se quiera cambiar la visibilidad de manera frecuente).

Elección de las transmisiones que publicar

func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream]

Al publicar, esto se utiliza para determinar qué transmisiones de audio y video se tienen que publicar. Esto se explica en mayor detalle más adelante en Publicación de una transmisión multimedia.

Actualización de la estrategia

La estrategia pretende ser dinámica: los valores devueltos por cualquiera de las funciones anteriores se pueden cambiar en cualquier momento. Por ejemplo, si la aplicación host no quiere publicar hasta que el usuario final presione un botón, puede devolver una variable de shouldPublishParticipant (como hasUserTappedPublishButton). Cuando esa variable cambie en función de una interacción del usuario final, llame a stage.refreshStrategy() para indicar al SDK que debe consultar la estrategia a fin de obtener los valores más recientes y aplicar solo los cambios. Si el SDK observa que el valor shouldPublishParticipant cambió, iniciará el proceso de publicación. Si las consultas del SDK y todas las funciones devuelven el mismo valor que antes, la llamada refreshStrategy no hará ninguna modificación en el escenario.

Si el valor devuelto de shouldSubscribeToParticipant cambia de .audioVideo a .audioOnly, la transmisión de video se eliminará para todos los participantes con valores devueltos modificados, si ya existía con anterioridad una transmisión de video.

Por lo general, el escenario utiliza la estrategia para aplicar de la manera más eficiente la diferencia entre las estrategias anteriores y actuales, sin que la aplicación host tenga que preocuparse por todo el estado necesario para administrarla correctamente. Por eso, piense en la llamada a stage.refreshStrategy() como una operación barata, porque no hace nada a no ser que cambie la estrategia.

Renderer

El protocolo IVSStageRenderer comunica el estado del escenario a la aplicación host. Por lo general, los eventos proporcionados por el renderizador permiten el funcionamiento completo de las actualizaciones de la interfaz de usuario de la aplicación host. El renderizador ofrece el siguiente resultado:

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participantDidLeave participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange publishState: IVSParticipantPublishState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange subscribeState: IVSParticipantSubscribeState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didAdd streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didRemove streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) func stage(_ stage: IVSStage, didChange connectionState: IVSStageConnectionState, withError error: Error?)

No se espera que la información que proporciona el renderizador afecte a los valores de retorno de la estrategia. Por ejemplo, no se espera que el valor devuelto de shouldSubscribeToParticipant cambie cuando se llama a participant:didChangePublishState. Si la aplicación host quiere suscribirse a un participante en particular, debe devolver el tipo de suscripción deseado, independientemente del estado de publicación de ese participante. El SDK es responsable de garantizar que se aplique el estado deseado de la estrategia en el momento correcto según el estado del escenario.

Tenga en cuenta que solo los participantes que publican desencadenan participantDidJoin. participantDidLeave se desencadena cada vez que un participante deja de publicar o abandona la sesión del escenario.

Publicación de una transmisión multimedia

Los dispositivos locales, como las cámaras y los micrófonos integrados, se detectan a través de IVSDeviceDiscovery. A continuación, se muestra un ejemplo de cómo seleccionar la cámara frontal y el micrófono predeterminados y devolverlos como IVSLocalStageStreams para que los publique el SDK:

let devices = IVSDeviceDiscovery().listLocalDevices() // Find the camera virtual device, choose the front source, and create a stream let camera = devices.compactMap({ $0 as? IVSCamera }).first! let frontSource = camera.listAvailableInputSources().first(where: { $0.position == .front })! camera.setPreferredInputSource(frontSource) let cameraStream = IVSLocalStageStream(device: camera) // Find the microphone virtual device and create a stream let microphone = devices.compactMap({ $0 as? IVSMicrophone }).first! let microphoneStream = IVSLocalStageStream(device: microphone) // Configure the audio manager to use the videoChat preset, which is optimized for bi-directional communication, including echo cancellation. IVSStageAudioManager.sharedInstance().setPreset(.videoChat) // This is a function on IVSStageStrategy func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream] { return [cameraStream, microphoneStream] }

Visualización y eliminación de participantes

Cuando se complete la suscripción, recibirá una matriz de objetos IVSStageStream a través de la función didAddStreams del renderizador. Para obtener una vista previa o recibir estadísticas del audio de este participante, puede acceder al objeto IVSDevice subyacente desde la transmisión:

if let imageDevice = stream.device as? IVSImageDevice { let preview = imageDevice.previewView() /* attach this UIView subclass to your view */ } else if let audioDevice = stream.device as? IVSAudioDevice { audioDevice.setStatsCallback( { stats in /* process stats.peak and stats.rms */ }) }

Cuando un participante deja de publicar o anula su suscripción, se invoca la función didRemoveStreams con las transmisiones que se eliminaron. Las aplicaciones host tienen que usar esto como una señal para eliminar la transmisión de video del participante de la jerarquía de visualización.

didRemoveStreams se invoca para todas las situaciones en las que se puede eliminar una transmisión, como las siguientes:

  • El participante remoto deja de publicar.

  • Un dispositivo local cancela la suscripción o cambia la suscripción de .audioVideo a .audioOnly.

  • El participante remoto abandona el escenario.

  • El participante local abandona el escenario.

Ya que didRemoveStreams se invoca en todas las situaciones, no es necesaria una lógica empresarial personalizada para eliminar a los participantes de la interfaz de usuario durante las operaciones de licencia remota o local.

Activación y desactivación del sonido de las transmisiones multimedia

Los objetos de IVSLocalStageStream tienen una función setMuted que controla si la transmisión está silenciada. Esta función se puede invocar en la transmisión antes o después de que la devuelva la función de estrategia streamsToPublishForParticipant.

Importante: Si streamsToPublishForParticipant devuelve una nueva instancia de objeto de IVSLocalStageStream después de una llamada a refreshStrategy, el estado de sonido desactivado del nuevo objeto de transmisión se aplicará al escenario. Tenga cuidado al crear nuevas instancias IVSLocalStageStream para asegurarse de que se mantenga el estado de sonido desactivado que se espera.

Monitoreo del estado de sonido desactivado en los contenidos multimedia del participante remoto

Cuando un participante cambia el estado de sonido desactivado de su transmisión de video o audio, se invoca la función didChangeMutedStreams de renderizado con una lista de las transmisiones que cambiaron. Use la propiedad isMuted en IVSStageStream para actualizar su interfaz de usuario según corresponda:

func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) { streams.forEach { stream in /* stream.isMuted */ } }

Creación de una configuración de escenario

Para personalizar los valores de la configuración de video de un escenario, utilice IVSLocalStageStreamVideoConfiguration:

let config = IVSLocalStageStreamVideoConfiguration() try config.setMaxBitrate(900_000) try config.setMinBitrate(100_000) try config.setTargetFramerate(30) try config.setSize(CGSize(width: 360, height: 640)) config.degradationPreference = .balanced

Obtención de estadísticas de WebRTC

Para obtener las estadísticas más recientes de WebRTC de una transmisión de publicación o de suscripción, utilice requestRTCStats en IVSStageStream. Cuando se complete una recopilación, recibirá estadísticas a través de IVSStageStreamDelegate, que se puede configurar en IVSStageStream. Para recopilar continuamente estadísticas de WebRTC, llame a esta función en un Timer.

func stream(_ stream: IVSStageStream, didGenerateRTCStats stats: [String : [String : String]]) { for stat in stats { for member in stat.value { print("stat \(stat.key) has member \(member.key) with value \(member.value)") } } }

Obtención de los atributos de los participantes

Si especifica atributos en la solicitud del punto de conexión de CreateParticipantToken, puede ver los atributos en las propiedades de IVSParticipantInfo:

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) { print("ID: \(participant.participantId)") for attribute in participant.attributes { print("attribute: \(attribute.key)=\(attribute.value)") } }

Continuación de la sesión en segundo plano

Cuando la aplicación pasa a segundo plano, puede seguir en el escenario mientras escucha el audio remoto, aunque no podrá enviar su propia imagen y audio. Es necesario que actualice la implementación IVSStrategy para detener la publicación y se suscriba a .audioOnly (o a .none, si corresponde):

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return false } func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioOnly }

A continuación, haga una llamada a stage.refreshStrategy().

Activación o desactivación de la codificación en capas con transmisión simultánea

Al publicar una transmisión multimedia, el SDK transmite transmisión de video de alta y baja calidad, de modo que los participantes remotos puedan suscribirse a transmisión incluso si tienen un ancho de banda de enlace descendente limitado. La codificación en capas con transmisión simultánea está activada de forma predeterminada. Puede desactivarla con IVSSimulcastConfiguration:

// Disable Simulcast let config = IVSLocalStageStreamVideoConfiguration() config.simulcast.enabled = false let cameraStream = IVSLocalStageStream(device: camera, configuration: config) // Other Stage implementation code

Transmisión del escenario a un canal de IVS

Para transmitir un escenario, cree una IVSBroadcastSession independiente y, a continuación, siga las instrucciones habituales para la transmisión con el SDK, descritas con anterioridad. La propiedad device en IVSStageStream será un IVSImageDevice o IVSAudioDevice, tal y como se muestra en el fragmento anterior. Estos se pueden conectar a IVSBroadcastSession.mixer para transmitir todo el escenario en un diseño personalizable.

Si lo desea, puede componer un escenario y transmitirlo a un canal de IVS de baja latencia para llegar a un público más amplio. Consulte Habilitación de varios hosts en una transmisión de Amazon IVS en la Guía del usuario de transmisión de baja latencia.