Canales de publicación — Web

Una vez que haya conectado a una sesiónpuede publicar un flujo que otros clientes conectados a la sesión puedan ver.

Este tema incluye las siguientes secciones:

Comprobar si un cliente tiene capacidades de publicación

Una vez que te hayas conectado a una sesión, puedes comprobar si el cliente puede publicar. Comprueba el valor de la capabilities.publish propiedad del Session objeto. Si se establece en 1, el cliente puede publicar:

if (session.capabilities.publish == 1) {
    // The client can publish. See the next section.
} else {
    // The client cannot publish.
    // You may want to notify the user.
}

Para publicar, el cliente debe conectarse a la sesión con un token al que se le haya asignado un rol que admita la publicación. Debe haber una cámara y un micrófono conectados. Además, el entorno del cliente debe admitir la publicación (véase Compatibilidad con navegadores).

Además, la publicación sólo se admite en páginas HTTPS.

Inicialización de un editor

El OT.initPublisher() El método inicializa y devuelve un objeto Publisher. El objeto Publisher representa la vista de un vídeo que publicas:

var publisher;
var targetElement = 'publisherContainer';

publisher = OT.initPublisher(targetElement, null, function(error) {
  if (error) {
    // The client cannot publish.
    // You may want to notify the user.
  } else {
    console.log('Publisher initialized.');
  }
});

El OT.initPublisher() El método toma tres parámetros:

  • targetElement- (Opcional) Define el elemento DOM al que sustituye el vídeo del editor.

  • properties— (Opcional) Un conjunto de propiedades que permiten personalizar el Publisher. El properties Este parámetro también incluye opciones para especificar un dispositivo de entrada de audio y vídeo utilizado por el editor (véase Configuración de la cámara y el micrófono que utiliza el editor). En properties Este parámetro también incluye opciones para personalizar el aspecto de la vista en la página HTML (véase Personalizar la interfaz de usuario) y selecciona si deseas publicar audio y vídeo (véase Publicar sólo audio o vídeo). Para conocer más opciones de editor, consulta la documentación de la properties del OT.initPublisher() método.

  • completionHandler- (Opcional) Un controlador de finalización que especifica si el editor se ha instanciado correctamente o con un error.

Puede pasar este objeto Publisher a la función Session.publish() Método para publicar un flujo en una sesión. Véase Publicar un flujo.

Antes de llamar Session.publish(), puedes utilizar este objeto Publisher para probar el micrófono y la cámara conectados al Publisher.

El insertMode propiedad del properties del OT.initPublisher() 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 Publisher sustituye el contenido del `targetElement`. Esta es la opción predeterminada.
  • "after" - El objeto Publisher es un nuevo elemento insertado después del targetElement en el DOM HTML. (Tanto el Publisher como el targetElement tienen el mismo elemento padre).
  • "before" - El objeto Publisher es un nuevo elemento insertado antes del targetElement en el DOM HTML. (Tanto el Publisher como el targetElement tienen el mismo elemento padre).
  • "append" — El objeto «Publisher» es un nuevo elemento añadido como elemento secundario del «targetElement». Si hay otros elementos secundarios, el «Publisher» se añade al final como último elemento secundario del «targetElement».

Por ejemplo, el siguiente código añade un nuevo objeto Publisher como hijo de un objeto publisherContainer Elemento DOM:

// Try setting insertMode to other values: "replace", "after", or "before":
var publisherProperties = {insertMode: "append"};
var publisher = OT.initPublisher('publisherContainer', publisherProperties, function (error) {
  if (error) {
    console.log(error);
  } else {
    console.log("Publisher initialized.");
  }
});

Detectar cuándo un cliente ha concedido acceso a la cámara y al micrófono

Para que un objeto Publisher pueda acceder a la cámara y al micrófono del cliente, el usuario debe concederle permiso para ello. El objeto Publisher emite eventos cuando el usuario concede o deniega el acceso a la cámara y al micrófono:

publisher.on({
  accessAllowed: function (event) {
    // The user has granted access to the camera and mic.
  },
  accessDenied: function accessDeniedHandler(event) {
    // The user has denied access to the camera and mic.
  }
});

Además, un objeto Publisher envía eventos cuando se le ofrece al usuario la opción de permitir o denegar el acceso a la cámara y al micrófono:

publisher.on({
  accessDialogOpened: function (event) {
    // The Allow/Deny dialog box is opened.
  },
  accessDialogClosed, function (event) {
    // The Allow/Deny dialog box is closed.
  }
});

La editorial tiene un accessAllowed propiedad, que indica si un cliente tiene (true) o no lo ha hecho (false) ha concedido acceso a la cámara y al micrófono.

Configuración de la cámara y el micrófono que utiliza el editor

Puedes (si lo deseas) especificar un dispositivo de entrada de audio y vídeo para que lo utilice el editor. Cuando llames a la función OT.initPublisher() puede establecer (opcionalmente) el método audioSource y videoSource propiedades del properties objeto pasado a la OT.initPublisher() método.

En primer lugar, utilice el OT.getDevices() para enumerar los dispositivos disponibles. La matriz de dispositivos se pasa como la variable devices del callback pasada a la función OT.getDevices() método. Por ejemplo, el siguiente código obtiene una lista de dispositivos de entrada de audio y vídeo:

var audioInputDevices;
var videoInputDevices;
OT.getDevices(function(error, devices) {
  audioInputDevices = devices.filter(function(element) {
    return element.kind == "audioInput";
  });
  videoInputDevices = devices.filter(function(element) {
    return element.kind == "videoInput";
  });
  for (var i = 0; i < audioInputDevices.length; i++) {
    console.log("audio input device: ", audioInputDevices[i].deviceId);
  }
  for (i = 0; i < videoInputDevices.length; i++) {
    console.log("video input device: ", videoInputDevices[i].deviceId);
  }
});

Cada dispositivo que aparece en la lista de OT.getDevices() tiene un ID de dispositivo único, establecido como deviceId propiedad. Puedes utilizar estos valores de ID de dispositivo como el audioSource y videoSource propiedades del properties objeto pasado a OT.initPublisher():

var pubOptions =
  {
    audioSource: audioInputDevices[0].deviceId,
    videoSource: videoInputDevices[0].deviceId
  };
var publisher = OT.initPublisher(null, pubOptions, function(error) {
  console.log("OT.initPublisher error: ", error);
});

Fije el videoSource propiedad a null o false en una sesión solo de voz (véase Publicar en una sesión de voz).

El Componente de configuración del hardware de OpenTok proporciona una interfaz de usuario para que los clientes seleccionen la cámara y el micrófono que van a utilizar. Se construye utilizando el OT.getDevices() método.

Ten en cuenta que también puedes publicar una transmisión compartida de pantalla, es decir, una en la que la fuente sea la pantalla del cliente, y no una cámara. Para obtener más información, consulta Compartir pantalla.

También puede cambiar la cámara utilizada por el editor, o configúralo para que utilice el cámara frontal o trasera (cuando esta opción esté disponible).

También puede cambiar la fuente de audio utilizada por el editor.

Uso de la cámara frontal o trasera

Al inicializar un editor, puedes configurar el facingMode propiedad del objeto de opciones que pasas al OT.initPublisher(). Por ejemplo, puedes establecer la propiedad en "user" (cámara frontal) o "environment" (cámara trasera), cuando esta opción esté disponible en el sistema del cliente. (Por lo general, estas opciones solo están disponibles en dispositivos móviles.)

Si configuras el facingMode opción, haz no fijar el videoSource propiedad.

