

# SDK de transmisión de IVS: guía para web \$1 Transmisión en tiempo real
<a name="broadcast-web"></a>

El SDK de transmisión web para transmisión en tiempo real de IVS ofrece a los desarrolladores las herramientas para crear experiencias interactivas y en tiempo real en la web. El SDK está pensado para los desarrolladores que crean aplicaciones web con Amazon IVS.

El SDK de transmisión web permite a los participantes enviar y recibir videos. El SDK admite las siguientes operaciones:
+ Incorporación a un escenario
+ Publicación de contenido multimedia para otros participantes del escenario
+ Suscripción al contenido multimedia de otros participantes del escenario
+ Administración y monitoreo del video y audio publicados en el escenario
+ Obtención de estadísticas de WebRTC de cada conexión de pares
+ Todas las operaciones del SDK de transmisión web de transmisión de baja latencia de IVS

**Versión más reciente del SDK de transmisión para web:** 1.33.0 ([notas de la versión](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-web-rt)) 

**Documentación de referencia:** a fin de obtener información sobre los métodos más importantes disponibles en el SDK de transmisión web de Amazon IVS, consulte [https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Asegúrese de seleccionar la versión más reciente del SDK.

**Código de ejemplo**: los siguientes ejemplos son un buen punto para empezar rápidamente a usar el SDK:
+ [Reproducción sencilla](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [Publicación y suscripción simple](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [Demostración completa de colaboración en tiempo real con React](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**Requisitos de la plataforma**: consulte [SDK de transmisión de Amazon IVS](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html) para obtener un listado de las plataformas compatibles.

**Nota:** Publicar desde un navegador es práctico para los usuarios finales, ya que no requiere la instalación de software adicional. Sin embargo, la publicación basada en un navegador depende de las restricciones y la variabilidad de los entornos de los navegadores. Si necesita priorizar la estabilidad (por ejemplo, para la transmisión de eventos), solemos recomendar publicar desde una fuente que no sea un navegador (por ejemplo, OBS Studio u otros codificadores dedicados), que suelen tener acceso directo a los recursos del sistema y evitan las limitaciones del navegador. Para obtener más información sobre las opciones de publicación distintas del navegador, consulte la documentación de [Ingesta de transmisiones](rt-stream-ingest.md).

# Introducción al SDK de transmisión para web de IVS \$1 Transmisión en tiempo real
<a name="broadcast-web-getting-started"></a>

Este documento explica los pasos necesarios para comenzar a utilizar el SDK de transmisión para web de la transmisión en tiempo real de IVS.

## Importaciones
<a name="broadcast-web-getting-started-imports"></a>

Los componentes básicos de la transmisión en tiempo real se encuentran en un espacio de nombres diferente al de los módulos de transmisión raíz.

### Uso de una etiqueta de script
<a name="broadcast-web-getting-started-imports-script"></a>

El SDK de transmisión web se distribuye como biblioteca de JavaScript y se puede obtener en [https://web-broadcast.live-video.net/1.33.0/amazon-ivs-web-broadcast.js](https://web-broadcast.live-video.net/1.33.0/amazon-ivs-web-broadcast.js).

Las clases y enumeraciones definidas en los ejemplos siguientes se pueden encontrar en el objeto global `IVSBroadcastClient`:

```
const { Stage, SubscribeType } = IVSBroadcastClient;
```

### Con npm
<a name="broadcast-web-getting-started-imports-npm"></a>

Para instalar el paquete de `npm`: 

```
npm install amazon-ivs-web-broadcast
```

Las clases, enumeraciones y tipos también se pueden importar desde el módulo del paquete:

```
import { Stage, SubscribeType, LocalStageStream } from 'amazon-ivs-web-broadcast'
```

### Compatibilidad con la representación del servidor
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

La biblioteca de fases del SDK de transmisión para web no se puede cargar en un contexto del servidor, ya que hace referencia a los elementos básicos del navegador necesarios para el funcionamiento de la biblioteca cuando se carga. Para solucionar este problema, cargue la biblioteca de forma dinámica, como se muestra en la [demostración de transmisión web con Next y React](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31).

## Solicitar permisos
<a name="broadcast-web-request-permissions"></a>

La aplicación debe solicitar permiso para acceder a la cámara y al micrófono del usuario, y deberán ser ofrecidos mediante HTTPS. (Esto no es específico de Amazon IVS; es necesario para cualquier sitio web que necesite acceso a cámaras y micrófonos).

A continuación, le presentamos una función a modo de ejemplo que muestra cómo solicitar y capturar permisos para los dispositivos de audio y video:

```
async function handlePermissions() {
   let permissions = {
       audio: false,
       video: false,
   };
   try {
       const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
       for (const track of stream.getTracks()) {
           track.stop();
       }
       permissions = { video: true, audio: true };
   } catch (err) {
       permissions = { video: false, audio: false };
       console.error(err.message);
   }
   // If we still don't have permissions after requesting them display the error message
   if (!permissions.video) {
       console.error('Failed to get video permissions.');
   } else if (!permissions.audio) {
       console.error('Failed to get audio permissions.');
   }
}
```

Para obtener más información, consulte la [API de permisos](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) y [MediaDevices.getUserMedia()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).

## Enlistar los dispositivos disponibles
<a name="broadcast-web-request-list-devices"></a>

Para conocer los dispositivos que puede capturar, consulte el método [MediaDevices.enumerateDevices()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) del navegador:

```
const devices = await navigator.mediaDevices.enumerateDevices();
window.videoDevices = devices.filter((d) => d.kind === 'videoinput');
window.audioDevices = devices.filter((d) => d.kind === 'audioinput');
```

## Recuperar MediaStream de un dispositivo
<a name="broadcast-web-retrieve-mediastream"></a>

Después de obtener la lista de dispositivos disponibles, puede recuperar una transmisión de diversos dispositivos. Por ejemplo, puede utilizar el método `getUserMedia()` para recuperar la transmisión de una cámara.

Si quisiera indicar desde cuál dispositivo desea capturar la transmisión, puede establecer de forma expresa `deviceId` en las secciones `audio` o `video` de las restricciones de multimedia. De forma alternativa, puede omitir `deviceId` y que los usuarios seleccionen los dispositivos desde el símbolo del navegador.

También puede especificar la resolución de cámara ideal mediante las restricciones `width` y `height`. (Obtenga más información sobre estas restricciones [aquí](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks)). El SDK aplica de forma automática las restricciones máximas de ancho y alto que corresponden a la resolución máxima de transmisión; sin embargo, es aconsejable que las aplique usted mismo para garantizar que la relación de aspecto de la fuente no cambie después de que la agregue al SDK.

Para la transmisión en tiempo real, asegúrese de que el contenido multimedia esté limitado a una resolución de 720p. En concreto, sus valores de ancho y alto de la restricción de `getUserMedia` y `getDisplayMedia` no deben ser superiores a 921 600 (1280\$1720) cuando se multiplican. 

```
const videoConfiguration = {
  maxWidth: 1280,
  maxHeight: 720,
  maxFramerate: 30,
}

window.cameraStream = await navigator.mediaDevices.getUserMedia({
   video: {
       deviceId: window.videoDevices[0].deviceId,
       width: {
           ideal: videoConfiguration.maxWidth,
       },
       height: {
           ideal:videoConfiguration.maxHeight,
       },
   },
});
window.microphoneStream = await navigator.mediaDevices.getUserMedia({
   audio: { deviceId: window.audioDevices[0].deviceId },
});
```

# Publicación y suscripción con el SDK de transmisión para web de IVS \$1 Transmisión en tiempo real
<a name="web-publish-subscribe"></a>

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

## Conceptos
<a name="web-publish-subscribe-concepts"></a>

Los siguientes tres conceptos básicos subyacen a la funcionalidad de transmisión en tiempo real: [escenario](#web-publish-subscribe-concepts-stage), [estrategia](#web-publish-subscribe-concepts-strategy) y [eventos](#web-publish-subscribe-concepts-events). El objetivo del diseño es minimizar la cantidad de lógica necesaria por parte del cliente para crear un producto que funcione.

### Etapa
<a name="web-publish-subscribe-concepts-stage"></a>

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

```
const stage = new Stage(token, strategy)

try {
   await stage.join();
} catch (error) {
   // handle join exception
}

stage.leave();
```

### Strategy (Estrategia)
<a name="web-publish-subscribe-concepts-strategy"></a>

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

Para usar una estrategia definida, pásela al constructor de `Stage`. El siguiente es un ejemplo completo de una aplicación que utiliza una estrategia para publicar la cámara web de un participante en el escenario y suscribirse a todos los participantes. El propósito de cada función de estrategia necesaria se explica detalladamente en las siguientes secciones.

```
const devices = await navigator.mediaDevices.getUserMedia({ 
   audio: true,
   video: {
        width: { max: 1280 },
        height: { max: 720 },
    } 
});
const myAudioTrack = new LocalStageStream(devices.getAudioTracks()[0]);
const myVideoTrack = new LocalStageStream(devices.getVideoTracks()[0]);

// Define the stage strategy, implementing required functions
const strategy = {
   audioTrack: myAudioTrack,
   videoTrack: myVideoTrack,

   // optional
   updateTracks(newAudioTrack, newVideoTrack) {
      this.audioTrack = newAudioTrack;
      this.videoTrack = newVideoTrack;
   },

   // required
   stageStreamsToPublish() {
      return [this.audioTrack, this.videoTrack];
   },

   // required
   shouldPublishParticipant(participant) {
      return true;
   },

   // required
   shouldSubscribeToParticipant(participant) {
      return SubscribeType.AUDIO_VIDEO;
   }
};

// Initialize the stage and start publishing
const stage = new Stage(token, strategy);
await stage.join();


// To update later (e.g. in an onClick event handler)
strategy.updateTracks(myNewAudioTrack, myNewVideoTrack);
stage.refreshStrategy();
```

#### Suscripción a participantes
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

```
shouldSubscribeToParticipant(participant: StageParticipantInfo): SubscribeType
```

Cuando un participante remoto se incorpora al escenario, el SDK consulta la aplicación host sobre el estado de suscripción deseado de ese participante. Las opciones son `NONE`, `AUDIO_ONLY` y `AUDIO_VIDEO`. Al devolver un valor para esta función, la aplicación host no tiene que preocuparse por el estado de la publicación, el estado actual de la suscripción ni el estado de la conexión del escenario. Si se devuelve `AUDIO_VIDEO`, el SDK espera a que el participante remoto publique antes de suscribirse y actualiza la aplicación host al emitir eventos durante todo el proceso.

Este es un ejemplo de implementación:

```
const strategy = {
   
   shouldSubscribeToParticipant: (participant) => {
      return SubscribeType.AUDIO_VIDEO;
   }

   // ... other strategy functions
}
```

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

También son posibles implementaciones más avanzadas. Por ejemplo, supongamos que la aplicación proporciona un atributo `role` al crear el token con CreateParticipantToken. La aplicación podría utilizar la propiedad `attributes` en `StageParticipantInfo` para suscribirse de forma selectiva a los participantes en función de los atributos proporcionados por el servidor:

```
const strategy = {
   
   shouldSubscribeToParticipant(participant) {
      switch (participant.attributes.role) {
         case 'moderator':
            return SubscribeType.NONE;
         case 'guest':
            return SubscribeType.AUDIO_VIDEO;
         default:
            return SubscribeType.NONE;
      }
   }
   // . . . other strategies properties
}
```

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

#### Configuración de la suscripción a participantes
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

```
subscribeConfiguration(participant: StageParticipantInfo): SubscribeConfiguration
```

Si se está subscribiendo a un participante remoto (consulte [Suscripción a participantes](#web-publish-subscribe-concepts-strategy-participants)), el SDK consulta a la aplicación host sobre una configuración de la subscrición personalizada para ese participante. Esta configuración es opcional y permite a la aplicación host controlar determinados aspectos del comportamiento de los suscriptores. Para obtener información sobre lo que se puede configurar, consulte [SubscribeConfiguration](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration) en la documentación de referencia del SDK.

Este es un ejemplo de implementación:

```
const strategy = {
   
   subscribeConfiguration: (participant) => {
      return {
         jitterBuffer: {
            minDelay: JitterBufferMinDelay.MEDIUM
         }  
      }

   // ... other strategy functions
}
```

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

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

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

#### Publicación
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

```
shouldPublishParticipant(participant: StageParticipantInfo): boolean
```

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

Este es un ejemplo de implementación:

```
const strategy = {
   
   shouldPublishParticipant: (participant) => {
      return true;
   }

   // . . . other strategies properties
}
```

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

#### Elección de las transmisiones que publicar
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

```
stageStreamsToPublish(): LocalStageStream[];
```

Al publicar, esto se utiliza para determinar qué transmisiones de audio y video se tienen que publicar. Esto se explica en mayor detalle más adelante en [Publicación de una transmisión multimedia](#web-publish-subscribe-publish-stream).

#### Actualización de la estrategia
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

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

Si el valor devuelto de `shouldSubscribeToParticipant` cambia de `AUDIO_VIDEO` a `AUDIO_ONLY`, la transmisión de video se elimina para todos los participantes con valores devueltos modificados, si ya existía con anterioridad una transmisión de video.

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

### Events
<a name="web-publish-subscribe-concepts-events"></a>

Una instancia `Stage` es un emisor de eventos. Con `stage.on()`, el estado del escenario se comunica a la aplicación host. Por lo general, los eventos permiten actualizar por completo la interfaz de usuario de la aplicación host. Los eventos son los siguientes:

```
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participant, state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participant, state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => {})
stage.on(StageEvents.STAGE_STREAM_ADAPTION_CHANGED, (participant, stream, isAdapting) => ())
stage.on(StageEvents.STAGE_STREAM_LAYERS_CHANGED, (participant, stream, layers) => ())
stage.on(StageEvents.STAGE_STREAM_LAYER_SELECTED, (participant, stream, layer, reason) => ())
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {})
stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, stream) => {})
```

Para la mayoría de estos métodos, se proporciona la `ParticipantInfo` correspondiente.

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

## Publicación de una transmisión multimedia
<a name="web-publish-subscribe-publish-stream"></a>

Los dispositivos locales, como micrófonos y cámaras, se recuperan siguiendo los mismos pasos descritos anteriormente en [Recuperación de MediaStream de un dispositivo](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream). En el ejemplo, utilizamos `MediaStream` para crear una lista de objetos `LocalStageStream` que el SDK utiliza para publicar:

```
try {
    // Get stream using steps outlined in document above
    const stream = await getMediaStreamFromDevice();

    let streamsToPublish = stream.getTracks().map(track => {
        new LocalStageStream(track)
    });

    // Create stage with strategy, or update existing strategy
    const strategy = {
        stageStreamsToPublish: () => streamsToPublish
    }
}
```

## Publicación de una pantalla compartida
<a name="web-publish-subscribe-publish-screenshare"></a>

Las aplicaciones suelen necesitar publicar una pantalla compartida además de la cámara web del usuario. Para publicar una pantalla compartida, es necesario crear un token adicional para la fase, específicamente para publicar el contenido multimedia de la pantalla compartida. Use `getDisplayMedia` y restrinja la resolución a un máximo de 720p. Después de eso, los pasos son similares a publicar una cámara en la fase.

```
// Invoke the following lines to get the screenshare's tracks
const media = await navigator.mediaDevices.getDisplayMedia({
   video: {
      width: {
         max: 1280,
      },
      height: {
         max: 720,
      }
   }
});
const screenshare = { videoStream: new LocalStageStream(media.getVideoTracks()[0]) };
const screenshareStrategy = {
   stageStreamsToPublish: () => {
      return [screenshare.videoStream];
   },
   shouldPublishParticipant: (participant) => {
      return true;
   },
   shouldSubscribeToParticipant: (participant) => {
      return SubscribeType.AUDIO_VIDEO;
   }
}
const screenshareStage = new Stage(screenshareToken, screenshareStrategy);
await screenshareStage.join();
```

## Visualización y eliminación de participantes
<a name="web-publish-subscribe-participants"></a>

Cuando se complete la suscripción, recibirá una matriz de objetos `StageStream` a través del evento `STAGE_PARTICIPANT_STREAMS_ADDED`. El evento también le brinda información sobre los participantes que le será de ayuda al visualizar las transmisiones multimedia:

```
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {
    let streamsToDisplay = streams;

    if (participant.isLocal) {
        // Ensure to exclude local audio streams, otherwise echo will occur
        streamsToDisplay = streams.filter(stream => stream.streamType === StreamType.VIDEO)
    }

    // Create or find video element already available in your application
    const videoEl = getParticipantVideoElement(participant.id);

    // Attach the participants streams
    videoEl.srcObject = new MediaStream();
    streamsToDisplay.forEach(stream => videoEl.srcObject.addTrack(stream.mediaStreamTrack));
})
```

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

`STAGE_PARTICIPANT_STREAMS_REMOVED` se invoca para todas las situaciones en las que se puede eliminar una transmisión, como las siguientes:
+ El participante remoto deja de publicar.
+ Un dispositivo local cancela la suscripción o cambia la suscripción de `AUDIO_VIDEO` a `AUDIO_ONLY`.
+ El participante remoto abandona el escenario.
+ El participante local abandona el escenario.

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

## Activación y desactivación del sonido de las transmisiones multimedia
<a name="web-publish-subscribe-mute-streams"></a>

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

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

## Monitoreo del estado de sonido desactivado en los contenidos multimedia del participante remoto
<a name="web-publish-subscribe-mute-state"></a>

Cuando los participantes cambian el estado de sonido desactivado de su video o audio, el evento `STAGE_STREAM_MUTE_CHANGED` se activa con una lista de las transmisiones que cambiaron. Use la propiedad `isMuted` en `StageStream` para actualizar su interfaz de usuario según corresponda:

```
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {
   if (stream.streamType === 'video' && stream.isMuted) {
       // handle UI changes for video track getting muted
   }
})
```

Además, puede consultar [StageParticipantInfo](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo) para obtener información del estado sobre si el audio o el video están silenciados:

```
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {
   if (participant.videoStopped || participant.audioMuted) {
       // handle UI changes for either video or audio
   }
})
```

## Obtención de estadísticas de WebRTC
<a name="web-publish-subscribe-webrtc-stats"></a>

El método `requestQualityStats()` proporciona acceso a estadísticas WebRTC detalladas para transmisiones locales y remotas. Está disponible en los objetos LocalStageStream y RemoteStageStream. Devuelve métricas de calidad completas, como la calidad de la red, las estadísticas de paquetes, la información sobre la velocidad de bits y las métricas relacionadas con las tramas.

Este es un método asíncrono con el que puede recuperar estadísticas mediante await o encadenando una promesa. Se devuelve `undefined` cuando las estadísticas no están disponibles; por ejemplo, si la transmisión no está activa o las estadísticas internas no están disponibles. Si hay estadísticas disponibles y en función de la transmisión (remota o local, video o audio), el método devuelve un objeto [LocalVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalVideoStats), [LocalAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalAudioStats), [RemoteVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteVideoStats) o [RemoteAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteAudioStats).

Tenga en cuenta que, en el caso de las transmisiones de vídeo con transmisión simultánea, la matriz contiene varios objetos de estadísticas (uno por capa).

**Prácticas recomendadas**
+ Frecuencia de sondeo: llame a `requestQualityStats()` intervalos razonables (de 1 a 5 segundos) para evitar que el rendimiento se vea afectado
+ Gestión de errores: compruebe siempre si el valor devuelto es `undefined` antes de procesarlo
+ Administración de memoria: borre los intervalos y tiempos de espera cuando las transmisiones ya no sean necesarias
+ Calidad de la red: se utiliza `networkQuality` para obtener comentarios de los usuarios sobre las posibles degradaciones causadas por la red. Para obtener más información, consulte [NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality).

**Ejemplo de uso**

```
// For local streams
const localStats = await localVideoStream.requestQualityStats();
const audioStats = await localAudioStream.requestQualityStats();

// For remote streams
const remoteVideoStats = await remoteVideoStream.requestQualityStats();
const remoteAudioStats = await remoteAudioStream.requestQualityStats();

// Example: Monitor stats every 10 seconds
const statsInterval = setInterval(async () => {
   const stats = await localVideoStream.requestQualityStats();
   if (stats) {
      // Note: If simulcast is enabled, you may receive multiple 
      // stats records for each layer
      stats.forEach(layer => {
         const rid = layer.rid || 'default';
         console.log(`Layer ${rid}:`, {
            active: layer.active,
            networkQuality: layer.networkQuality,
            packetsSent: layer.packetsSent,
            bytesSent: layer.bytesSent,
            resolution: `${layer.frameWidth}x${layer.frameHeight}`,
            fps: layer.framesPerSecond
         });
      });
   }
}, 10000);
```

## Optimización del contenido multimedia
<a name="web-publish-subscribe-optimizing-media"></a>

Se recomienda limitar las llamadas a `getUserMedia` y a `getDisplayMedia` con las siguientes restricciones para obtener el mejor rendimiento:

```
const CONSTRAINTS = {
    video: {
        width: { ideal: 1280 }, // Note: flip width and height values if portrait is desired
        height: { ideal: 720 },
        framerate: { ideal: 30 },
    },
};
```

Puede restringir aún más el contenido multimedia mediante opciones adicionales que se pasan al constructor `LocalStageStream`:

```
const localStreamOptions = {
    minBitrate?: number;
    maxBitrate?: number;
    maxFramerate?: number;
    simulcast: {
        enabled: boolean
    }
}
const localStream = new LocalStageStream(track, localStreamOptions)
```

En el código anterior:
+ `minBitrate` establece la velocidad de bits mínima que se espera que utilice el navegador. Sin embargo, una transmisión de video de poca complejidad puede hacer que el codificador establezca una velocidad inferior a esta velocidad de bits.
+ `maxBitrate` establece una velocidad de bits máxima que se espera que el navegador no supere para esta transmisión.
+ `maxFramerate` establece una velocidad de fotogramas máxima que se espera que el navegador no supere para esta transmisión.
+ La opción `simulcast` solo se puede utilizar en navegadores basados en Chromium. Permite enviar tres capas de representación de la transmisión.
  + Esto permite al servidor elegir qué representación enviar a otros participantes, en función de sus limitaciones de red.
  + Cuando `simulcast` se especifica junto con un valor de `maxBitrate` o `maxFramerate`, se espera que la capa de representación más alta se configure teniendo en cuenta estos valores, siempre que `maxBitrate` no sea inferior al valor predeterminado de `maxBitrate` (900 kbps) de la segunda capa más alta del SDK interno.
  + Si `maxBitrate` se especifica como demasiado baja en comparación con el valor predeterminado de la segunda capa más alta, `simulcast` se desactivará.
  + `simulcast` no se puede activar y desactivar sin volver a publicar el contenido multimedia. Para ello, `shouldPublishParticipant` tiene que devolver `false` y llamar a `refreshStrategy`; `shouldPublishParticipant` tiene que devolver `true` y llamar a `refreshStrategy` otra vez.

## Obtención de los atributos de los participantes
<a name="web-publish-subscribe-participant-attributes"></a>

Si especifica atributos en la solicitud de la operación de `CreateParticipantToken`, podrá ver los atributos en las propiedades de `StageParticipantInfo`:

```
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {
   console.log(`Participant ${participant.id} info:`, participant.attributes);
})
```

## Información de mejora adicional (SEI)
<a name="web-publish-subscribe-sei-attributes"></a>

La unidad NAL de información de mejora adicional (SEI) se usa para almacenar metadatos alineados con los fotogramas junto con el video. Se puede utilizar al publicar y suscribirse a transmisiones de video H.264. No se garantiza que las cargas útiles de SEI lleguen a los suscriptores, sobre todo en malas condiciones de la red. Como la carga útil del SEI almacena los datos directamente dentro de la estructura de fotogramas H.264, esta capacidad no se puede aprovechar para transmisiones únicamente de audio.

### Inserción de cargas útiles de SEI
<a name="sei-attributes-inserting-sei-payloads"></a>

Los clientes de publicación pueden insertar cargas útiles de SEI en una transmisión de escenario que se esté publicando si se configura el LocalStageStream del video para activar `inBandMessaging` y, posteriormente, se invoca el método `insertSeiMessage`. Tenga en cuenta que habilitar `inBandMessaging` aumenta el uso de memoria del SDK.

Las cargas útiles deben ser del tipo [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). El tamaño de la carga útil debe ser superior a 0 KB e inferior a 1 KB. El número de mensajes SEI insertados por segundo no debe superar los 10 KB por segundo.

```
const config = {
    inBandMessaging: { enabled: true }
};
const vidStream = new LocalStageStream(videoTrack, config);
const payload = new TextEncoder().encode('hello world').buffer;
vidStream.insertSeiMessage(payload);
```

#### Cargas útiles de SEI que se repiten
<a name="sei-attributes-repeating-sei-payloads"></a>

De manera opcional, proporcione un `repeatCount` para repetir la inserción de las cargas útiles del SEI para los siguientes N fotogramas enviados. Esto podría ser útil para reducir la pérdida inherente que puede producirse debido al protocolo de transporte UDP subyacente utilizado para enviar el video. Tenga en cuenta que este valor debe estar entre 0 y 30. Los clientes receptores deben tener una lógica para desduplicar el mensaje.

```
vidStream.insertSeiMessage(payload, { repeatCount: 5 }); // Optional config, repeatCount must be between 0 and 30
```

### Lectura de cargas útiles de SEI
<a name="sei-attributes-reading-sei-payloads"></a>

Los clientes suscritos pueden leer las cargas útiles de SEI de un publicador que publique video H.264, si está presente, al configurar el `SubscribeConfiguration` de los suscriptores para que habiliten `inBandMessaging` y escuchen el evento `StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED`, como se muestra en el siguiente ejemplo:

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            inBandMessaging: {
                enabled: true
            }
        }
    }
    // ... other strategy functions
}

stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, seiMessage) => {
    console.log(seiMessage.payload, seiMessage.uuid);
});
```

## Codificación por capas con la transmisión simultánea
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

La codificación por capas con transmisión simultánea es una característica de transmisión en tiempo real de IVS que permite a quienes publican enviar múltiples capas de video con diferentes niveles de calidad, mientras que los suscriptores pueden cambiar estas capas de manera dinámica o manual. Esta característica se describe con más detalle en el documento [Optimizaciones de transmisión](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html).

### Configuración de la codificación por capas (publicador)
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

Como publicador, para habilitar la codificación por capas con transmisión simultánea, agregue la siguiente configuración a `LocalStageStream` en la instanciación:

```
// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: { enabled: true }
})
```

En función de la resolución de entrada del dispositivo de cámara, se codificará y enviará una cantidad determinada de capas, tal como se define en la sección [Capas, calidades y velocidades de fotogramas predeterminadas](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers) de *Optimizaciones de transmisión*.

Además, si lo desea, puede configurar capas individuales desde la configuración de transmisión simultánea:

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         SimulcastLayerPresets.DEFAULT_720,
          SimulcastLayerPresets.DEFAULT_360,
          SimulcastLayerPresets.DEFAULT_180, 
   }
})
```

De manera opcional, también puede crear sus propias configuraciones de capas personalizadas para hasta tres capas. Si proporciona una matriz vacía o ningún valor, se utilizan los valores predeterminados descritos con anterioridad. Las capas se describen con las siguientes propiedades obligatorias:
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

A partir de los ajustes preestablecidos, puede anular las propiedades individuales o crear una configuración completamente nueva:

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

const custom720pLayer = {
   ...SimulcastLayerPresets.DEFAULT_720,
   maxFramerate: 15,
}

const custom360pLayer = {
       maxBitrateKbps: 600,
       maxFramerate: 15,
       width: 640,
       height: 360,
}

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         custom720pLayer,
         custom360pLayer, 
   }
})
```

Para conocer los valores máximos, los límites y los errores que se pueden activar al configurar capas individuales, consulta la documentación de referencia del SDK.

### Configuración de la codificación por capas (suscriptor)
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

Como suscriptor, no es necesario hacer nada para habilitar la codificación por capas. Si un publicador envía capas de transmisión simultánea, el servidor, de forma predeterminada, se adaptará dinámicamente entre las capas para elegir la calidad óptima en función de las condiciones de la red y del dispositivo del suscriptor.

Como alternativa, existen varias opciones para seleccionar las capas explícitas que envía el publicador, tal y como se describe a continuación.

### Opción 1: preferencia de calidad de la capa inicial
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

Mediante la estrategia `subscribeConfiguration`, es posible elegir qué capa inicial desea recibir como suscriptor:

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            simulcast: {
                initialLayerPreference: InitialLayerPreference.LOWEST_QUALITY
            }
        }
    }
    // ... other strategy functions
}
```

