Suscribirse a canales — Web
Una vez que haya conectado a una sesión, puedes suscribirte a las transmisiones de la sesión. Cuando te suscribes a una transmisión, su vídeo aparece en la página del cliente y se reproduce su audio.
Este tema incluye las siguientes secciones:
- Detectar cuándo se crean nuevas secuencias
- Suscribirse a una transmisión
- Darse de baja de un canal
- Reconexión automática
- Restricción de la frecuencia de fotogramas de una transmisión a la que se está suscrito
- Detectar cuándo los flujos abandonan una sesión
- Detectar cuándo se bloquea o desbloquea el audio de un abonado
- Detectar cuándo se desactiva el vídeo de un suscriptor
- Detectar cuándo cambian las dimensiones del vídeo de una transmisión
- Obtener información sobre un flujo
- Ajuste de la frecuencia de imagen y la resolución preferidas
- Aplicar filtros y efectos al contenido de audio y vídeo al que estás suscrito
- Detección de cambios en la calidad del audio y el vídeo
- Solución de problemas
- Implementación de los reintentos de suscripción a la sesión
Detectar cuándo se crean flujos en una sesión
El objeto «Session» envía un streamCreated evento que se produce cuando se crea un nuevo flujo (que no sea el tuyo) en una sesión. Se crea un flujo cuando un cliente publica un flujo a la sesión. El streamCreated para cada flujo existente en la sesión cuando se conecta por primera vez. Este evento está definido por el StreamEvent, que tiene un atributo stream propiedad, que representa el flujo que se ha creado:
session.on("streamCreated", function (event) {
console.log("New stream in the session: " + event.stream.streamId);
});
// Replace with a valid token:
session.connect(token);
Puede suscribirse a cualquier flujo. Consulte la sección siguiente.
Suscribirse a una transmisión
Para suscribirse a un flujo, pasa el objeto Stream al subscribe del objeto Session:
session.subscribe(stream, replacementElementId);
El subscribe() recibe los siguientes parámetros:
-
stream—El objeto Stream. -
targetElement— (Opcional) Define el elemento DOM que sustituye el vídeo del suscriptor. -
properties— (Opcional) Un conjunto de propiedades que personalizan el aspecto de la vista «Suscriptor» en la página HTML (véase Personalizar la interfaz de usuario) y elige si deseas suscribirte al contenido de audio y vídeo (véase Ajustar el audio y el vídeo). -
completionHandler— (Opcional) Una función que se invoca de forma asíncrona cuando la llamada a lasubscribe()el método se ejecuta correctamente o falla. Si la llamada alsubscribe()falla, el controlador de finalización recibe un objeto de error. Este objeto tiene uncodeymessageque describen el error.
El siguiente código se suscribe a todas las secuencias, excepto a las publicadas por tu cliente:
session.on("streamCreated", function(event) {
session.subscribe(event.stream);
});
// Replace with your API key and token:
session.connect(token, function (error) {
if(error) {
// failed to connect
}
});
El insertMode propiedad del properties del Session.subscribe() especifica cómo se insertará el objeto Publisher en el DOM HTML, en relación con el método targetElement parámetro. Puede establecer este parámetro en uno de los siguientes valores:
"replace"— El objeto «Subscriber» sustituye el contenido del «targetElement». Este es el valor por defecto."after"— El objeto «Subscriber» es un nuevo elemento insertado después del «targetElement» en el DOM HTML. (Tanto «Subscriber» como «targetElement» tienen el mismo elemento padre.)"before"— El objeto «Subscriber» es un nuevo elemento insertado antes del «targetElement» en el DOM HTML. (Tanto «Subscriber» como «targetElement» tienen el mismo elemento padre.)"append"- El objeto Subscriber es un nuevo elemento que se añade como hijo del targetElement. Si hay otros elementos hijos, el Publisher se añade como último elemento hijo del targetElement.
Por ejemplo, el siguiente código añade un nuevo objeto Subscriber como hijo de un objeto subscriberContainer Elemento DOM:
session.on('streamCreated', function(event) {
var subscriberProperties = {insertMode: 'append'};
var subscriber = session.subscribe(event.stream,
'subscriberContainer',
subscriberProperties,
function (error) {
if (error) {
console.log(error);
} else {
console.log('Subscriber added.');
}
});
});
El objeto «Subscriber» tiene un element propiedad, cuyo valor es el elemento DOM de HTML que la contiene.
Si no quieres utilizar la interfaz de usuario predeterminada, puedes acceder a la Video elemento para el suscriptor (véase este tema). También puedes utilizar tu propio Video elemento para mostrar el vídeo del suscriptor y utilizar el objeto `MediaStream` del suscriptor como fuente multimedia para ese Video elemento (véase este tema).
Darse de baja de un canal
Para detener la reproducción de una transmisión a la que estás suscrito, pasa el objeto «Subscriber» al unsubscribe() del objeto Session:
session.unsubscribe(subscriber);
El objeto Subscriber se destruye y la visualización del flujo se elimina del DOM HTML.
Detectar cuándo los flujos abandonan una sesión
Cuando un flujo, que no sea el propio, abandona una sesión, el objeto Session envía un streamDestroyed evento:
session.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
Cuando un flujo que publicas sale de una sesión, el objeto Publisher envía un streamDestroyed evento:
var publisher = OT.initPublisher();
publisher.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
El streamDestroyed El evento viene definido por la clase StreamEvent. El evento incluye un reason que detalla por qué ha finalizado el flujo. Estas razones incluyen "clientDisconnected", "forceDisconnected", "forceUnpublished", o "networkDisconnected". Para más detalles, véase StreamEvent.
Por defecto, cuando un streamDestroyed Cuando se envía un evento para un flujo al que estás suscrito, los objetos Subscriber correspondientes (puede haber más de uno) se destruyen y se eliminan del DOM HTML. Puedes evitar este comportamiento predeterminado llamando a la función preventDefault() del objeto StreamEvent:
session.on("streamDestroyed", function (event) {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
// Now you can adjust the DOM elements around each
// subscriber to the stream, and then delete it yourself.
});
Tenga en cuenta que el getSubscribersForStream() de un objeto Session devuelve todos los objetos Subscriber de un Stream.
Es posible que quieras evitar el comportamiento predeterminado y conservar el suscriptor si deseas ajustar los elementos DOM relacionados antes de eliminar tú mismo el suscriptor. A continuación, puedes eliminar el objeto suscriptor (y su elemento DOM) llamando a la función destroy() método del objeto Subscriber.
Un objeto Subscriber envía un destroyed evento que se produce cuando el objeto se ha eliminado del DOM HTML. En respuesta a este evento, puedes optar por modificar (o eliminar) los elementos del DOM relacionados con el suscriptor que se ha eliminado.
Reconexión automática
Si un cliente pierde la conexión con un flujo al que está suscrito (por ejemplo, debido a una interrupción de la conectividad de red en cualquiera de los clientes), intentará volver a conectarse automáticamente al flujo. Cuando se interrumpe el flujo y el cliente intenta volver a conectarse, el objeto «Subscriber» envía un disconnected evento. Cuando se restablece el flujo, el objeto «Subscriber» emite un connected evento. Si el cliente no puede restaurar el flujo, el objeto Subscriber envía un evento destroyed evento.
En respuesta a estos eventos, tu aplicación puede (opcionalmente) mostrar notificaciones en la interfaz de usuario indicando los estados de desconexión temporal, reconexión y destrucción:
subscriber.on(
disconnected: function() {
// Display a user interface notification.
},
connected: function() {
// Adjust user interface.
},
destroyed: function() {
// Adjust user interface.
}
);
Restricción de la frecuencia de fotogramas de una transmisión a la que se está suscrito
También puedes limitar la frecuencia de fotogramas de la transmisión de vídeo de un suscriptor. Para limitar la frecuencia de fotogramas de un suscriptor, llama a la función restrictFrameRate() método del objeto Subscriber, pasando como parámetro true:
subscriber.restrictFrameRate(true);
Pasa el balón a false y la frecuencia de fotogramas de la transmisión de vídeo no está limitada:
subscriber.restrictFrameRate(false);
Cuando la frecuencia de imagen está restringida, la imagen de vídeo del abonado se actualizará una vez por segundo o menos.
Esta función solo está disponible en las sesiones que utilizan OpenTok Media Router (sesiones con el modo multimedia (configurado en «routed»), pero no en sesiones cuyo modo multimedia esté configurado en «relayed». En sesiones de tipo «relayed», llamar a este método no tiene ningún efecto.
La restricción de la frecuencia de imagen del abonado tiene las siguientes ventajas:
- Reduce el uso de la CPU.
- Reduce el ancho de banda de red que consume la aplicación.
- Te permite suscribirte a más flujos simultáneamente.
Reducir la frecuencia de fotogramas de un suscriptor no afecta a la frecuencia de fotogramas del vídeo en otros clientes.
Detectar cuándo se bloquea o desbloquea el audio de un abonado
Algunos navegadores bloquean automáticamente la reproducción de audio, requiriendo un click antes de que comience la reproducción de audio para los abonados. Estos navegadores incluyen Safari, Firefox 66+ y Chrome 71+.
El objeto «Subscriber» muestra un botón de reproducción de audio si la reproducción está bloqueada. Puedes desactivar el botón de reproducción de audio predeterminado del «Subscriber» y mostrar tu propio elemento de interfaz de usuario en el que el usuario hará clic para iniciar la reproducción de audio. Consulta Visualización de un elemento de interfaz de usuario personalizado cuando el audio del abonado está bloqueado.
Cuando se bloquea el audio del suscriptor, el objeto «Subscriber» envía un audioBlocked evento, y envía un audioUnblocked evento que se produce cuando se desbloquea el audio:
subscriber.on({
audioBlocked: function(event) {
console.log("Subscriber audio is blocked.")
},
audioUnblocked: function(event) {
console.log("Subscriber audio is unblocked.")
}
});
Además, el suscriptor incluye un isAudioBlocked() que devuelve true si el audio está bloqueado o false si no es así.
El audio del abonado se desbloquea cuando ocurre alguna de las siguientes situaciones:
- El usuario hace clic en el icono predeterminado de reproducción de audio del suscriptor
- El OT.desbloquearAudio() El método se invoca en respuesta a la activación de un elemento HTML que envía un
clickevento (si has desactivado el icono predeterminado de reproducción de audio) - El cliente local obtiene acceso a la cámara o al micrófono (por ejemplo, tras una llamada satisfactoria a
OT.initPublisher()).
Para más información, consulte este artículo de Mozilla sobre la reproducción automática en Firefox y este artículo de Google sobre la reproducción automática en Chrome.
Detectar cuándo se desactiva el vídeo de un suscriptor
Cuando se desactiva el vídeo del suscriptor, el objeto «Subscriber» envía un videoDisabled evento:
subscriber.on("videoDisabled", function(event) {
// You may want to hide the subscriber video element:
domElement = document.getElementById(subscriber.id);
domElement.style["visibility"] = "hidden";
// You may want to add or adjust other UI.
});
Cuando el OpenTok Media Router, o un editor con la función de alternativa activada, desactiva el vídeo de un suscriptor, es posible que desees ajustar la interfaz de usuario relacionada con dicho suscriptor.
El reason propiedad del videoDisabled define la razón por la que se ha desactivado el vídeo. Se puede establecer en uno de los siguientes valores:
-
"publishVideo"— La editorial dejó de publicar vídeos tras recibir una llamadapublishVideo(false). -
"quality"— El OpenTok Media Router, o el cliente de publicación si opción alternativa de audio del editor Si está activada, deja de enviar vídeo al suscriptor en función de los cambios en la calidad de la transmisión. Esta función del OpenTok Media Router hace que el suscriptor interrumpa la transmisión de vídeo cuando la conectividad se deteriora. (El suscriptor sigue recibiendo la transmisión de audio, si la hay). La función de recambio de audio del emisor hace que este deje de emitir la transmisión de vídeo cuando se deteriora su conexión y, posteriormente, el suscriptor interrumpe la transmisión de vídeo.Antes de enviar este evento, cuando la calidad de la transmisión del suscriptor se deteriora, o cuando la calidad de la transmisión de un emisor con la función de recambio activada se deteriora hasta un nivel tan bajo que la transmisión de vídeo corre el riesgo de desactivarse, el suscriptor envía un
videoDisableWarningevento.Si la conectividad mejora y vuelve a permitir la transmisión de vídeo, el objeto «Subscriber» envía un
videoEnabledevento, y el suscriptor vuelve a recibir el vídeo.Por defecto, el Suscriptor muestra un indicador de vídeo desactivado cuando un
videoDisabledEl evento con este motivo se envía y elimina el indicador cuando elvideoDisabledSe envía un evento con este motivo. Puedes controlar la visualización de este icono llamando a la funciónsetStyle()método del suscriptor, estableciendo elvideoDisabledDisplayModepropiedad; o bien puedes establecer el estilo al llamar a laSession.subscribe()método, configurando elstylepropiedad delpropertiesparámetro.Esta función solo está disponible en las sesiones que utilizan OpenTok Media Router (sesiones con el modo multimedia (configurado en «routed»), o en sesiones con un editor que tenga habilitada la función de recambio. Véase «Editor con función de recambio habilitada» documentos.
Al publicar un flujo, puede evitar que se desactive su vídeo debido a la calidad del flujo. Establezca
audioFallbackEnabledafalseen elpropertiesobjeto pasado a la OT.initPublisher() método (esta función quedará obsoleta), o bien configurarsubscriberafalseen elaudioFallbackobjeto pasado comopropertiesdel OT.initPublisher() método. -
"subscribeToVideo"— El suscriptor ha activado o cancelado su suscripción al servicio de vídeo llamando alsubscribeToVideo(false). -
"codecNotSupported"- El abonado ha dejado de abonarse al vídeo debido a un códec incompatible (consulte la sección Códecs de vídeo (Guía para desarrolladores).
El suscriptor envía un videoEnabled cuando se reanude el vídeo:
subscriber.on("videoEnabled", function(event) {
// You may want to display the subscriber video element,
// if it was hidden:
domElement = document.getElementById(subscriber.id);
domElement.style["visibility"] = "visible";
// You may want to add or adjust other UI.
});
El reason propiedad del videoEnabled El objeto «event» define el motivo por el que se activó el vídeo. Se puede establecer en uno de los siguientes valores:
-
"publishVideo"— La editorial comenzó a publicar vídeos llamando apublishVideo(true). -
"quality"— El OpenTok Media Router, o el emisor con función de conmutación de reserva, reanudó el envío de vídeo al suscriptor en función de los cambios en la calidad de la transmisión. Esta función del OpenTok Media Router hace que el suscriptor interrumpa la transmisión de vídeo cuando la conectividad se deteriora y, posteriormente, la reanude si la calidad de la transmisión mejora. La función de recambio de audio del emisor hace que este deje de emitir la transmisión de vídeo cuando se deteriora su conexión y, posteriormente, el suscriptor interrumpa la transmisión de vídeo.Esta función solo está disponible en las sesiones que utilizan OpenTok Media Router (sesiones con el modo multimedia (configurado como «routed»), o en sesiones con un editor que tenga habilitada la opción de recambio.
-
"subscribeToVideo"— El suscriptor ha activado o cancelado su suscripción al servicio de vídeo llamando alsubscribeToVideo(false). -
"codecChanged"- El vídeo de abonado se habilitó después de un cambio de códec incompatible (consulte la sección Códecs de vídeo (Guía para desarrolladores).
Detectar cuándo cambian las dimensiones del vídeo de la transmisión de un suscriptor
Las dimensiones de la transmisión de vídeo de un suscriptor pueden cambiar si una transmisión publicada desde un dispositivo móvil cambia de tamaño, debido a un cambio en la orientación del dispositivo. También puede ocurrir si la fuente de vídeo es una ventana de pantalla compartida y el usuario que publica la transmisión cambia el tamaño de la ventana que sirve de fuente para la transmisión. Cuando cambian las dimensiones del vídeo, el objeto «Subscriber» envía un videoDimensionsChanged evento.
El siguiente código ajusta el tamaño de un suscriptor cuando cambian las dimensiones del vídeo de la transmisión:
subscriber.on('videoDimensionsChanged', function(event) {
subscriber.element.style.width = event.newValue.width + 'px';
subscriber.element.style.height = event.newValue.height + 'px';
// You may want to adjust other UI.
});
Obtener información sobre un flujo
El objeto `Stream` tiene las siguientes propiedades que definen el flujo:
connection—El objeto `Connection` correspondiente a la conexión que está publicando el flujo. Se puede comparar con elconnectionpropiedad del objeto Session para comprobar si la página web local está publicando el flujo.creationTime—La marca de tiempo (un número) correspondiente a la creación del flujo. Este valor se calcula en milisegundos. Puedes convertir este valor en un objeto Date llamando anew Date(stream.creationTime).hasAudio—(Booleano) Indica si la transmisión tiene audio. Esta propiedad puede cambiar si el emisor activa o desactiva el audio (mediante la llamada a Publisher.publishAudio()). Cuando esto ocurre, el Sesión El objeto envía unstreamPropertyChangedevento.hasVideo-(Boolean) Si el flujo tiene vídeo.initials—(Booleano) Las iniciales del flujo (si se establecieron al crear el editor del flujo se inicializó).name—(Cadena) El nombre del flujo. Por defecto, este nombre se muestra cuando el usuario pasa el ratón por encima del suscriptor en el DOM de HTML. No obstante, puedes personalizar la interfaz de usuario para ocultar el nombre o mostrarlo sin necesidad de pasar el ratón por encima.videoDimensions—Este objeto tiene dos propiedades:widthyheight. Ambos son números. Elwidthes la anchura del flujo codificado; la propiedadheightes la altura del flujo codificado. (Es independiente de la anchura real de los objetos Publisher y Subscriber correspondientes al flujo). Esta propiedad puede cambiar si un flujo publicado desde un dispositivo iOS cambia de tamaño, basándose en un cambio en la orientación del dispositivo.videoType—El tipo de vídeo: puede ser «cámara», «pantalla», «personalizado» o indefinido. Un vídeo de tipo «pantalla» utiliza la función de compartir pantalla del editor como fuente de vídeo; un vídeo de tipo «personalizado» utiliza un elemento VideoTrack como fuente de vídeo en el editor. ElvideoTypeesundefinedcuando un flujo es sólo de voz (véase la sección Guía solo de voz). Esta propiedad puede cambiar si una transmisión publicada desde un dispositivo móvil pasa de ser un vídeo de cámara a un vídeo de pantalla compartida. Para obtener más información, consulta Compartir pantalla - Web.
El hasAudio, hasVideo, videoDimensionsy videoType Las propiedades pueden cambiar (por ejemplo, cuando el presentador activa o desactiva el vídeo). Cuando esto ocurre, el Sesión El objeto envía un streamPropertyChanged evento (véase StreamPropertyChangedEvent.)
El getStats() El método de un objeto «Subscriber» te proporciona información sobre el flujo del suscriptor. Para obtener estadísticas de bajo nivel sobre la conexión entre pares, utiliza el Subscriber.getRtcStatsReport() método. Devuelve una promesa que, en caso de éxito, se resuelve con un RtcStatsReport objeto correspondiente al flujo al que se ha suscrito.
Consulte guía del desarrollador de la observabilidad del cliente para obtener información detallada.
Ajuste de la frecuencia de imagen y la resolución preferidas
Al suscribirse a una transmisión que utiliza el función de vídeo escalable, tienes la opción de configurar preferredResolution a "auto" para gestionar automáticamente la resolución de vídeo de los suscriptores en función del tamaño en el que se reproduce, con el fin de optimizar el uso de la red y de la CPU. Los usuarios avanzados también pueden configurar manualmente la frecuencia de fotogramas y la resolución preferidas para la transmisión que el cliente suscrito recibe del OpenTok Media Router. Puedes configurarlas como preferredFrameRate y preferredResolution propiedades del options entras en el [`Session.subscribe()`](/video/sdk-reference/js/Session.html#subscribe) método. Recomendamos configurar preferredResolution a "auto". Con el "auto" Con esta configuración, OpenTok.js selecciona la resolución preferida en función de las dimensiones del vídeo del suscriptor en el navegador. También puedes configurar la frecuencia de fotogramas y la resolución preferidas tras suscribirte a una transmisión (véase [`Subscriber.setPreferredFrameRate()`](/opentok/sdks/js/reference/Subscriber.html#setPreferredFrameRate) y Subscriber.setPreferredResolution()).
Nota: En "auto" La configuración de la resolución solo se aplica cuando se utiliza el elemento «Subscriber Video» predeterminado creado por el SDK. No funciona si creas tu propio elemento «Video» en respuesta a la videoElementCreated evento (véase este tema).
Nota: Estas preferencias dan por hecho que el editor utiliza la disposición predeterminada de la capa de escalabilidad. Si el editor ha configurado un modo de escalabilidad de destino distinto del predeterminado (véase Configuración del modo de escalabilidad deseado), es posible que la selección de capa del Media Router no coincida con la resolución o la frecuencia de fotogramas solicitadas. Véase Interacción con la resolución y la frecuencia de fotogramas preferidas por el suscriptor Para más información.
Aplicar filtros y efectos al contenido de audio y vídeo al que estás suscrito
Puedes aplicar filtros y efectos a las pistas de audio o vídeo de una transmisión a la que estés suscrito; consulta este tema.
Detección de cambios en la calidad del audio y el vídeo
Si un cliente sufre períodos de deterioro en la conectividad de red, esto puede repercutir en la calidad de la llamada del abonado. El objeto «Abonado» envía un qualityScoreChanged situación en la que cambian las puntuaciones MOS calculadas para el audio y el vídeo. Estas puntuaciones se expresan como números enteros comprendidos entre 1 (la peor) y 5 (la mejor), que corresponden a «malo», «deficiente», «aceptable», «bueno» y «excelente». Para obtener más detalles, consulta el apartado «Suscriptor» qualityScoreChanged evento.
Un objeto «Subscriber» envía este evento únicamente cuando ha cambiado uno de los índices de calidad. Cada «Subscribe» envía eventos con sus propios índices de calidad de audio y vídeo, dependiendo de si se está suscribiendo al audio, al vídeo o a ambos.
En respuesta a estos sucesos, tu aplicación puede (de forma opcional) notificar al cliente las condiciones de la red que provocan una disminución de la calidad de la llamada:
subscriber.on('qualityScoreChanged', ({qualityScore}) => {
if (qualityScore.audioQualityScore <= 3){
// Alert the user that the remote party is experiencing degraded service
}
if (qualityScore.videoQualityScore <= 3){
// Alert the user that the remote party is experiencing degraded service
}
});
Solución de problemas
Sigue los consejos de esta sección para evitar problemas de conexión al darte de alta. Para obtener información general sobre la resolución de problemas, consulta Depuración — Web.
Gestión de errores
Gestionar los errores al suscribirse es un poco más sencillo que al publicar. Solo hay una forma de suscribirse: mediante el Session.subscribe() método, y prácticamente cualquier error que se produzca al suscribirse se debe a un problema de red. Esto puede ocurrir si, por ejemplo, el usuario se encuentra en una conexión de red muy restrictiva que no permite conexiones WebRTC (aunque la conexión WebSocket sí haya funcionado). Si el suscriptor no consigue conectarse, simplemente mostrará su propio mensaje de error en el propio suscriptor. No tiene un aspecto especialmente agradable y no resulta muy informativo para el usuario final. Te recomendamos que gestiones este caso tú mismo y muestres un mensaje al usuario indicándole que no ha podido suscribirse y que debe comprobar su conexión de red. La gestión de estos errores se realiza de la siguiente manera:
session.subscribe(event.stream, 'subscriber', {insertMode: 'append'}, function (err) {
if (err) {
showMessage('Streaming connection failed. This could be due to a restrictive firewall.');
}
});
Perder conectividad
Tu suscriptor también puede perder la conexión después de haberse conectado correctamente. En la mayoría de los casos, esto también provocará que la sesión pierda la conexión, pero no siempre es así. Además, puede que sea el editor del otro lado el que haya perdido la conexión, en lugar de que se haya perdido la conexión a nivel local. Puedes gestionar la desconexión del suscriptor escuchando el streamDestroyed evento en la sesión con un reason propiedad establecida en «networkDisconnected», de esta forma:
session.on({
streamDestroyed: function (event) {
if (event.reason === 'networkDisconnected') {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
if (subscribers.length > 0) {
var subscriber = document.getElementById(subscribers[0].id);
// Display error message inside the Subscriber
subscriber.innerHTML = 'Lost connection. This could be due to your internet connection '
+ 'or because the other party lost their connection.';
event.preventDefault(); // Prevent the Subscriber from being removed
}
}
}
});
Implementación de los reintentos de suscripción a la sesión
Pueden producirse fallos temporales en la suscripción cuando session.subscribe() se invoca y no se puede establecer a tiempo la conexión WebRTC subyacente, o cuando un fallo momentáneo de la red interrumpe la negociación ICE. Cuando session.subscribe() Si falla, el SDK devuelve un error a través de la llamada de retorno de su manejador de finalización. Se recomienda implementar una lógica de reintentos a nivel de la aplicación con un intervalo de tiempo entre cada intento.
Nota: Compatibilidad integrada con reintentos para session.subscribe() Está incluido en la hoja de ruta del SDK. Hasta que se lance, tendrás que implementarlo tú mismo.
Por qué se producen errores en las suscripciones
Las causas fundamentales más habituales de los fallos transitorios en las suscripciones son:
OT_TIMEOUT(código 1501): La suscripción no se ha completado dentro del plazo permitido (30 segundos). Se trata del equivalente, por parte del suscriptor, al tiempo de espera de publicación, y es el error más habitual que se puede reintentar.- Fracasos en las negociaciones con el ICE (
OT_ICE_WORKFLOW_FAILED): No se ha podido establecer la conexión entre pares de WebRTC, normalmente debido a una red restrictiva o a un problema de conectividad pasajero. - Errores en la creación de conexiones entre pares (
OT_CREATE_PEER_CONNECTION_FAILED): No se ha podido crear el objeto de conexión entre pares de WebRTC, lo que suele deberse a un problema temporal de la plataforma o de la red. - Problemas de red durante el proceso de suscripción: Una breve interrupción de la red durante la negociación del ICE o la vinculación de medios puede provocar que la suscripción caduque sin que se produzca un error grave.
Errores recuperables frente a errores no recuperables
No todos session.subscribe() No todos los errores son iguales. Es fundamental clasificar correctamente los errores antes de volver a intentarlo: volver a intentarlo ante un error irrecuperable supone una pérdida de tiempo y puede ocultar fallos reales.
Nota: Utiliza siempre el error.name propiedad para identificar errores mediante programación. El valor numérico error.code La propiedad está en desuso.
Errores irrecuperables: no volver a intentarlo
Estos errores corresponden a restricciones estrictas, a un contexto de llamada no válido o a estados de flujo de terminal. Volver a intentarlo no los resolverá.
error.name |
Descripción | Medida recomendada |
|---|---|---|
OT_NOT_CONNECTED |
session.subscribe() se llamó antes de que se estableciera la sesión. |
Asegúrese session.connect() se ha completado correctamente antes de darse de alta. |
OT_DISCONNECTED |
La acción ha fallado porque el cliente no está conectado a la sesión. | Espera a que la sesión se vuelva a conectar antes de volver a intentarlo. |
OT_INVALID_PARAMETER |
Uno o más parámetros pasados a session.subscribe() eran inválidos (por ejemplo, un flujo nulo o un elemento de destino). |
Corrige la lógica de la aplicación. No vuelvas a intentarlo. |
OT_STREAM_DESTROYED |
La retransmisión se interrumpió antes de que se pudiera suscribirse a ella. | No lo intentes de nuevo: el flujo ya no existe. Elimina cualquier estado de suscripción pendiente para este flujo. |
OT_STREAM_NOT_FOUND |
No se ha podido encontrar la transmisión en la sesión. | No lo intentes de nuevo: el flujo ya no está disponible. |
OT_STREAM_LIMIT_EXCEEDED |
La sesión ha superado el límite de conexiones simultáneas. | Informa al usuario. No vuelvas a intentarlo hasta que haya una ranura de flujo disponible. |
OT_UNABLE_TO_SUBSCRIBE |
El usuario ha intentado suscribirse en una sesión con cifrado de extremo a extremo (E2EE) sin especificar un secreto de cifrado; o bien, un error inesperado ha impedido la suscripción. | Para las sesiones E2EE, asegúrate de que se haya configurado un secreto de cifrado mediante session.setEncryptionSecret() antes de suscribirse. En el caso general, registra el error e informa al usuario. |
Errores recuperables: se puede volver a intentar con total seguridad
Estos errores suelen deberse a condiciones transitorias de la red, tiempos de espera de señalización o indisponibilidad temporal de la plataforma.
error.name |
Descripción | Medida recomendada |
|---|---|---|
OT_TIMEOUT (código 1501) |
La suscripción no se completó en un plazo razonable. El error más habitual en la suscripción que se puede volver a intentar. | Cancela la suscripción y vuelve a intentarlo con un intervalo de espera (hasta 3 intentos). |
OT_ICE_WORKFLOW_FAILED |
La negociación ICE ha fallado: no se ha podido establecer la conexión entre pares. Suele ser algo pasajero en redes restrictivas. | Cancela la suscripción y vuelve a intentarlo. Si el problema persiste tras todos los intentos, informa al usuario de un posible problema de red o del cortafuegos. |
OT_CREATE_PEER_CONNECTION_FAILED |
No se ha podido establecer la conexión entre pares mediante WebRTC. Esto podría deberse a un cortafuegos restrictivo o a un problema temporal de la plataforma. | Cancela la suscripción y vuelve a intentarlo. Si el problema persiste, sugiere al usuario que compruebe su conexión a Internet. |
OT_SET_REMOTE_DESCRIPTION_FAILED |
La conexión WebRTC ha fallado durante setRemoteDescription. Normalmente se trata de un problema de señalización pasajero. |
Darse de baja y, a continuación, volver a intentarlo con un tiempo de espera. |
OT_MEDIA_ERR_ABORTED / OT_MEDIA_ERR_NETWORK |
La adquisición de archivos multimedia se ha cancelado o interrumpido debido a un error de red. | Cancela la suscripción y vuelve a intentarlo al cabo de unos minutos. |
OT_MEDIA_ERR_DECODE |
Se ha producido un error de decodificación al intentar reproducir la transmisión en el elemento de vídeo. | Cancela la suscripción y vuelve a intentarlo al cabo de un rato. Si el problema persiste, es posible que el formato multimedia sea incompatible. |
OT_MEDIA_ERR_SRC_NOT_SUPPORTED |
Se ha detectado que la transmisión no es apta para su reproducción. | Cancela la suscripción y vuelve a intentarlo una vez. Si el problema persiste, comprueba la configuración del elemento de vídeo del suscriptor. |
Importante: Cancela siempre la suscripción antes de volver a intentarlo
A diferencia de session.publish(), donde la instancia del editor suele poder reutilizarse directamente, session.subscribe() requiere que llames session.unsubscribe() y eliminar el objeto de suscriptor antes de volver a intentarlo. No es posible reutilizar una instancia de suscriptor que haya fallado.
async function subscribeWithRetry(session, stream, targetElement, options, attempt = 1) {
const MAX_RETRIES = 3;
const RETRY_DELAY_MS = 3000;
let subscriber = session.subscribe(stream, targetElement, options);
const error = await new Promise((resolve) => {
subscriber.on('subscribeComplete', (err) => resolve(err));
});
if (!error) {
console.log('Subscribed successfully.');
return subscriber;
}
// Always clean up the failed subscriber before retrying
try { session.unsubscribe(subscriber); } catch (e) { /* ignore */ }
// Non-recoverable: do not retry
const nonRetryable = [
'OT_NOT_CONNECTED',
'OT_DISCONNECTED',
'OT_INVALID_PARAMETER',
'OT_STREAM_DESTROYED',
'OT_STREAM_NOT_FOUND',
'OT_STREAM_LIMIT_EXCEEDED',
'OT_UNABLE_TO_SUBSCRIBE',
];
if (nonRetryable.includes(error.name)) {
console.error('Non-retryable subscribe error:', error.name);
handleNonRecoverableError(error);
return null;
}
// Recoverable: retry with backoff
if (attempt < MAX_RETRIES) {
console.warn(`Subscribe attempt ${attempt} failed (${error.name}), retrying...`);
await delay(RETRY_DELAY_MS * attempt);
return subscribeWithRetry(session, stream, targetElement, options, attempt + 1);
}
console.error('All subscribe attempts failed.');
handleSubscribeFailure(session, stream);
return null;
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function handleNonRecoverableError(error) {
// Surface a meaningful message to the user based on error.name
}
function handleSubscribeFailure(session, stream) {
// Inform the user that the stream could not be loaded
}
Uso:
session.on('streamCreated', (event) => {
subscribeWithRetry(session, event.stream, document.getElementById('subscriber'), {});
});
Situaciones en las que el tiempo es un factor decisivo
El flujo se interrumpe durante un intento de reintento
Si el flujo se destruye mientras hay un reintento pendiente, el streamDestroyed Se activará el evento de sesión. Debes cancelar cualquier reintento pendiente para esa secuencia, a fin de evitar suscribirte a una secuencia que ya no existe.
const pendingRetries = new Map(); // stream.id → timeout handle
session.on('streamDestroyed', (event) => {
const pending = pendingRetries.get(event.stream.id);
if (pending) {
clearTimeout(pending);
pendingRetries.delete(event.stream.id);
console.log(`Cancelled pending retry for destroyed stream: ${event.stream.id}`);
}
});
Reconexión de la sesión durante un nuevo intento de suscripción
Si la sesión se está volviendo a conectar (por ejemplo, tras una interrupción de la conexión de red), pospone el reintento hasta que la sesión se haya vuelto a conectar. Si se intenta suscribirse mientras la sesión se está volviendo a conectar, la operación fallará inmediatamente.
let isSessionReconnecting = false;
session.on('sessionReconnecting', () => { isSessionReconnecting = true; });
session.on('sessionReconnected', () => {
isSessionReconnecting = false;
// Re-trigger any deferred subscriptions here
});
// In your retry logic, check before retrying:
if (isSessionReconnecting) {
// Defer — wait for sessionReconnected before retrying
return;
}
Lo que NO hay que hacer
- Haz no Reutilizar una instancia de suscriptor que haya fallado: llamar siempre a
session.unsubscribe()y crear una nueva suscripción en el siguiente intento. - Haz no intentarlo de nuevo en
OT_STREAM_DESTROYEDoOT_STREAM_NOT_FOUND— El flujo ha desaparecido y cualquier nuevo intento siempre fracasará. - Haz no intentarlo de nuevo en
OT_STREAM_LIMIT_EXCEEDED— Se trata de una limitación de capacidad a nivel de sesión, no de un error pasajero. - Haz no Reintentar indefinidamente — limitar a 3 intentos e informar al usuario si todos fallan.
- Haz no reintentar mientras la sesión se vuelve a conectar — posponer hasta
sessionReconnectedincendios.
Resumen de los parámetros recomendados
| Parámetro | Valor recomendado | Notas |
|---|---|---|
| Número máximo de intentos | 3 | De conformidad con session.publish() instrucciones para volver a intentarlo |
| Retraso entre reintentos | 3 s × intento (3 s, 6 s, 9 s) | Es ligeramente más largo que los reintentos de publicación: el tiempo de espera de la suscripción es de 30 s. |
| Si fallan todos los reintentos | Informar al usuario | Evita cerrar el flujo sin avisar |
| Errores que no se pueden volver a intentar | OT_STREAM_DESTROYED, OT_STREAM_NOT_FOUND, OT_STREAM_LIMIT_EXCEEDED |
Fracasa rápido en esto |
| Limpieza de suscriptores | Siempre session.unsubscribe() antes de volver a intentarlo |
Obligatorio: a diferencia de los editores, las instancias de suscriptor no se pueden reutilizar |