Recordar la selección de la cámara y el micrófono

Por motivos de seguridad en las páginas cargadas a través de HTTP, todos los navegadores solicitan siempre al usuario que seleccione la cámara y el micrófono que se van a utilizar para publicar una transmisión.

En las páginas cargadas a través de HTTPS en Chrome, la selección de la cámara y el micrófono del usuario se guarda y se vuelve a utilizar en visitas posteriores a una página cargada desde el mismo dominio HTTPS.

En las páginas cargadas a través de HTTPS en Firefox, el usuario tiene la opción de guardar la configuración de la cámara y el micrófono (para visitas posteriores a una página cargada desde el mismo dominio HTTPS) al seleccionar los dispositivos.

En las páginas cargadas a través de HTTPS en IE, puedes utilizar la selección anterior de cámara y micrófono del usuario, realizada en accesos anteriores al mismo dominio HTTPS (si la hubiera), configurando el usePreviousDeviceSelection propiedad a true en las opciones que introduzca en el campo OT.initPublisher() método:

var pubOptions = {usePreviousDeviceSelection: true};
var publisher = OT.initPublisher(null, pubOptions, function(error) {
  console.log("OT.initPublisher error: ", error);
});

Para que el usuario seleccione la cámara y el micrófono que desea utilizar en IE (e ignorar las selecciones de dispositivos anteriores), haz lo siguiente: no fijar el usePreviousDevices en las opciones que introduzca en el campo OT.initPublisher() método (o configúralo en false, el valor por defecto).

Desactivación de la gestión predeterminada de los dispositivos de entrada de audio

De forma predeterminada, el SDK gestiona automáticamente el cambio de dispositivo de entrada de audio si se conecta uno nuevo. Es posible que este no sea el comportamiento deseado para algunos usuarios finales que prefieran mantener seleccionado su micrófono actual.

Como usuario avanzado del SDK, puedes desactivar la gestión automática de los dispositivos de entrada de audio. Para ello, debes configurar el disableAudioInputDeviceManagement a las opciones introducidas en el campo OT.initPublisher() método:

var pubOptions = {disableAudioInputDeviceManagement: true};
var publisher = OT.initPublisher(null, pubOptions, function(error) {
  console.log("Publishing a stream");
});

Nota: Esta es una función avanzada. Si la activas, el dispositivo de entrada de audio utilizado por el SDK no actualizarse cuando el usuario final cambie de micrófono.

Publicar un flujo

Una vez creado el objeto Publisher (véase Inicialización de un editor), puedes pasarlo a la publish() Método de un objeto Session para publicar un flujo en la sesión:

    publisher = OT.initPublisher('replacementElementId');
    session.publish(publisher, function(error) {
      if (error) {
        console.log(error);
      } else {
        console.log('Publishing a stream.');
      }
    });

El segundo parámetro es una función de gestión de finalización a la que se pasa un objeto de error si falla la publicación. En caso contrario, se llama a la función de finalización sin pasarle ningún error.

Este código supone que session es un objeto Session y que el cliente se ha conectado a la sesión. Para obtener más información, consulta Cómo unirse a una sesión.

El objeto Publish envía un streamCreated cuando comience a transmitirse a la sesión:

var publisher = OT.initPublisher();
session.publish(publisher, function(error) {
  if (error) {
    console.log(error);
  } else {
    console.log('Publishing a stream.');
  }
});
publisher.on('streamCreated', function (event) {
    console.log('The publisher started streaming.');
});

El objeto Publisher tiene un element propiedad, cuyo valor es el elemento DOM de HTML que la contiene.

Impedir que un editor transmita en streaming a una sesión

Puedes impedir que el editor transmita en directo a la sesión llamando a la función unpublish() del objeto Session:

    session.unpublish(publisher);

Ten en cuenta que puedes dejar de enviar vídeo o audio de forma individual (sin dejar de publicar). Para obtener más información, consulta Ajustar el audio y el vídeo.

Detectar cuándo un flujo publicado abandona una sesión

El objeto Publisher envía un streamDestroyed cuando deja de transmitir a la sesión:

var publisher = OT.initPublisher();
session.publish(publisher);
publisher.on("streamDestroyed", function (event) {
  console.log("The publisher stopped streaming. 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 editor envía el comando streamDestroyed el editor se destruye y se elimina del DOM HTML. Puede evitar este comportamiento por defecto llamando a la función preventDefault() del objeto StreamEvent:

publisher.on("streamDestroyed", function (event) {
    event.preventDefault();
    console.log("The publisher stopped streaming.");
});

Es posible que desee evitar el comportamiento predeterminado y conservar el Editor si desea reutilizar el objeto Editor para publicar de nuevo en la sesión.

La editorial también 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 editor que se ha eliminado.

Configuración de la resolución de vídeo de una transmisión

Para establecer una resolución de vídeo recomendada para una transmisión publicada, configura el resolution propiedad del properties que se pasa al parámetro OT.initPublisher() método:

var publisherProperties = {resolution: '1280x720'};
var publisher = OT.initPublisher(targetElement,
                                 publisherProperties);
publisher.on('streamCreated', function(event) {
   console.log('Stream resolution: ' +
     event.stream.videoDimensions.width +
     'x' + event.stream.videoDimensions.height);
});

Este resolution es una cadena que define la resolución deseada del vídeo. El formato de la cadena es "_width_x_height_"donde la anchura y la altura se representan en píxeles. Los valores válidos son "1920x1080", "1280x720", "640x480"y "320x240".

La resolución solicitada de una transmisión de vídeo se establece como la videoDimensions.width y videoDimensions.height propiedades del objeto Stream.

La resolución predeterminada de una transmisión (si no se especifica ninguna resolución) es de 640 x 480 píxeles. Si el sistema del cliente no es compatible con la resolución solicitada, la transmisión utilizará la siguiente configuración más alta que admita.

El videoHeight() y videoWidth() devuelven la resolución configurada del objeto Publisher. La resolución real de un flujo de vídeo de abonado se devuelve mediante el método videoWidth() y videoHeight() métodos del objeto «Subscriber». Estos pueden diferir de los valores de la resolution propiedad pasada como properties propiedad del OT.initPublisher() método, en caso de que el navegador de publicación no admita la resolución solicitada.

Nota: Consulta el Guía del desarrollador 1080p para conocer los aspectos que hay que tener en cuenta a la hora de utilizar una resolución de 1080p.

Ajuste de la frecuencia de imagen de un flujo

Para establecer una frecuencia de fotogramas recomendada para una transmisión publicada, configura el frameRate propiedad del properties que se pasa al parámetro OT.initPublisher() método:

var publisherProperties = {frameRate: 7};
var publisher = OT.initPublisher(targetElement,
                                 publisherProperties);
publisher.on('streamCreated', function(event) {
   console.log('Frame rate: ' + event.stream.frameRate);
});

Establece el valor en la frecuencia de fotogramas deseada, en fotogramas por segundo, del vídeo. Los valores válidos son 30, 15, 7 y 1.

Si el editor especifica una velocidad de fotogramas, la velocidad de fotogramas real de la secuencia de vídeo se establece como el valor de frameRate del objeto Stream, aunque la frecuencia de imagen real variará en función de las condiciones cambiantes de la red y del sistema. Si no especifica una frecuencia de imagen al llamar a OT.initPublisheresta propiedad no está definida.

En el caso de las sesiones que utilizan el OpenTok Media Router (sesiones con el modo multimedia (configurado en «routed»), al reducir la frecuencia de fotogramas se reduce proporcionalmente el ancho de banda máximo que puede utilizar la transmisión. Sin embargo, en una sesión con el modo multimedia en retransmitido, la reducción de la frecuencia de imagen no reduce el ancho de banda del flujo.

También puedes limitar la frecuencia de fotogramas de la transmisión de vídeo de un suscriptor. Para obtener más información, consulta Restricción de la frecuencia de fotogramas de una transmisión a la que se está suscrito.

Configuración de la velocidad de bits máxima para una transmisión

Puedes establecer la tasa de bits máxima para una transmisión publicada. Establecer la tasa de bits máxima puede ayudar a reducir el consumo de ancho de banda cuando un usuario se conecta desde una conexión con límite de datos. Consulta esta documentación.

Eliminar un editor

Puede eliminar un editor llamando a su destroy() método:

    publisher.destroy();

Llamada al destroy() Este método elimina el objeto Publisher y lo retira del DOM HTML.

Obtener estadísticas sobre la transmisión de un editor

El Publisher.getStats() Este método te proporciona una matriz de objetos que definen las estadísticas actuales de audio y vídeo del emisor. En el caso de un emisor que se encuentre en una sesión enrutada (es decir, una que utilice el OpenTok Media Router), este array incluye un objeto que define las estadísticas de la única secuencia de audio y vídeo que se envía al OpenTok Media Router. En una sesión retransmitida, el array incluye un objeto por cada suscriptor de la secuencia publicada.

Para obtener estadísticas detalladas de bajo nivel sobre las conexiones entre pares, utiliza el Publisher.getRtcStatsReport() método. Devuelve una promesa que, si se ejecuta correctamente, se resuelve con un array de RtcStatsReport objetos.

Consulte guía del desarrollador de la observabilidad del cliente para obtener información detallada.

Probar el flujo de un editor

Puedes publicar un flujo de prueba y comprobar sus estadísticas de audio y vídeo para determinar el tipo de flujo (como alta resolución o sólo audio) que admite tu conexión.

Para obtener estadísticas de una transmisión publicada por el cliente local, debes utilizar una sesión que emplee el OpenTok Media Router (las sesiones con el modo multimedia (configurado como «enrutado»), y debes configurar el testNetwork propiedad a true en el options que se pasa al objeto Session.subscribe() método. A continuación, puede utilizar el método getStats() método del objeto «Subscriber» para obtener estadísticas de audio y vídeo de la transmisión que publicas. Consulta este tema para más información.

El prueba-de-red-opentok repo incluye código de ejemplo para mostrar cómo utilizar las estadísticas de un flujo de prueba antes de publicarlo en una sesión.

Publicar un vídeo procedente de una fuente distinta de una cámara o una pantalla

Puedes configurar la fuente de vídeo de un Publisher como un vídeo MediaStreamTrack objeto. Esto te permite hacer lo siguiente:

  • Publica el vídeo utilizando un elemento HTML «Canvas» como vídeo. Puedes llamar al captureStream() método del HTMLCanvasElement objeto y llamar a la getVideoTracks() método del resultado CanvasCaptureMediaStream objeto para obtener un objeto MediaStreamTrack de vídeo. Para ver un ejemplo básico, consulta el ejemplo «Publish-Canvas». repositorio opentok-web-samples en GitHub.

  • Publicar un vídeo desde un elemento «Vídeo». Llama al captureStream() método de un HTMLVideoElement objeto para obtener un objeto MediaStream. El getVideoTracks() El método del objeto MediaStream devuelve una matriz de objetos MediaStreamTrack de audio (normalmente, solo uno). A continuación, puedes utilizar el objeto MediaStreamTrack como el audioSource propiedad del options que se pasa al objeto OT.initPublisher() método. Para ver un ejemplo básico, consulta el ejemplo «Publish-Video» repositorio opentok-web-samples en GitHub.

Puedes utilizar un objeto MediaStreamTrack de vídeo como el videoSource propiedad del options que se pasa al objeto OT.initPublisher() método. Esto hace que el vídeo representado por el objeto MediaStreamTrack sea la fuente de vídeo para el flujo publicado.

Reproducir audio procedente de una fuente distinta al micrófono

Puedes configurar la fuente de audio de un Publisher como un archivo de audio MediaStreamTrack objeto. Esto te permite hacer lo siguiente:

  • Publica el audio de un elemento de audio o vídeo. Llama al captureStream() método de un HTMLAudioElement objeto o un HTMLVideoElement objeto para obtener un objeto MediaStream. El getAudioTracks() El método del objeto `MediaStream` es una matriz de objetos `MediaStreamTrack` de audio (normalmente, solo uno). A continuación, puedes utilizar el objeto `MediaStreamTrack` como el audioSource propiedad del options que se pasa al objeto OT.initPublisher() método.
  • Publicar audio desde un objeto `MediaStreamTrack` de audio. Por ejemplo, puedes utilizar el AudioContext objeto y el API de audio web para generar audio de forma dinámica. A continuación, puedes llamar a createMediaStreamDestination().stream.getAudioTracks()[0] en el objeto AudioContext para obtener el objeto MediaStreamTrack de audio que se utilizará como objeto audioSource propiedad del options que se pasa al objeto OT.initPublisher() método. Para ver un ejemplo básico, consulta el ejemplo «Stereo-Audio». repositorio opentok-web-samples en GitHub.

Aplicar filtros y efectos al audio y al vídeo publicados

Puedes aplicar filtros y efectos, como la sustitución del fondo o el desenfoque del fondo, al audio o al vídeo obtenido de un micrófono o una cámara utilizados como fuente de audio o vídeo para una retransmisión publicada; consulta este tema.

Configuración de sugerencias de contenido de vídeo para mejorar el rendimiento del vídeo en determinadas situaciones

Puedes configurar una sugerencia de contenido de vídeo para mejorar la calidad y el rendimiento de un vídeo publicado. Esto puede resultar útil en determinadas situaciones:

  • Al publicar un vídeo de pantalla compartida que contenga principalmente texto o contenido de vídeo.
  • Cuando se utilice una fuente de vídeo de cámara, si prefieres reducir la velocidad de fotogramas y mantener la resolución, puedes configurar la indicación de contenido en «texto» o «detalle». En una sesión enrutada, si el editor admite el uso de vídeo escalable, enviará una transmisión a resolución máxima y baja frecuencia de fotogramas y —si las condiciones de la red lo permiten— una transmisión a resolución máxima y frecuencia de fotogramas normal. El OpenTok Media Router reenviará una de esas transmisiones a los suscriptores.

Esto indica al navegador que utilice métodos de codificación o procesamiento más apropiados para el tipo de contenido especificado.

Para establecer la indicación de contenido de vídeo inicial de una transmisión, configura el videoContentHint propiedad de las opciones que pasas a la OT.initPublisher() método:

var publisherOptions = {
  videoContentHint: "text",
  // other options, such as videoSource: "screen"
};
var publisher = OT.initPublisher(targetElement, publisherOptions, callbackFunction);

Puedes modificar dinámicamente la sugerencia del contenido de vídeo llamando a la función setVideoContentHint() método de un objeto Publisher:

publisher.setVideoContentHint("motion");

Puedes establecer la indicación de contenido de vídeo en uno de los siguientes valores:

  • "" - No se proporciona ninguna sugerencia (por defecto). El cliente de publicación hará una estimación de cómo debe tratarse el contenido de vídeo.
  • "motion" — La pista debe tratarse como si contuviera vídeo en el que el movimiento sea importante. Por ejemplo, puedes utilizar esta configuración para una transmisión de vídeo de pantalla compartida que contenga vídeo.
  • "detail" - La pista debe tratarse como si los detalles del vídeo fueran extra importantes. Por ejemplo, puede utilizar este ajuste para un flujo de vídeo de pantalla compartida que contenga contenido de texto, pintura o arte lineal.
  • "text" - La pista debe tratarse como si los detalles de texto fueran extra importantes. Por ejemplo, puede utilizar este ajuste para un flujo de vídeo de pantalla compartida que contenga texto.

Con las sugerencias de contenido "texto" y "detallado", el navegador intenta mantener una resolución alta, aunque tenga que reducir la frecuencia de imagen del vídeo. En el caso de la sugerencia de contenido "movimiento", el navegador reduce la resolución para evitar que la frecuencia de imagen se detenga.

Puedes obtener más información sobre estas opciones en el Borrador de trabajo del W3C.

Chrome 60 o superior, Safari 12.1 o superior, Edge 79 o superior, Opera 47 o superior, las versiones recientes de Samsung Internet, WebView en Android 70 o superior y WebView en iOS 12.2 o superior admiten indicaciones de contenido de vídeo. En otros navegadores, esta configuración no se tiene en cuenta.

Si no te importa que la velocidad de fotogramas sea baja, también podrías plantearte limitar la frecuencia de fotogramas de las transmisiones a las que se está suscrito para mejorar la calidad.

Opción alternativa de audio del editor

Consulta la guía para desarrolladores sobre fallback de audio . La función de audio de reserva del editor ofrece un mayor ancho de banda y un mejor control de la calidad para mejorar las comunicaciones.

Otras opciones de audio y vídeo

Consulta la guía para desarrolladores sobre Ajustar el audio y el vídeo.

Buenas prácticas a la hora de publicar

En esta sección se ofrecen consejos para publicar transmisiones con éxito.

Permitir el acceso de dispositivos

Se recomienda informar a los usuarios de que se les pedirá que autoricen el acceso a su cámara y micrófono. Hemos observado que, con diferencia, la mayoría de los errores en la publicación se deben a que los usuarios hacen clic en el botón «Denegar» o no hacen clic en el botón «Permitir» en absoluto. Te proporcionamos todos los eventos que necesitas para poder guiar a tus usuarios a lo largo de este proceso:

publisher.on({
  accessDialogOpened: function (event) {
    // Show allow camera message
    pleaseAllowCamera.style.display = 'block';
  },
  accessDialogClosed: function (event) {
    // Hide allow camera message
    pleaseAllowCamera.style.display = 'none';
  }
});

También es una buena idea servir su sitio web a través de SSL. Esto se debe a que Chrome sólo requiere que los usuarios hagan clic para permitir el acceso a los dispositivos una vez por dominio si ese dominio se sirve a través de SSL. Esto significa que sus usuarios (si están en Chrome) no tienen que lidiar con ese incómodo cuadro de diálogo de permitir/denegar cada vez que cargan la página.

Dividir OT.initPublisher() y Session.publish()

Otra cosa que recomendamos es dividir el OT.initPublisher() y Session.publish() pasos. Esto acelera el tiempo de conexión inicial, ya que te conectas a la sesión mientras esperas a que el usuario haga clic en el botón «Permitir». Así que, en lugar de:

session.connect(token, function (err) {
{... your error handling code ...}
if (!err) {
    var publisher = OT.initPublisher();
    session.publish(publisher);
  }
});

Mueva el OT.initPublisher() paso a antes de conectarse, como en el siguiente:

var publisher = OT.initPublisher();
session.connect(token, function (err) {
{... your error handling code ...}
  if (!err) {
    session.publish(publisher);
  }
});

Resolución y frecuencia de fotogramas

Puedes configurar la resolución y la frecuencia de fotogramas del Publisher al iniciarlo:

OT.initPublisher(divId, {
  resolution: '320x240',
  frameRate: 15
});

Por defecto, la resolución de un Publisher es de 640x480, pero también puedes configurarla en 1920x1080, 1280x720 o 320x240. Lo mejor es intentar ajustar la resolución al tamaño en el que se va a mostrar el vídeo. Si solo vas a mostrar el vídeo a 320x240 píxeles, no tiene sentido transmitirlo a 1280x720 o 1920x1080. Reducir la resolución puede ahorrar ancho de banda y reducir la congestión y las caídas de conexión.

Por defecto, la velocidad de fotogramas del vídeo es de 30 fotogramas por segundo, pero también puedes establecerla en 15, 7 o 1. Reducir la frecuencia de imagen puede reducir el ancho de banda necesario. Los vídeos de menor resolución pueden tener una frecuencia de imagen más baja sin que el usuario perciba tanta diferencia. Por lo tanto, si utilizas una resolución baja, también deberías pensar en utilizar una frecuencia de imagen baja.

Para obtener más información, consulta la documentación de OT.initPublisher().

Solución de problemas

Sigue los consejos de esta sección para evitar problemas de conectividad al publicar. Para obtener información general sobre la resolución de problemas, consulta Depuración — Web.

Gestión de errores

Existen métodos de devolución de llamada tanto para Session.publish() y OT.initPublisher(). Recomendamos gestionar las respuestas de error de ambos métodos. Como se ha mencionado anteriormente, lo mejor es dividir estos pasos y llamar a OT.initPublisher() antes de que haya comenzado a conectarse a su Sesión. También facilita el manejo de errores si no está llamando a ambos métodos al mismo tiempo. Esto se debe a que ambos manejadores de error se dispararán si hay algún error publicando. Es mejor esperar a que OT.initPublisher() para completar y Session.connect() para completar y luego llamar a Session.publish(). De este modo, podrá gestionar todos los problemas relacionados con el hardware en el OT.initPublisher() y todas las cuestiones relacionadas con la red en el Session.publish() llamada de retorno.

var connected = false,
  publisherInitialized = false;

var publisher = OT.initPublisher(function(err) {
  if (err) {
    // handle error
  } else {
    publisherInitialized = true;
    publish();
  }
});

var publish = function() {
  if (connected && publisherInitialized) {
    session.publish(publisher);
  }
};

session.connect(token, function(err) {
  if (err) {
    // handle error
  } else {
    connected = true;
    publish();
  }
});

Acceso denegado

El mayor número de fallos de OT.initPublisher() se deben a que el usuario final deniega el acceso a la cámara y al micrófono. Esto puede solucionarse escuchando el accessDenied evento o detectando una respuesta de error del método OT.initPublisher() con un code propiedad establecida en 1500 y un message con el valor "Acceso al editor denegado:". Le recomendamos que gestione este caso y emita un mensaje al usuario indicándole que debe intentar publicar de nuevo y permitir el acceso a la cámara.

publisher.on({
  'accessDenied': function() {
    showMessage('Please allow access to the Camera and Microphone and try publishing again.');
  }
});

Acceso a dispositivos

Otra razón para OT.initPublisher() El error se produce si OpenTok no puede acceder a una cámara o a un micrófono. Esto puede ocurrir si no hay ninguna cámara o micrófono conectado al equipo, si hay algún problema con el controlador de la cámara o del micrófono, o si alguna otra aplicación está utilizando la cámara o el micrófono (esto solo ocurre en Windows). Puedes intentar minimizar la aparición de estos problemas utilizando nuestro componente de configuración de hardware o llamando al OT.getDevices() directamente. Sin embargo, también debe manejar cualquier error al llamar a OT.initPublisher() porque algo podría salir mal. Por ejemplo, el usuario podría haber denegado el acceso a la cámara o al micrófono. En este caso, el error.name se establece en "OT_USER_MEDIA_ACCESS_DENIED":

publisher = OT.initPublisher('publisher', {}, function (err) {
  if (err) {
    if (err.name === 'OT_USER_MEDIA_ACCESS_DENIED') {
      // Access denied can also be handled by the accessDenied event
      showMessage('Please allow access to the Camera and Microphone and try publishing again.');
    } else {
      showMessage('Failed to get access to your camera or microphone. Please check that your webcam'
        + ' is connected and not being used by another application and try again.');
    }
    publisher.destroy();
    publisher = null;
  }
});

Errores de red

Las demás causas de los errores en la publicación suelen deberse a algún tipo de fallo de red. Estas situaciones se gestionan en la llamada de retorno a Session.publish(). Si el usuario no está conectado a la red, a la función de devolución de llamada se le pasa un objeto de error con el valor name con el valor "OT_NOT_CONNECTED". Si el usuario se encuentra en una conexión de red muy restrictiva que no permite conexiones WebRTC, el Publisher no podrá conectarse y el elemento Publisher mostrará únicamente una rueda giratoria. Este error tiene un name con el valor "OT_CREATE_PEER_CONNECTION_FAILED". En este caso, te recomendamos que muestres un mensaje al usuario indicando que no se ha podido publicar y que debe comprobar su conexión a Internet. La gestión de estos errores se realiza de la siguiente manera:

session.publish(publisher, function(err) {
  if (err) {
    switch (err.name) {
      case "OT_NOT_CONNECTED":
        showMessage("Publishing your video failed. You are not connected to the internet.");
        break;
      case "OT_CREATE_PEER_CONNECTION_FAILED":
        showMessage("Publishing your video failed. This could be due to a restrictive firewall.");
        break;
      default:
        showMessage("An unknown error occurred while trying to publish your video. Please try again later.");
    }
    publisher.destroy();
    publisher = null;
  }
});

Perder conectividad

Su Editor también puede perder su conexión después de haber logrado conectarse. En la mayoría de los casos, esto también provocará que la sesión pierda su conexión, pero no siempre es así. Puede manejar la desconexión del Publisher escuchando el comando streamDestroyed evento con un reason propiedad establecida en «networkDisconnected» de la siguiente manera:

publisher.on({
  streamDestroyed: function (event) {
    if (event.reason === 'networkDisconnected') {
      showMessage('Your publisher lost its connection. Please check your internet connection and try publishing again.');
    }
  }
});

Poniendo todo en su sitio

El siguiente código crea un editor, se conecta a una sesión (véase Conceptos básicos sobre las sesiones), publica un flujo en la sesión cuando el cliente se conecta a la sesión, y detecta cuándo el editor inicia y detiene el flujo:

var session;
var publisher;

// Replace with the replacement element ID:
publisher = OT.initPublisher(replacementElementId);
publisher.on({
  streamCreated: function (event) {
    console.log("Publisher started streaming.");
  },
  streamDestroyed: function (event) {
    console.log("Publisher stopped streaming. Reason: "
      + event.reason);
  }
});

// Replace apiKey and sessionID with your own values:
session = OT.initSession(apiKey, sessionID);
// Replace token with your own value:
session.connect(token, function (error) {
  if (session.capabilities.publish == 1) {
    session.publish(publisher);
  } else {
    console.log("You cannot publish an audio-video stream.");
  }
});

Implementación de los reintentos de publicación de sesiones

Los errores transitorios de publicación son un problema conocido y recurrente en el SDK de JavaScript de la Video API, especialmente en los navegadores móviles. Cuando session.publish() 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.publish() Está incluido en la hoja de ruta del SDK. Hasta que se lance, tendrás que implementarlo tú mismo.

Cómo session.publish() Obras

session.publish() Se puede invocar de dos maneras:

  • Con un editor preinicializado: session.publish(publisher, callback) — ¿Llamas? OT.initPublisher() primero, y luego pasa la instancia de editor resultante a session.publish(). Este es el enfoque recomendado ya que separa la adquisición de contenidos multimedia de la creación de la transmisión, lo que permite gestionar los errores de forma más clara.
  • Sin una instancia de editor: session.publish(targetElement, options, callback) — el SDK realiza internamente una llamada a OT.initPublisher() para ti. En este caso, tanto los errores de adquisición de medios como los de creación de flujos se detectan a través de un único session.publish() llamada de retorno.

Buenas prácticas: Split OT.initPublisher() y session.publish() en pasos separados. Esto te permite gestionar los errores de hardware o de los soportes en el OT.initPublisher() errores de devolución de llamada y de red/señalización en el session.publish() callback: simplifica considerablemente la lógica de reintentos y la hace más específica.

// Recommended: split initialization from publishing
let publisherReady = false;
let sessionConnected = false;

const publisher = OT.initPublisher('publisher-container', publisherOptions, (err) => {
  if (err) {
    handleInitPublisherError(err); // hardware/media errors — see OT.initPublisher() errors below
    return;
  }
  publisherReady = true;
  maybePublish();
});

session.connect(token, (err) => {
  if (err) { /* handle connection error */ return; }
  sessionConnected = true;
  maybePublish();
});

function maybePublish() {
  if (sessionConnected && publisherReady) {
    publishWithRetry(session, publisher);
  }
}

Por qué se producen errores de publicación

Las causas fundamentales más habituales de los fallos transitorios en la publicación son:

  • Tiempos de espera de StreamCreateRequest (error 1500): El editor no ha podido completar la creación del flujo en un plazo razonable, lo que suele deberse a retrasos en la red durante la negociación ICE/SDP.
  • mediaStopped eventos durante el proceso de publicación, donde el acceso a los dispositivos multimedia puede verse interrumpido.
  • Reutilización del objeto «Publisher» sin una limpieza adecuada — reutilizar una instancia de «publisher» inicializada con restricciones diferentes sin llamar a unpublish y reiniciando.
  • OT_NOT_CONNECTED — Se está intentando publicar antes de que la sesión esté completamente conectada.
  • OT_PERMISSION_DENIED — El token no tiene el rol de publicación (no se puede volver a intentar).

Errores de OT.initPublisher()

Cuando se preinicializa un editor con OT.initPublisher(), todos los errores de hardware y de adquisición de medios se envían a su controlador de finalización — antes de session.publish() se invoca en algún momento. Gestiónalos en esta función de devolución de llamada utilizando las acciones específicas para cada error que se indican a continuación: algunos requieren una acción por parte del usuario o una corrección del código, mientras que los errores transitorios relacionados con los medios pueden solucionarse reiniciando el editor.

Nota: Si llamas session.publish() Si no se ha inicializado previamente el editor, estos mismos errores aparecerán a través del session.publish() utiliza en su lugar una función de devolución de llamada.

error.name Descripción Medida recomendada
OT_HARDWARE_UNAVAILABLE El hardware existe, pero no se ha podido acceder a él (por ejemplo, porque lo está utilizando otra aplicación). Pide al usuario que cierre las demás aplicaciones que se estén ejecutando en el dispositivo y, a continuación, llama a OT.initPublisher() otra vez.
OT_INVALID_PARAMETER Uno o más parámetros pasados a OT.initPublisher() no eran válidos. Corrige el objeto de opciones que se pasa a OT.initPublisher().
OT_MEDIA_ENDED El ended Evento del elemento de vídeo que se activa durante la inicialización. Reinicializa el editor.
OT_MEDIA_ERR_ABORTED Se ha interrumpido la descarga del flujo para el elemento de vídeo. Reinicia el editor tras una breve pausa.
OT_MEDIA_ERR_DECODE Se ha producido un error de decodificación al intentar reproducir la transmisión en el elemento de vídeo. Reinicia el editor tras una breve pausa.
OT_MEDIA_ERR_NETWORK Un error de red ha provocado que se haya interrumpido la descarga de la transmisión. Reinicia el editor tras una breve pausa.
OT_MEDIA_ERR_SRC_NOT_SUPPORTED Se ha detectado que la transmisión no es apta para su reproducción. Comprueba la configuración de la fuente de vídeo/audio del emisor y reinicia el sistema.
OT_NOT_SUPPORTED El navegador no admite algún elemento de la solicitud de contenido multimedia del usuario. Informar al usuario y no volver a intentarlo.
OT_NO_DEVICES_FOUND No se han encontrado dispositivos de entrada de audio ni de vídeo. Pide al usuario que conecte un dispositivo antes de volver a intentarlo.
OT_NO_VALID_CONSTRAINTS Se han desactivado tanto el vídeo como el audio; es necesario activar al menos uno de ellos. Asegúrese publishAudio o publishVideo es true en las opciones del editor.
OT_PROXY_URL_ALREADY_SET_ERROR El proxyUrl Ya se ha configurado. Volver a configurarlo no tendrá ningún efecto. Configura la URL del proxy solo una vez, antes de inicializar cualquier objeto «Session» o «Publisher».
OT_REQUESTED_DEVICE_PERMISSION_DENIED El dispositivo de audio solicitado no tiene permiso para ser utilizado. Solicita al usuario que conceda los permisos del dispositivo.
OT_USER_MEDIA_ACCESS_DENIED El usuario ha denegado el acceso a la cámara, al micrófono o a la pantalla. Solicita al usuario que autorice el acceso en la configuración del navegador; no lo vuelvas a intentar automáticamente.
OT_SCREEN_SHARING_NOT_SUPPORTED El navegador actual no admite la función de compartir pantalla. Informar al usuario y no volver a intentarlo.
OT_UNABLE_TO_CAPTURE_SCREEN Se ha solicitado compartir pantalla, pero esta función no está disponible (p. ej., videoSource ajustado a "screen", "application", o "window"). Llame a OT.checkScreenSharingCapability() antes de inicializar un emisor de pantalla compartida.
OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED Para compartir pantalla se necesita una extensión del navegador, pero no se ha registrado ninguna. Registra la extensión antes de llamar OT.initPublisher().
OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED Para compartir pantalla se necesita una extensión del navegador, pero no está instalada. Indica al usuario que instale la extensión necesaria.
const publisher = OT.initPublisher('publisher-container', publisherOptions, (err) => {
  if (!err) {
    publisherReady = true;
    maybePublish();
    return;
  }

  // Hardware/media errors — handle before session.publish() is called
  switch (err.name) {
    case 'OT_REQUESTED_DEVICE_PERMISSION_DENIED':
      showMessage('Please allow access to your camera and microphone and try again.');
      break;
    case 'OT_HARDWARE_UNAVAILABLE':
    case 'OT_NO_DEVICES_FOUND':
      showMessage('Could not access your camera or microphone. Please check your devices.');
      break;
    case 'OT_SCREEN_SHARING_NOT_SUPPORTED':
    case 'OT_UNABLE_TO_CAPTURE_SCREEN':
    case 'OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED':
    case 'OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED':
      showMessage('Screen sharing is not available. Please check your browser settings.');
      break;
    default:
      showMessage('Could not initialize the publisher. Please try again.');
  }

  publisher.destroy();
});

Errores recuperables frente a errores no recuperables de session.publish()

No todos session.publish() No todos los errores son iguales. Antes de implementar la lógica de reintento, es fundamental clasificar los errores correctamente: reintentar ante un error irrecuperable supone una pérdida de tiempo, empeora la experiencia del usuario y puede ocultar fallos reales que requieren una respuesta diferente.

Nota: Código de error 1500 ha quedado obsoleto como mecanismo de clasificación. Utiliza siempre el error.name propiedad que permite identificar errores mediante programación, ya que se corresponde con el escenario de fallo concreto.

Nota: Cuando session.publish() se llama sin un editor preinicializado, errores de adquisición de medios procedentes de OT.initPublisher() (los mencionados anteriormente) también pueden manifestarse a través de la session.publish() callback. En ese caso, considéralos como no reintentables y aplícales el mismo procedimiento descrito anteriormente.

Errores irrecuperables: no volver a intentarlo

Estos errores se deben a errores de programación, restricciones estrictas de permisos o un contexto de llamada no válido. Volver a intentarlo no los resolverá. En su lugar, muestra un mensaje claro al usuario o corrige la lógica de la aplicación.

error.name Descripción Medida recomendada
OT_NOT_CONNECTED session.publish() se llamó antes de que se estableciera la sesión. Asegúrese session.connect() se haya completado con éxito antes de su publicación.
OT_PERMISSION_DENIED El rol del token no permite publicar (debe ser publisher o moderator). Indica al usuario que no dispone de permisos de publicación. No lo vuelvas a intentar: genera un token con el rol correcto.
OT_INVALID_PARAMETER El editor facilitado no es válido, ya se ha publicado o ya está asociado a otra sesión. Corregir la lógica de la aplicación: llamar a session.unpublish(publisher) antes de volver a publicar, o bien crear una nueva cuenta de publicación.
OT_USER_MEDIA_ACCESS_DENIED El usuario ha denegado el acceso a la cámara o al micrófono (o a la pantalla, en el caso de las transmisiones con pantalla compartida). Pide al usuario que autorice el acceso al dispositivo en la configuración de su navegador e inténtalo de nuevo. No lo intentes de nuevo automáticamente.
OT_CHROME_MICROPHONE_ACQUISITION_ERROR El navegador no ha podido acceder al micrófono debido a un error conocido del navegador. Para solucionar este problema, el usuario debe reiniciar el navegador y volver a cargar la página. Informar al usuario y no volver a intentarlo.
OT_SCREEN_SHARING_NOT_SUPPORTED El navegador actual no admite la función de compartir pantalla. Informar al usuario y no volver a intentarlo.
OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED Para compartir pantalla se necesita una extensión del navegador, pero no se ha registrado ninguna. Registra la extensión antes de intentar publicar una transmisión compartida de pantalla.
OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED Para compartir pantalla se necesita una extensión del navegador, pero no está instalada. Indica al usuario que instale la extensión necesaria.
OT_CONSTRAINTS_NOT_SATISFIED El navegador no ha podido cumplir los requisitos de reproducción solicitados (resolución, frecuencia de fotogramas, dispositivo). Ajusta las restricciones del editor y reinicia el proceso.
OT_NO_VALID_CONSTRAINTS Se han desactivado tanto el vídeo como el audio; es necesario activar al menos uno de ellos. Asegúrese publishAudio o publishVideo es true antes de llamar a session.publish().
OT_NOT_SUPPORTED El navegador no admite algún elemento de la solicitud de contenido multimedia del usuario. Informar al usuario y no volver a intentarlo.
OT_STREAM_CREATE_FAILED El usuario ha intentado publicar en una sesión con cifrado de extremo a extremo (E2EE) activado sin especificar una clave de cifrado; o bien no se ha podido crear el flujo en el modelo de servidor. Para las sesiones E2EE, asegúrate de que se haya configurado un secreto de cifrado mediante session.setEncryptionSecret() antes de publicarlo.
OT_INVALID_AUDIO_OUTPUT_SOURCE Se ha introducido un identificador de dispositivo de salida de audio no válido. Verify que el ID del dispositivo sea un dispositivo de salida de audio válido antes de volver a intentarlo.
OT_UNABLE_TO_CAPTURE_MEDIA No se ha podido capturar el contenido multimedia: se ha producido un error desconocido. Informa al usuario y pídele que compruebe la disponibilidad del dispositivo.

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 la indisponibilidad temporal de la plataforma. Son el objetivo principal de la lógica de reintentos.

error.name Descripción Medida recomendada
OT_TIMEOUT (código 1500) session.publish() se ha agotado el tiempo de espera — el StreamCreateRequest no se completó a tiempo. La causa más habitual son los retrasos en la negociación entre ICE y SDP o mediaStopped eventos. Volver a intentarlo con retrasos exponenciales (hasta 3 intentos). Reutilizar la misma instancia del editor si no se ha eliminado.
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. 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. Inténtalo de nuevo. Si el problema persiste, muestra un mensaje en el que se sugiera al usuario que compruebe su conexión a Internet.
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. Vuelve a intentarlo tras una breve pausa.
OT_MEDIA_ERR_DECODE Se ha producido un error de decodificación al intentar reproducir la transmisión en el elemento de vídeo. Vuelve a intentarlo tras un breve intervalo. 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. Inténtalo de nuevo. Si el problema persiste, comprueba la configuración de la fuente de vídeo o audio del editor.
OT_SET_REMOTE_DESCRIPTION_FAILED La conexión WebRTC ha fallado durante setRemoteDescription. Normalmente se trata de un problema de señalización pasajero. Vuelve a intentarlo con un periodo de espera. Si el problema persiste tras todos los intentos, informa al usuario de un posible problema de red.
OT_UNEXPECTED_SERVER_RESPONSE El servidor ha devuelto un error inesperado. Vuelve a intentarlo una vez tras una breve pausa. Si el problema persiste, registra el error e informa al usuario.

Errores que requieren una acción diferente (no basta con volver a intentarlo)

Algunos errores no se resuelven ni con un simple reintento ni con una interrupción total; requieren una medida correctiva específica antes de volver a intentarlo.

error.name Descripción Medida recomendada
OT_HARDWARE_UNAVAILABLE La cámara o el micrófono no están disponibles (por ejemplo, porque los está utilizando otra aplicación o porque están desconectados). Pide al usuario que cierre las demás aplicaciones que estén ejecutándose en el dispositivo y, a continuación, reinicia el editor con OT.initPublisher() antes de volver a intentarlo.
OT_NO_DEVICES_FOUND No se han encontrado dispositivos de entrada de audio ni de vídeo. Solicita al usuario que conecte un dispositivo. No vuelvas a intentarlo hasta que el usuario confirme que hay un dispositivo disponible.

Puesta en práctica: patrón de reintento recomendado con clasificación de errores

async function publishWithRetry(session, publisher, attempt = 1) {
  const MAX_RETRIES = 3;
  const RETRY_DELAY_MS = 2000;

  const error = await new Promise((resolve) => {
    session.publish(publisher, resolve);
  });

  if (!error) {
    console.log('Publishing started successfully.');
    return;
  }

  // Non-recoverable: programmer error or hard permission constraint
  const nonRetryable = [
    'OT_NOT_CONNECTED',
    'OT_PERMISSION_DENIED',
    'OT_INVALID_PARAMETER',
    'OT_USER_MEDIA_ACCESS_DENIED',
    'OT_CHROME_MICROPHONE_ACQUISITION_ERROR',
    'OT_SCREEN_SHARING_NOT_SUPPORTED',
    'OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED',
    'OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED',
    'OT_CONSTRAINTS_NOT_SATISFIED',
    'OT_NO_VALID_CONSTRAINTS',
    'OT_NOT_SUPPORTED',
    'OT_STREAM_CREATE_FAILED',
    'OT_INVALID_AUDIO_OUTPUT_SOURCE',
    'OT_UNABLE_TO_CAPTURE_MEDIA',
  ];

  // Requires corrective action before retrying
  const requiresAction = [
    'OT_HARDWARE_UNAVAILABLE',
    'OT_NO_DEVICES_FOUND',
  ];

  if (nonRetryable.includes(error.name)) {
    console.error('Non-retryable error — user action or code fix required:', error.name);
    handleNonRecoverableError(error);
    return;
  }

  if (requiresAction.includes(error.name)) {
    console.warn('Device error — prompting user before retrying:', error.name);
    handleDeviceError(error);
    return;
  }

  // Recoverable: retry with backoff
  if (attempt < MAX_RETRIES) {
    console.warn(`Publish attempt ${attempt} failed (${error.name}), retrying...`);
    await delay(RETRY_DELAY_MS * attempt);
    await publishWithRetry(session, publisher, attempt + 1);
  } else {
    console.error('All publish attempts failed. Disconnecting user.');
    handlePublishFailure(session);
  }
}

function handleNonRecoverableError(error) {
  // Surface a meaningful message to the user based on error.name
  // e.g. for OT_USER_MEDIA_ACCESS_DENIED: "Please allow camera/mic access"
}

function handleDeviceError(error) {
  // Prompt the user to check their device, then allow them to retry manually
}

function handlePublishFailure(session) {
  session.disconnect();
}

Uso:

const publisher = OT.initPublisher('publisher-container', publisherOptions);

// Wait for session to be connected before publishing
session.connect(token, (err) => {
  if (err) { /* handle connection error */ return; }
  publishWithRetry(session, publisher);
});

Importante: Limpieza del editor antes de volver a intentarlo

En la mayoría de los casos de fallo —incluidos OT_TIMEOUT / OT_ICE_WORKFLOW_FAILED — la instancia del editor se puede reutilizar directamente para el próximo session.publish() llamada. No es necesario reinicializarla.

Cuando falla un intento de publicación, el SDK cierra el flujo que estaba intentando crear y emite un streamDestroyed evento en el editor con reason: "reset". Se trata de una limpieza prevista y no no es necesario que reinicies el editor; puedes volver a intentarlo con la misma instancia. Ten en cuenta que "reset" es un motivo general del tipo «el flujo del editor se ha interrumpido» (también se muestra cuando se llama a publisher.destroy()), así que considéralo una señal de limpieza más que un indicador específico de fallo en la publicación; utiliza el error.name del session.publish() función de devolución de llamada para decidir si se debe volver a intentarlo.

El SDK hace lo siguiente: no reintentar automáticamente session.publish() En tu nombre: la lógica de reintento debe implementarse a nivel de aplicación, tal y como se muestra más arriba.

El único caso en el que debes reinicializar el editor con OT.initPublisher() antes de volver a intentarlo es cuando el propio editor destroyed Se activa el evento. Este evento es definitivo e indica que el propio objeto emisor ya no se puede utilizar.

publisher.on('destroyed', () => {
  // Publisher object is no longer usable — reinitialize before retrying
  publisher = OT.initPublisher('publisher-container', publisherOptions);
});

// A streamDestroyed event with reason 'reset' is emitted by the SDK when it tears
// down the stream (during a failed publish attempt, or when you call publisher.destroy()).
// A 'reset' during a failed publish does NOT require reinitializing the publisher.
publisher.on('streamDestroyed', (event) => {
  if (event.reason === 'reset') {
    // Expected cleanup — reuse the same publisher instance
    return;
  }
  // Handle other streamDestroyed reasons as appropriate for your application
});

Lo que NO hay que hacer

  • Haz no llamada OT.initPublisher() dos veces en el mismo objeto «publisher» con restricciones diferentes sin limpiarlo primero (session.unpublish() → esperar a streamDestroyed → y, a continuación, reinicializar).
  • Haz no intentarlo de nuevo en OT_PERMISSION_DENIED (el usuario ha denegado el acceso a la cámara o al micrófono): esto requiere una acción por parte del usuario, no un nuevo intento.
  • Haz no intentarlo de nuevo en OT_NOT_CONNECTED — Asegúrate de que la sesión esté conectada antes de publicar.
  • Haz no Reintentar indefinidamente — limitar a 3 reintentos y gestionar el fallo de forma adecuada.

Manejo del mediaStopped Evento

La reproducción del archivo multimedia se puede detener durante la publicación. Detecta este evento y utilízalo como desencadenante para volver a intentarlo:

publisher.on('mediaStopped', async () => {
  console.warn('Media stopped during publish — retrying...');
  // Unpublish if already publishing, then retry
  try { session.unpublish(publisher); } catch (e) { /* ignore */ }
  await delay(2000);
  publishWithRetry(session, publisher);
});

Resumen de los parámetros recomendados

Parámetro Valor recomendado Notas
Número máximo de intentos 3 Equilibra la resiliencia y el tiempo de espera del usuario
Retraso entre reintentos 2 s × intento (2 s, 4 s, 6 s) Da tiempo a la plataforma para recuperarse
Si fallan todos los reintentos Desconectar al usuario Evita el estado de «participante fantasma»
Errores que no se pueden volver a intentar OT_NOT_CONNECTED, OT_PERMISSION_DENIED Fracasa rápido en esto

Solución de problemas relacionados con la captura de audio: audioAcquisitionProblem y audioAcquisitionProblemResolved

Más allá de los reintentos a nivel de publicación, existe una categoría distinta de problemas de audio que pueden afectar a un editor activo: es posible que el dispositivo de audio del cliente no transmita los datos de audio incluso después de una publicación correcta. El SDK de JS de la Video API ofrece dos eventos específicos para este caso.

Causas habituales

El audioAcquisitionProblem El evento se activa cuando el SDK detecta —a través de las estadísticas del emisor— que la pista de audio ha dejado de enviar bytes a la conexión con el par, a pesar de que getUserMedia Se ha realizado correctamente y la editorial parece estar activa. Las causas principales más habituales son:

  • Dispositivo de audio Bluetooth conectado o desconectado durante la sesión: Cuando un usuario conecta o desconecta unos auriculares, o conecta unos auriculares Bluetooth (por ejemplo, AirPods) durante una sesión activa, es posible que el sistema operativo cambie el dispositivo de audio predeterminado. Es posible que el canal de audio del navegador no consiga volver a detectar el micrófono en el nuevo dispositivo, lo que provocaría que no se enviaran bytes de audio.
  • Cambio de dispositivo de audio al inicio de la sesión: Cambiar la entrada de audio al principio de la sesión —en los primeros 1 o 2 segundos tras la publicación— suele provocar este problema con especial frecuencia.
  • Pista de audio finalizada por el navegador o el sistema operativo (trackEndedEvent): El navegador puede detener la pista de audio subyacente independientemente de cualquier acción del usuario. El SDK detecta esto a través de un track.ended evento y recauda fondos audioAcquisitionProblem con method: trackEndedEvent.
  • Detección basada en estadísticas (no se transmiten bytes de audio): Una vez que la conexión entre pares alcanza el estado «conectada», el SDK consulta las estadísticas del emisor aproximadamente cada pocos segundos. Si la pista de audio saliente bytesSent no aumenta entre encuestas consecutivas, audioAcquisitionProblem se genera (con method: getStats). Cuando bytesSent empieza a aumentar de nuevo, audioAcquisitionProblemResolved se plantea.

Nota: Este evento no siempre indica un fallo grave. En algunas sesiones, el audio se restablece por sí solo (y audioAcquisitionProblemResolved se interrumpe); en otros casos, el flujo de audio nunca se recupera y los suscriptores posteriores pueden acabar agotando el tiempo de espera.

Los eventos

Estos eventos se emiten en la instancia del editor:

  • audioAcquisitionProblem — se activa cuando el SDK detecta que el editor ha dejado de enviar audio (según las estadísticas del editor), o cuando la pista de audio subyacente activa un ended evento. Esto no significa necesariamente que la transmisión vaya a fallar, pero es un indicio de que la captura de audio se ha interrumpido.
  • audioAcquisitionProblemResolved — se activa cuando se restablece la transmisión de audio tras una interrupción previa audioAcquisitionProblem. Si se activa este evento, no es necesario tomar ninguna medida correctiva.

Nota: Estos eventos se celebran actualmente no forma parte de la API pública documentada/definida (no están declaradas en las definiciones de TypeScript del SDK). Considéralas señales orientativas que pueden variar de una versión a otra, y Verify su disponibilidad con tu versión del SDK antes de utilizarlas en producción. Cuando se emiten en el editor, incluyen un method propiedad que indica cómo se detectó el problema ('getStats' o 'trackEndedEvent').

Nota: Las comprobaciones de adquisición de audio se basan en las estadísticas del editor, por lo que puede producirse un breve retraso entre la interrupción real del audio y el momento en que se genera el evento.

Patrón de recuperación recomendado

Activar un temporizador corto al recibir audioAcquisitionProblem. Si audioAcquisitionProblemResolved Si el problema se soluciona antes de que expire el temporizador, el audio se habrá restablecido por sí solo y no será necesario realizar ninguna acción. Si el temporizador expira sin que se haya solucionado el problema, cambia la fuente de audio como medida de recuperación.

publisher.on('audioAcquisitionProblem', () => {
  // Start a 3-second timer
  const timeout = setTimeout(() => {
    // Problem not resolved — attempt recovery by switching audio source
    publisher.setAudioSource(newDeviceId);
  }, 3000);

  publisher.on('audioAcquisitionProblemResolved', () => {
    // Audio recovered — clear the timer, no action needed
    clearTimeout(timeout);
  });
});

Aspectos clave a tener en cuenta

  • No es un indicador de fallo seguro: audioAcquisitionProblem No siempre implica un fallo en la suscripción. Úsalo como una señal temprana para realizar un seguimiento y, en su caso, tomar medidas, no como un evento de fallo definitivo.
  • Supervisar las estadísticas de audio de los editores: Tras recibir audioAcquisitionProblem, también puedes consultar las estadísticas de audio del editor (por ejemplo, a través de publisher.getStats()) para comprobar si la transmisión de audio se ha interrumpido realmente antes de tomar medidas.
  • Medidas de recuperación: Llamando a publisher.setAudioSource(newDeviceId) es el mecanismo de recuperación principal. Esto permite cambiar el dispositivo de entrada de audio sin necesidad de realizar un ciclo completo de retirada y nueva publicación.
  • Relación con los tiempos de espera de las suscripciones: Si no se recupera el audio y el emisor sigue sin enviar paquetes de audio, los suscriptores podrían acabar encontrándose con OT_TIMEOUT (1501). Gestión proactiva de audioAcquisitionProblem puede ayudar a evitar este fallo posterior.