De forma predeterminada, a los suscriptores siempre se les envía primero la capa de calidad más baja; poco a poco se incrementa hasta llegar a la capa de calidad más alta. Esto optimiza el consumo de ancho de banda del usuario final y proporciona el mejor tiempo de inicio del video, lo cual reduce las congelaciones iniciales de video para los usuarios en redes más débiles.

Estas opciones se encuentran disponibles para `InitialLayerPreference`:
+ `LOWEST_QUALITY`: el servidor entrega primero la capa de video de menor calidad. Esto optimiza tanto el consumo de ancho de banda como el tiempo de inicio del contenido multimedia. La calidad se define como la combinación de tamaño, velocidad de bits y velocidad de fotogramas del video. Por ejemplo, un video 720p es de menor calidad que un video 1080p.
+ `HIGHEST_QUALITY`: el servidor entrega primero la capa de video de mayor calidad. Esto optimiza la calidad, pero puede aumentar el tiempo de inicio del contenido multimedia. La calidad se define como la combinación de tamaño, velocidad de bits y velocidad de fotogramas del video. Por ejemplo, el video 1080p es de mayor calidad que el video 720p.

**Nota:** Para que se apliquen las preferencias de la capa inicial (la llamada `initialLayerPreference`), es necesario volver a suscribirse, ya que estas actualizaciones no se aplican a la suscripción activa.



### Opción 2: capa preferida para la transmisión
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

Una vez iniciada la transmisión, podrá utilizar el método de estrategia `preferredLayerForStream `. Este método de estrategia expone la información del participante y de la transmisión.

El método de estrategia se puede devolver de la siguiente manera:
+ El objeto de capa directamente, basado en lo que `RemoteStageStream.getLayers` devuelve 
+ La cadena de etiqueta del objeto de capa, en función de `StageStreamLayer.label`
+ Sin definir o nulo, lo que indica que no se debe seleccionar ninguna capa y que se prefiere la adaptación dinámica

Por ejemplo, la siguiente estrategia hará que los usuarios seleccionen siempre la capa de video de menor calidad disponible:

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        return stream.getLowestQualityLayer();
    }
    // ... other strategy functions
}
```

Para restablecer la selección de capas y volver a la adaptación dinámica, devuelva nulo o sin definir en la estrategia. En este ejemplo, `appState` es una variable ficticia que representa el estado posible de la aplicación.

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        if (appState.isAutoMode) {
            return null;
        } else {
            return appState.layerChoice
        }
    }
    // ... other strategy functions
}
```

### Opción 3: ayudantes de la capa RemoteStageStream
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream` cuenta con varios ayudantes que se pueden utilizar para tomar decisiones sobre la selección de capas y mostrar las selecciones correspondientes a los usuarios finales:
+ **Eventos de capa**: además de los `StageEvents`, el propio objeto `RemoteStageStream` tiene eventos que comunican los cambios de adaptación de capa y transmisión simultánea:
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **Métodos de capa**: `RemoteStageStream` tiene varios métodos de ayudante que se pueden utilizar para obtener información sobre la transmisión y las capas que se presentan. Estos métodos están disponibles en la transmisión remota proporcionada en la estrategia `preferredLayerForStream `, así como en las transmisiones remotas expuestas a través de `StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

Para conocer los detalles, consulte la clase `RemoteStageStream` en la [documentación de referencia del SDK](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). En cuanto a la razón `LAYER_SELECTED`, si se devuelve `UNAVAILABLE`, esto indica que no se ha podido seleccionar la capa solicitada. En su lugar, se selecciona la mejor opción posible, que suele ser una capa de menor calidad para mantener la estabilidad de la transmisión.

## Gestión de los problemas de red
<a name="web-publish-subscribe-network-issues"></a>

Cuando se pierde la conexión de red del dispositivo local, el SDK se intenta volver a conectar internamente sin que el usuario lleve a cabo ninguna acción. En algunos casos, el SDK no funciona de manera correcta y es necesario que el usuario actúe.

En términos generales, el estado del escenario se puede gestionar mediante el evento `STAGE_CONNECTION_STATE_CHANGED`:

```
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {
   switch (state) {
      case StageConnectionState.DISCONNECTED:
         // handle disconnected UI
         return;
      case StageConnectionState.CONNECTING:
         // handle establishing connection UI
         return;
      case StageConnectionState.CONNECTED:
         // SDK is connected to the Stage
         return;
      case StageConnectionState.ERRORED:
         // SDK encountered an error and lost its connection to the stage. Wait for CONNECTED.
         return;
    }
})
```

En general, puede ignorar un estado de error que se produzca tras unirse correctamente a una fase, ya que el SDK intentará recuperarse internamente. Si el SDK informa de un estado `ERRORED` y la fase permanece en el estado `CONNECTING` durante un periodo prolongado (por ejemplo, 30 segundos o más), es probable que se haya desconectado de la red.

## Transmisión del escenario a un canal de IVS
<a name="web-publish-subscribe-broadcast-stage"></a>

Para transmitir un escenario, cree una sesión de `IVSBroadcastClient` independiente y, a continuación, siga las instrucciones habituales para la transmisión con el SDK, descritas con anterioridad. La lista de `StageStream` expuestas mediante `STAGE_PARTICIPANT_STREAMS_ADDED` se puede utilizar para recuperar las transmisiones multimedia participantes aplicables a la composición del flujo de transmisión, de la siguiente manera:

```
// Setup client with preferred settings
const broadcastClient = getIvsBroadcastClient();

stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {
    streams.forEach(stream => {
        const inputStream = new MediaStream([stream.mediaStreamTrack]);
        switch (stream.streamType) {
            case StreamType.VIDEO:
                broadcastClient.addVideoInputDevice(inputStream, `video-${participant.id}`, {
                    index: DESIRED_LAYER,
                    width: MAX_WIDTH,
                    height: MAX_HEIGHT
                });
                break;
            case StreamType.AUDIO:
                broadcastClient.addAudioInputDevice(inputStream, `audio-${participant.id}`);
                break;
        }
    })
})
```

Si lo desea, puede componer un escenario y transmitirlo a un canal de IVS de baja latencia para llegar a un público más amplio. Consulte [Habilitación de varios hosts en una transmisión de Amazon IVS](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html) en la Guía del usuario de transmisión de baja latencia.

# Problemas conocidos y soluciones alternativas del SDK de transmisión para web de IVS \$1 Transmisión en tiempo real
<a name="broadcast-web-known-issues"></a>

Este documento enumera problemas conocidos que puede experimentar al utilizar el SDK de transmisión para web de la transmisión en tiempo real de Amazon IVS y sugiere posibles soluciones alternativas.
+ Al cerrar las pestañas del navegador o salir de los navegadores sin llamar a `stage.leave()`, los usuarios pueden seguir apareciendo en la sesión con una pantalla congelada o negra durante un máximo de 10 segundos.

  **Solución alternativa:** ninguna.
+ Las sesiones de Safari aparecen de forma intermitente con una pantalla negra para que los usuarios se unan una vez iniciada la sesión.

  **Solución alternativa:** actualice el navegador y vuelva a conectar la sesión.
+ Safari no se recupera correctamente al cambiar de red.

  **Solución alternativa:** actualice el navegador y vuelva a conectar la sesión.
+ La consola para desarrolladores repite un error `Error: UnintentionalError at StageSocket.onClose`.

  **Solución alternativa:** solo se puede crear un escenario por token de participante. Este error se produce cuando se crea más de una instancia `Stage` con el mismo token de participante, independientemente de si la instancia está en un dispositivo o en varios.
+ Es posible que tenga problemas para mantener el estado `StageParticipantPublishState.PUBLISHED` y que reciba estados `StageParticipantPublishState.ATTEMPTING_PUBLISH` repetidos al escuchar el evento `StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED`.

  **Solución alternativa:** limite la resolución de video a 720p al invocar a `getUserMedia` o `getDisplayMedia`. En concreto, sus valores de ancho y alto de la restricción de `getUserMedia` y `getDisplayMedia` no deben ser superiores a 921 600 (1280\$1720) cuando se multiplican.
+ Cuando se invoca `stage.leave()` o un participante remoto abandona, aparece un error 404 DELETE en la consola de depuración del navegador.

  **Solución alternativa:** ninguna. Este es un error sin consecuencias.

## Limitaciones de Safari
<a name="broadcast-web-safari-limitations"></a>
+ Para denegar un mensaje de permisos, debe restablecer el permiso en la configuración del sitio web de Safari en el sistema operativo.
+ Safari no detecta todos los dispositivos de forma directa con la misma eficacia que Firefox o Chrome. Por ejemplo, no identifica la cámara virtual OBS.

## Limitaciones de Firefox
<a name="broadcast-web-firefox-limitations"></a>
+ Los permisos del sistema deben estar habilitados para que Firefox pueda compartir la pantalla. Luego de activarlos, el usuario debe reiniciar Firefox para que funcione sin inconvenientes; de lo contrario, si considera que los permisos están bloqueados, el navegador generará una excepción [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions).
+ Falta el método `getCapabilities`. Esto significa que los usuarios no pueden obtener la resolución o la relación de aspecto de la pista multimedia. Consulte este [hilo de Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084).
+ Faltan varias propiedades `AudioContext`, por ejemplo, la latencia y el recuento de canales. Esto podría suponer un problema para los usuarios avanzados que desean manejar las pistas de audio.
+ Las imágenes de la cámara de `getUserMedia` están limitadas a una relación de aspecto 4:3 en MacOS. Consulte el [hilo 1 de Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640) y el [hilo 2 de Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034).
+ Con `getDisplayMedia`, la captura de audio no es compatible. Consulte este [hilo de Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425).
+ La velocidad de fotogramas en la captura de pantalla es poco óptima (¿aproximadamente 15 fps?). Consulte este [hilo de Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522).

## Limitaciones de la web móvil
<a name="broadcast-web-mobile-web-limitations"></a>
+ Los dispositivos móviles no admiten el uso compartido de pantalla con [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility).

  **Solución alternativa:** ninguna.
+ El participante tarda entre 15 y 30 segundos en salir cuando cierra un navegador sin llamar a `leave()`.

  **Solución alternativa**: añada una interfaz de usuario que anime a los usuarios a desconectarse correctamente.
+ Poner en segundo plano la aplicación hace que se detenga la publicación del video.

  **Solución alternativa**: muestre una lista de interfaz de usuario cuando el publicador esté en pausa.
+ La velocidad de fotogramas del video se reduce durante aproximadamente 5 segundos después de desactivar el silenciamiento de una cámara en los dispositivos Android.

  **Solución alternativa:** ninguna.
+ La transmisión de video se estira al girar para iOS 16.0.

  **Solución alternativa**: muestre una interfaz de usuario en la que se describa este problema conocido del sistema operativo.
+ Al cambiar el dispositivo de entrada de audio, se cambia automáticamente el dispositivo de salida de audio.

  **Solución alternativa:** ninguna.
+ Al poner en segundo plano el navegador, el flujo de publicación se pone en negro y solo produce audio.

  **Solución alternativa:** ninguna. Lo hacemos por motivos de seguridad.

# Control de errores en el SDK de transmisión para web de IVS \$1 Transmisión en tiempo real
<a name="broadcast-web-error-handling"></a>

En esta sección se ofrece información general sobre las condiciones de error, cómo el SDK de transmisión para web las notifica a la aplicación y qué debe hacer una aplicación cuando se producen esos errores. El SDK informa de los errores a los oyentes del evento `StageEvents.ERROR`:

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    // log or handle errors here
    console.log(`${error.code}, ${error.category}, ${error.message}`);
});
```

## Errores de fases
<a name="web-error-handling-stage-errors"></a>

Se informa de un StageError cuando el SDK encuentra un problema del que no puede recuperarse y, por lo general, requiere la intervención de la aplicación o la reconexión de la red para recuperarse.

Cada `StageError` notificado tiene un código (o `StageErrorCode`), un mensaje (cadena) y una categoría (`StageErrorCategory`). Cada uno está relacionado con una categoría de operación subyacente.

La categoría de operación del error se determina en función de si está relacionado con la conexión a la fase (`JOIN_ERROR`), el envío de contenido multimedia a la fase (`PUBLISH_ERROR`) o la recepción de una transmisión de contenido multimedia entrante desde la fase (`SUBSCRIBE_ERROR`).

La propiedad de código de un `StageError` notifica el problema específico:


| Nombre | Código | Acción recomendada | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | Cree un token válido y vuelva a intentar crear instancias para la fase. | 
| TOKEN\$1EXPIRED | 2 | Cree un token no vencido y vuelva a intentar crear instancias para la fase. | 
| TIMEOUT | 3 | La operación ha agotado el tiempo de espera. Si la fase existe y el token es válido, es probable que este error se deba a un problema de red. En ese caso, espere a que se recupere la conectividad del dispositivo. | 
| ERROR | 4 | Se produjo una condición grave al intentar completar una operación. Compruebe los detalles del error. Si la fase existe y el token es válido, es probable que este error se deba a un problema de red. En ese caso, espere a que se recupere la conectividad del dispositivo. Para la mayoría de las fallas relacionadas con la estabilidad de la red, el SDK reintentará internamente durante un período de hasta 30 segundos antes de emitir un error de tipo FAILED.  | 
| CANCELADO | 5 | Compruebe el código de la aplicación y asegúrese de que no haya invocaciones de `join`, `refreshStrategy` o `replaceStrategy` repetidas, ya que puede provocar que las operaciones repetidas se inicien y cancelen antes de completarse. | 
| STAGE\$1AT\$1CAPACITY | 6 | Este error indica que la etapa o su cuenta ha alcanzado la capacidad máxima. Si la etapa ha alcanzado su límite de participantes, intente la operación nuevamente cuando haya disponibilidad y actualice la estrategia de reintento si es necesario. Si su cuenta ha alcanzado su cuota de suscripciones simultáneas o de publicadores simultáneos, reduzca el uso o solicite un aumento de cuota a través de la [consola de AWS Service Quotas](https://console.aws.amazon.com/servicequotas/).  | 
| CODEC\$1MISMATCH | 7 | La fase no admite el códec. Compruebe si el navegador y la plataforma son compatibles con el códec. Para la transmisión en tiempo real de IVS, los navegadores deben admitir el códec H.264 para video y el códec Opus para audio. | 
| TOKEN\$1NOT\$1ALLOWED | 8 | El token no tiene permiso para la operación. Vuelva a crear el token con los permisos correctos e inténtelo de nuevo. | 
| STAGE\$1DELETED | 9 | Ninguno. Este error se produce al intentar unirse a una etapa que ha sido eliminada. | 
| PARTICIPANT\$1DISCONNECTED | 10 | Ninguno. Este error se produce al intentar unirse con el token de un participante que se ha desconectado. | 

### Ejemplo de gestión de StageError
<a name="web-error-handling-stage-errors-example"></a>

Use el código StageError para determinar si el error se debe a un token vencido:

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    if (error.code === StageError.TOKEN_EXPIRED) {
        // recreate the token and stage instance and re-join
    }
});
```

### Errores de red cuando ya está conectado
<a name="web-error-handling-stage-errors-network"></a>

Si se interrumpe la conexión de red del dispositivo, es posible que el SDK pierda la conexión con los servidores de fases. Es posible que observe errores en la consola porque el SDK ya no puede acceder a los servicios de backend. Las publicaciones en https://broadcast.stats.live-video.net fallarán.

Si está publicando o suscribiéndose, observará errores en la consola relacionados con los intentos de publicar/suscribirte.

Internamente, el SDK intentará reconectarse con una estrategia de retroceso exponencial.

**Acción**: espere a que se recupere la conectividad del dispositivo.

## Estados de error
<a name="web-error-handling-errored-states"></a>

Le recomendamos que utilice estos estados para el registro de las aplicaciones y para mostrar mensajes a los usuarios que les avisen de problemas de conectividad con la fase para un participante concreto.

### Publicación
<a name="errored-states-publish"></a>

El SDK informa `ERRORED` cuando se produce un error en una publicación.

```
stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantPublishState.ERRORED) {
      // Log and/or display message to user
  }
});
```

### Suscribirse
<a name="errored-states-subscribe"></a>

El SDK informa `ERRORED` cuando se produce un error en la suscripción. Esto puede ocurrir debido a las condiciones de la red o si una etapa está llena para los suscriptores.

```
stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantSubscribeState.ERRORED) {
    // Log and/or display message to user
  }
});
```