

# SDK de Transmissão do IVS: Guia para a Web \$1 Streaming em tempo Real
<a name="broadcast-web"></a>

O SDK de Transmissão do streaming em tempo real do IVS para Web fornece aos desenvolvedores as ferramentas necessárias para criar experiências interativas e em tempo real na Web. Esse SDK destina-se a desenvolvedores que estão criando aplicações para a Web com o Amazon IVS.

O SDK de Transmissão da Web possibilita que os participantes enviem e recebam vídeos. O SDK oferece suporte para as seguintes operações:
+ Entrar em um palco
+ Publicar mídia para outros participantes do palco
+ Inscrever-se na mídia de outros participantes do palco
+ Gerenciar e monitorar vídeos e áudios publicados no palco
+ Obter estatísticas WebRTC para cada conexão de pares
+ Todas as operações do SDK de Transmissão do streaming de baixa latência do IVS para Web

**Versão mais recente do SDK de transmissão para a Web:** 1.33.0 ([Notas de release](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-web-rt)) 

**Documentação de referência:** para obter informações sobre os métodos mais importantes disponíveis no SDK de Transmissão do Amazon IVS para a Web, consulte [https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Verifique se a versão mais atual do SDK está selecionada.

**Código de exemplo**: os exemplos abaixo são um bom lugar para aprender rapidamente a usar o SDK:
+ [Reprodução simples](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [Publicação e inscrição simples](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [Demonstração abrangente de colaboração em tempo real do React](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**Requisitos de plataforma**: consulte [SDK de Transmissão do Amazon IVS](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html) para obter uma lista das plataformas compatíveis.

**Observação:** publicar de um navegador é conveniente para os usuários finais, pois não requer a instalação de software adicional. No entanto, a publicação baseada em navegador está sujeita às restrições e à variabilidade desse ambiente. Caso você precise priorizar a estabilidade (por exemplo, para streaming de eventos), geralmente recomendamos publicar de fontes que não sejam o navegador (por exemplo, OBS Studio ou outros codificadores dedicados), que costumam ter acesso direto aos recursos do sistema e evitam limitações do navegador. Para saber mais sobre as opções de publicação fora do navegador, consulte a documentação do [Stream Ingest](rt-stream-ingest.md).

# Introdução ao SDK de Transmissão na Web do IVS \$1 Streaming em tempo real
<a name="broadcast-web-getting-started"></a>

Este documento descreve as etapas envolvidas ao começar a usar o SDK de Transmissão na Web para streaming em tempo real do IVS.

## Importações
<a name="broadcast-web-getting-started-imports"></a>

Os blocos de criação para tempo real estão localizados em um namespace diferente dos módulos de transmissão raiz.

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

O SDK de Transmissão da Web é distribuído como uma biblioteca de JavaScript e pode ser recuperado em [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).

As classes e as enumerações definidas nos exemplos abaixo podem ser encontradas no objeto global `IVSBroadcastClient`:

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

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

Para instalar o pacote `npm` 

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

As classes, as enumerações e os tipos também podem ser importados do módulo do pacote:

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

### Suporte para renderização do servidor
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

A biblioteca dos palcos do SDK de Transmissão para a Web não pode ser carregada em um contexto do servidor, pois faz referência às primitivas do navegador necessárias para o funcionamento da biblioteca quando carregada. Para contornar isso, carregue a biblioteca dinamicamente, conforme demonstrado na [Demonstração de transmissão da Web usando Next e React](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31).

## Solicitar permissões
<a name="broadcast-web-request-permissions"></a>

Sua aplicação deverá solicitar permissão para acessar a câmera e o microfone do usuário, e isso deverá ser servido por meio de HTTPS. (Isso não é específico do Amazon IVS; é necessário para qualquer site que precise acessar câmeras e microfones.)

Aqui está um exemplo de função que mostra como é possível solicitar e capturar permissões para ambos os dispositivos de áudio e vídeo:

```
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 obter informações adicionais, consulte a [API de permissões](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) e [MediaDevices.getUserMedia()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).

## Listar dispositivos disponíveis
<a name="broadcast-web-request-list-devices"></a>

Para ver quais dispositivos estão disponíveis para captura, consulte o método [MediaDevices.enumerateDevices()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) do navegador:

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

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

Depois de adquirir a lista de dispositivos disponíveis, é possível recuperar um stream de qualquer número de dispositivos. Por exemplo, é possível usar o método `getUserMedia()` para recuperar um stream de uma câmera.

Se você quiser especificar de qual dispositivo capturar o stream, é possível definir explicitamente o `deviceId` na seção `audio` ou `video` das restrições de mídia. Como alternativa, é possível omitir o `deviceId` e fazer com que os usuários selecionem seus dispositivos no prompt do navegador.

Também é possível especificar uma resolução de câmera ideal usando as restrições `width` e `height`. (Leia mais sobre essas restrições [aqui](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks).) O SDK aplica automaticamente restrições de largura e altura que correspondem à resolução máxima de transmissão, mas é melhor você mesmo também aplicá-las para garantir que a proporção da fonte não seja alterada depois que ela for adicionada ao SDK.

Para streaming em tempo real, certifique-se de que a mídia esteja restrita à resolução de 720p. Especificamente, seus valores de restrição `getUserMedia` e `getDisplayMedia` para largura e altura não devem exceder 921600 (1280\$1720) quando multiplicados juntos. 

```
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 },
});
```

# Publicação e assinatura com o SDK de Transmissão na Web do IVS \$1 Streaming em tempo real
<a name="web-publish-subscribe"></a>

Este documento descreve as etapas envolvidas na publicação e assinatura de um estágio usando o SDK de Transmissão na Web para streaming em tempo real do IVS.

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

Existem três conceitos principais que fundamentam a funcionalidade em tempo real: [palco](#web-publish-subscribe-concepts-stage), [estratégia](#web-publish-subscribe-concepts-strategy) e [eventos](#web-publish-subscribe-concepts-events). O objetivo do projeto é minimizar a quantidade de lógica do lado do cliente que é necessária para desenvolver um produto funcional.

### Estágio
<a name="web-publish-subscribe-concepts-stage"></a>

A classe `Stage` corresponde ao principal ponto de interação entre a aplicação de host e o SDK. Ela representa o próprio palco e é usada para entrar e sair do palco. Criar e entrar em um palco requer uma string de token válida e não expirada do ambiente de gerenciamento (representada como `token`). Entrar e sair de um palco é simples:

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

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

stage.leave();
```

### Estratégia
<a name="web-publish-subscribe-concepts-strategy"></a>

A interface `StageStrategy` fornece uma maneira para a aplicação de host comunicar o estado desejado do palco ao SDK. Três funções precisam ser implementadas: `shouldSubscribeToParticipant`, `shouldPublishParticipant` e `stageStreamsToPublish`. Todas serão discutidas abaixo.

Para usar uma estratégia definida, passe-a para o `Stage` de criação. Veja a seguir um exemplo completo de uma aplicação que usa uma estratégia para publicar a webcam de um participante no palco e realizar a inscrição para todos os participantes. A finalidade de cada função de estratégia necessária é explicada em detalhes nas seções subsequentes.

```
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();
```

#### Como se inscrever como participante
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

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

Quando um participante remoto entra no palco, o SDK consulta a aplicação de host sobre o estado de inscrição desejado para esse participante. As opções são `NONE`, `AUDIO_ONLY` e `AUDIO_VIDEO`. Ao retornar um valor para essa função, a aplicação de host não precisa se preocupar com o estado de publicação, o estado atual da inscrição ou o estado da conexão do palco. Se `AUDIO_VIDEO` for retornado, o SDK aguardará até que o participante remoto esteja publicando antes de inscrever e atualizará a aplicação de host ao emitir eventos durante todo o processo.

Veja a seguir uma amostra de implementação:

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

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

Esta é a implementação completa desta função para uma aplicação de host que sempre deseja que todos os participantes se vejam, por exemplo, uma aplicação de bate-papo por vídeo.

Implementações mais avançadas também são possíveis. Por exemplo, suponha que o aplicativo forneça um atributo `role` ao criar o token com CreateParticipantToken. A aplicação pode usar a propriedade `attributes` em `StageParticipantInfo` para se inscrever, de forma seletiva, como participante com base nos recursos fornecidos pelo 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
}
```

Isso pode ser usado para criar um palco no qual os moderadores podem monitorar todos os convidados sem serem vistos ou ouvidos. A aplicação de host pode usar uma lógica de negócios adicional para permitir que os moderadores se vejam, mas permaneçam invisíveis para os convidados.

#### Configuração da assinatura de participantes
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

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

Se um participante remoto estiver fazendo uma assinatura (consulte [Assinatura de participantes](#web-publish-subscribe-concepts-strategy-participants)), o SDK consultará a aplicação host sobre uma configuração de assinatura personalizada para esse participante. Essa configuração é opcional e permite que a aplicação host controle certos aspectos do comportamento do assinante. Para obter informações sobre o que pode ser configurado, consulte [SubscribeConfiguration](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration) na documentação de referência do SDK.

Veja a seguir uma amostra de implementação:

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

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

Essa implementação atualiza o atraso mínimo do buffer de instabilidade para todos os participantes assinantes para uma predefinição de `MEDIUM`.

Como com `shouldSubscribeToParticipant`, implementações mais avançadas são possíveis. As `ParticipantInfo` fornecidas podem ser usadas para atualizar seletivamente a configuração de assinatura para participantes específicos.

Recomendamos usar os valores padrão. Especifique a configuração personalizada somente se houver um comportamento específico que você queira alterar.

#### Publicação
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

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

Uma vez conectado ao palco, o SDK consulta a aplicação de host para visualizar se um determinado participante deve realizar uma publicação. Isso é invocado somente para participantes locais que têm permissão para realizar publicações com base no token fornecido.

Veja a seguir uma amostra de implementação:

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

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

Isso é para uma aplicação de bate-papo por vídeo padrão na qual os usuários sempre desejam realizar publicações. Eles podem ativar e desativar o áudio e o vídeo para serem ocultados ou vistos/ouvidos instantaneamente. (Também é possível usar publicar/cancelar a publicação, mas isso é muito mais lento. Ativar/Desativar o áudio é preferível para casos de uso em que é desejável alterar a visibilidade com frequência.)

#### Como escolher streams para realizar publicações
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

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

Ao realizar publicações, isso é usado para determinar quais streams de áudio e de vídeo devem ser publicados. Isso será abordado com mais detalhes posteriormente em [Publish a Media Stream](#web-publish-subscribe-publish-stream).

#### Como atualizar a estratégia
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

A estratégia pretende ser dinâmica, ou seja, os valores retornados de qualquer uma das funções acima podem ser alterados a qualquer momento. Por exemplo, se a aplicação de host não desejar realizar publicações até que o usuário final toque em um botão, será possível retornar uma variável de `shouldPublishParticipant` (algo como `hasUserTappedPublishButton`). Quando essa variável for alterada com base em uma interação do usuário final, chame `stage.refreshStrategy()` para sinalizar ao SDK que ele deve consultar a estratégia para obter os valores mais recentes, aplicando somente o que sofreu alterações. Se o SDK observa que o valor `shouldPublishParticipant` foi alterado, ele inicia o processo de publicação. Se as consultas do SDK e todas as funções retornarem o mesmo valor anterior, a chamada `refreshStrategy` não modificará o palco.

Se o valor de retorno de `shouldSubscribeToParticipant` for alterado de `AUDIO_VIDEO` para `AUDIO_ONLY`, a transmissão de vídeo será removida para todos os participantes com os valores retornados alterados, caso uma transmissão de vídeo tenha existido anteriormente.

Geralmente, o palco usa a estratégia para aplicar com mais eficiência a diferença entre as estratégias anteriores e atuais, sem que a aplicação de host precise se preocupar com todo o estado necessário para realizar o gerenciamento adequado. Por causa disso, pense na chamada `stage.refreshStrategy()` como uma operação barata, porque ela não faz nada a menos que a estratégia seja alterada.

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

Uma instância `Stage` é um emissor de eventos. Ao usar `stage.on()`, o estado do palco é comunicado à aplicação de host. Geralmente, as atualizações na interface do usuário da aplicação de host podem ser totalmente apoiadas pelos eventos. Os eventos são os seguintes:

```
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 a maioria desses eventos, o correspondente `ParticipantInfo` é fornecido.

Não é esperado que as informações fornecidas pelos eventos impactem os valores de retorno da estratégia. Por exemplo, não se espera que o valor de retorno de `shouldSubscribeToParticipant` seja alterado quando `STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` for chamado. Se a aplicação de host desejar inscrever um determinado participante, ele deverá retornar o tipo de inscrição desejado, independentemente do estado de publicação desse participante. O SDK é responsável por garantir que o estado desejado da estratégia seja acionado no momento correto com base no estado do palco.

## Publicação de uma transmissão de mídia
<a name="web-publish-subscribe-publish-stream"></a>

Dispositivos locais, como microfones e câmeras, são recuperados usando as mesmas etapas descritas acima em [Recuperar um MediaStream de um dispositivo](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream). No exemplo, usamos `MediaStream` para criar uma lista de objetos `LocalStageStream` usados ​​para publicação pelo SDK:

```
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
    }
}
```

## Publicação de um compartilhamento de tela
<a name="web-publish-subscribe-publish-screenshare"></a>

Geralmente, as aplicações precisam publicar um compartilhamento de tela além da câmera da Web do usuário. A publicação de um compartilhamento de tela exige a criação de um token adicional para o palco, especificamente para a publicação da mídia do compartilhamento de tela. Use `getDisplayMedia` e restrinja a resolução a um máximo de 720p. Depois disso, as etapas são semelhantes à publicação de uma câmera no palco.

```
// 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();
```

## Exibição e remoção de participantes
<a name="web-publish-subscribe-participants"></a>

Após a conclusão da inscrição, você recebe uma matriz de objetos `StageStream` por meio do evento `STAGE_PARTICIPANT_STREAMS_ADDED`. O evento também fornece informações do participante para ajudar na exibição de transmissões de mídia:

```
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));
})
```

Quando um participante interrompe as publicações ou cancela a inscrição de uma transmissão, a função `STAGE_PARTICIPANT_STREAMS_REMOVED` é chamada com as transmissões que foram removidas. As aplicações de host devem usar isso como um sinal para remover a transmissão de vídeo do participante do DOM.

`STAGE_PARTICIPANT_STREAMS_REMOVED` é invocada para todos os cenários em que uma transmissão pode ser removida, incluindo:
+ Um participante remoto que interrompe as publicações.
+ Um dispositivo local que cancela a inscrição ou altera a inscrição de `AUDIO_VIDEO` para `AUDIO_ONLY`.
+ Um participante remoto que sai do palco.
+ Um participante local que sai do palco.

Como `STAGE_PARTICIPANT_STREAMS_REMOVED` é invocada para todos os cenários, nenhuma lógica de negócios personalizada é necessária para remover participantes da IU durante operações de saída remotas ou locais.

## Ativação ou desativação do áudio para transmissões de mídia
<a name="web-publish-subscribe-mute-streams"></a>

Os objetos `LocalStageStream` têm uma função `setMuted` que controla se a transmissão é silenciada. Essa função pode ser chamada na transmissão antes ou depois de ser retornada da função de estratégia `stageStreamsToPublish`.

**Importante**: se uma nova instância de objeto `LocalStageStream` for retornada por `stageStreamsToPublish` após uma chamada para `refreshStrategy`, o estado mudo do novo objeto de transmissão será aplicado ao palco. Tenha cuidado ao criar novas instâncias `LocalStageStream` para garantir que o estado mudo esperado seja mantido.

## Monitoramento do estado mudo da mídia do participante remoto
<a name="web-publish-subscribe-mute-state"></a>

Quando os participantes alteram o estado mudo do vídeo ou do áudio, o evento `STAGE_STREAM_MUTE_CHANGED` é acionado com uma lista de transmissões que foram alteradas. Use a propriedade `isMuted` na `StageStream` para atualizar a IU adequadamente:

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

Além disso, você pode consultar [StageParticipantInfo](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo) para saber se o áudio ou o vídeo estão silenciados:

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

## Obtenção de estatísticas WebRTC
<a name="web-publish-subscribe-webrtc-stats"></a>

O método `requestQualityStats()` fornece acesso a estatísticas detalhadas do WebRTC para fluxos locais e remotos. Isso está disponível nos objetos LocalStageStream e RemoteStageStream. Ele retorna métricas de qualidade abrangentes, incluindo qualidade de rede, estatísticas de pacotes, informações de taxa de bits e métricas relacionadas a quadros.

Este é um método assíncrono com o qual estatísticas podem ser recuperadas utilizando await ou encadeando uma promessa. Ele retorna `undefined` quando as estatísticas não estão disponíveis; por exemplo, o fluxo não está ativo ou as estatísticas internas não estão disponíveis. Se as estatísticas estiverem disponíveis, e dependendo da transmissão (remota ou local, vídeo ou áudio), o método retornará um 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) ou [RemoteAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteAudioStats).

Observe que, para transmissões de vídeo com transmissão simultânea, a matriz contém vários objetos estatísticos (um por camada).

**Práticas recomendadas**
+ Frequência de pesquisa: chame `requestQualityStats()` em intervalos razoáveis (1 a 5 segundos) para evitar impacto no desempenho
+ Tratamento de erros: sempre verifique se o valor retornado é `undefined` antes do processamento
+ Gerenciamento de memória: intervalos e tempos limite claros quando os fluxos não são mais necessários
+ Qualidade da rede: use `networkQuality` para feedback do usuário sobre possíveis degradações causadas pela rede. Para obter detalhes, consulte [NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality).

**Exemplo 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);
```

## Otimização de mídia
<a name="web-publish-subscribe-optimizing-media"></a>

É recomendável limitar as chamadas `getUserMedia` e `getDisplayMedia` para as seguintes restrições com a finalidade de obter a melhor performance:

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

É possível restringir ainda mais a mídia por meio de opções adicionais passadas para o construtor `LocalStageStream`:

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

No código acima:
+ `minBitrate` define uma taxa de bits mínima que o navegador deve usar. No entanto, um stream de vídeo de baixa complexidade pode impulsionar o codificador a diminuir a taxa de bits.
+ `maxBitrate` define uma taxa de bits máxima que o navegador não deve exceder para este stream.
+ `maxFramerate` define uma taxa de quadros máxima que o navegador não deve exceder para este stream.
+ A opção `simulcast` pode ser usada somente em navegadores baseados no Chromium. Ela possibilita o envio de três camadas de representação do stream.
  + Isso permite que o servidor escolha qual representação enviar aos outros participantes, com base em suas limitações de rede.
  + Quando `simulcast` é especificada junto com um valor `maxBitrate` e/ou `maxFramerate`, espera-se que a camada de representação mais alta seja configurada considerando esses valores, desde que `maxBitrate` não seja inferior ao valor de `maxBitrate` padrão para a segunda camada mais alta do SDK interno de 900 kbps.
  + Se `maxBitrate` for especificada com um valor muito inferior em comparação com o valor padrão da segunda camada mais alta, a `simulcast` será desabilitada.
  + A `simulcast` não pode ser ativada e desativada sem republicar a mídia por meio de uma combinação de `shouldPublishParticipant` retornar `false`, chamar `refreshStrategy`, fazer `shouldPublishParticipant` retornar `true` e chamar `refreshStrategy` novamente.

## Obtenção de atributos do participante
<a name="web-publish-subscribe-participant-attributes"></a>

Se você especificar atributos na solicitação da operação `CreateParticipantToken`, poderá visualizar os atributos nas propriedades `StageParticipantInfo`:

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

## Informações complementares aprimoradas (SEI)
<a name="web-publish-subscribe-sei-attributes"></a>

A unidade NAL de informações de aprimoramento suplementar (SEI) é usada para armazenar metadados alinhados ao quadro ao lado do vídeo. Ele pode ser usado ao publicar e assinar streams de vídeo H.264. Não é garantido que as cargas úteis de SEI cheguem aos assinantes, especialmente em condições de rede pouco satisfatórias. Como a carga útil do SEI armazena dados diretamente na estrutura do quadro H.264, esse recurso não pode ser aproveitado para streams somente de áudio.

### Inserindo cargas úteis de SEI
<a name="sei-attributes-inserting-sei-payloads"></a>

Os clientes de publicação podem inserir cargas úteis de SEI em um stream de preparação que está será publicado, configurando o LocalStageStream de vídeo para habilitar `inBandMessaging` e, posteriormente, invocando o método `insertSeiMessage`. Observe que a habilitação de `inBandMessaging` aumenta o uso de memória do SDK.

As cargas úteis devem ser do tipo [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). A carga útil deve ter mais de 0 KB e menos de 1 KB. O número de mensagens de SEI inseridas não deve exceder 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);
```

#### Repetir cargas úteis de SEI
<a name="sei-attributes-repeating-sei-payloads"></a>

Opcionalmente, forneça um `repeatCount` para repetir a inserção de cargas úteis de SEI nos próximos N quadros enviados. Isso pode ser útil para reduzir a perda inerente que pode ocorrer devido ao protocolo de transporte UDP subjacente usado para enviar vídeo. Esse valor deve ser de 0 a 30. Os clientes destinatários devem ter uma lógica para desduplicar a mensagem.

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

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

Os clientes assinantes podem ler as cargas úteis de SEI de um publicador que esteja publicando vídeo H.264, se presente, configurando o(s) assinante(s) `SubscribeConfiguration` para habilitar `inBandMessaging` e ouvir o evento `StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED`, conforme mostrado no exemplo a seguir:

```
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);
});
```

## Codificação em camadas com transmissão simultânea
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

A codificação em camadas com transmissão simultânea é um atributo de streaming em tempo real do IVS que permite que os publicadores enviem várias camadas de vídeo de qualidade diferentes e que os assinantes alterem essas camadas de forma dinâmica ou manual. O atributo é descrito mais detalhadamente no documento [Otimizações de streaming](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html).

### Configuração da codificação em camadas (Publicador)
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

Como publicador, para habilitar a codificação em camadas com transmissão simultânea, adicione a seguinte configuração à sua `LocalStageStream` na instanciação:

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

Dependendo da resolução de entrada do seu dispositivo de câmera, um determinado número de camadas será codificado e enviado conforme definido na seção [Camadas, qualidades e taxas de quadros padrão](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers) de *Otimizações de streaming*.

Também é possível configurar opcionalmente camadas individuais a partir da configuração do simulcast:

```
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, 
   }
})
```

Como alternativa, é possível criar suas próprias configurações de camada personalizadas para até três camadas. Se você fornecer uma matriz vazia ou não fornecer um valor, serão usados os padrões descritos acima. As camadas são descritas com as seguintes propriedades obrigatórias:
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

Começando com as predefinições, você pode substituir propriedades individuais ou criar uma configuração totalmente nova:

```
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 obter informações sobre valores máximos, limites e erros que podem ser acionados ao configurar camadas individuais, consulte a documentação de referência do SDK.

### Configuração da codificação em camadas (Assinante)
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

Como assinante, você não precisa fazer nada para habilitar a codificação em camadas. Se um publicador estiver enviando camadas de transmissão simultânea, por padrão, o servidor se adapta dinamicamente entre as camadas para escolher a qualidade ideal com base no dispositivo e nas condições da rede do assinante.

Alternativamente, para escolher camadas explícitas que o publicador está enviando, há várias opções, descritas abaixo.

### Opção 1: preferência de qualidade da camada inicial
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

Usando a estratégia `subscribeConfiguration`, é possível escolher qual camada inicial você deseja receber como assinante:

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

Por padrão, os assinantes sempre recebem primeiro a camada de qualidade mais baixa; isso aumenta lentamente até a camada de mais alta qualidade. Isso otimiza o consumo de largura de banda do usuário final e fornece o melhor tempo para vídeo, reduzindo os congelamentos iniciais de vídeo para usuários em redes mais fracas.

Essas opções estão disponíveis para `InitialLayerPreference`:
+ `LOWEST_QUALITY` — O servidor fornece primeiro a camada de vídeo de menor qualidade. Isso otimiza o consumo de largura de banda, bem como o tempo até a mídia. A qualidade é definida como a combinação de tamanho, taxa de bits e taxa de quadros do vídeo. Por exemplo, o vídeo 720p tem qualidade inferior ao vídeo 1080p.
+ `HIGHEST_QUALITY` — O servidor fornece primeiro a camada de vídeo de mais alta qualidade. Isso otimiza a qualidade, mas pode aumentar o tempo até a mídia. A qualidade é definida como a combinação de tamanho, taxa de bits e taxa de quadros do vídeo. Por exemplo, o vídeo 1080p tem qualidade superior ao vídeo 720p.

**Observação:** para que as preferências iniciais da camada (a chamada `initialLayerPreference`) entrem em vigor, é necessária uma nova assinatura, pois essas atualizações não se aplicam à assinatura ativa.



### Opção 2: Camada preferida para fluxo
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

Depois que um fluxo for iniciado, você poderá usar o método de estratégia `preferredLayerForStream `. Esse método de estratégia expõe o participante e as informações da transmissão.

O método de estratégia pode ser retornado com o seguinte:
+ O objeto de camada diretamente, com base no que `RemoteStageStream.getLayers` retorna 
+ A string do rótulo do objeto de camada, com base em `StageStreamLayer.label`
+ Undefined ou null, o que indica que nenhuma camada deve ser selecionada e que a adaptação dinâmica é preferida

Por exemplo, a estratégia a seguir sempre fará com que os usuários selecionem a camada de vídeo de menor qualidade disponível:

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

Para redefinir a seleção de camadas e retornar à adaptação dinâmica, retorne null ou undefined na estratégia. Neste exemplo, `appState` é uma variável fictícia que representa o possível estado da aplicação.

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

### Opção 3: auxiliares da camada RemoteStageStream
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream` tem vários auxiliares que podem ser usados para tomar decisões sobre a seleção de camadas e exibir as seleções correspondentes aos usuários finais:
+ **Eventos de camada** — Além de `StageEvents`, o próprio objeto `RemoteStageStream` tem eventos que comunicam as mudanças de adaptação de camada e transmissão simultânea:
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **Métodos de camada** — `RemoteStageStream` tem vários métodos auxiliares que podem ser usados para obter informações sobre o fluxo e as camadas que estão sendo apresentadas. Esses métodos estão disponíveis no fluxo remoto fornecido na estratégia `preferredLayerForStream `, bem como nos fluxos remotos expostos via `StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

Para obter detalhes, consulte a classe `RemoteStageStream` na [documentação de referência do SDK](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Pelo motivo `LAYER_SELECTED`, se `UNAVAILABLE` for retornado, isso indica que não foi possível selecionar a camada solicitada. Em vez disso, a melhor seleção é feita, que normalmente é uma camada de qualidade inferior para manter a estabilidade do fluxo.

## Tratamento de problemas de rede
<a name="web-publish-subscribe-network-issues"></a>

Quando a conexão de rede do dispositivo local é perdida, o SDK tenta se reconectar internamente sem nenhuma ação do usuário. Em alguns casos, o SDK não obtém êxito e a ação do usuário é necessária.

De maneira geral, o estado do palco pode ser tratado por meio do 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;
    }
})
```

Em geral, você pode ignorar um estado de erro encontrado após ingressar com êxito em um palco, pois o SDK tentará se recuperar internamente. Se o SDK reportar um estado de `ERRORED` e o estágio permanecer no estado `CONNECTING` por um longo período de tempo (por exemplo, 30 segundos ou mais), você provavelmente está desconectado da rede.

## Transmissão do palco para um canal do IVS
<a name="web-publish-subscribe-broadcast-stage"></a>

Para transmitir um palco, crie uma sessão `IVSBroadcastClient` separada e, em seguida, siga as instruções usuais para transmissão com o SDK, descritas acima. A lista de `StageStream` expostas por meio de `STAGE_PARTICIPANT_STREAMS_ADDED` pode ser usada para recuperar as transmissões de mídia participantes que podem ser aplicadas à composição do fluxo de transmissão da seguinte forma:

```
// 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;
        }
    })
})
```

Você também pode compor um palco e transmiti-lo para um canal de baixa latência do IVS para alcançar um público maior. Consulte [Enabling Multiple Hosts on an Amazon IVS Stream](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html) no Guia do usuário do streaming de baixa latência do IVS.

# Problemas conhecidos e soluções alternativas no SDK de Transmissão na Web do IVS \$1 Streaming em tempo real
<a name="broadcast-web-known-issues"></a>

Este documento lista problemas conhecidos que podem ser encontrados ao usar o SDK de Transmissão na Web para streaming em tempo real do Amazon IVS e sugere possíveis soluções alternativas.
+ Ao fechar as guias do navegador ou sair dos navegadores sem chamar `stage.leave()`, os usuários ainda podem aparecer na sessão com um quadro congelado ou tela preta por até dez segundos.

  **Solução alternativa:** nenhuma.
+ As sessões do Safari aparecem intermitentemente com uma tela preta para os usuários que entram após o início de uma sessão.

  **Solução alternativa:** atualize o navegador e reconecte a sessão.
+ O Safari não se recupera normalmente da troca de redes.

  **Solução alternativa:** atualize o navegador e reconecte a sessão.
+ O console do desenvolvedor repete um erro `Error: UnintentionalError at StageSocket.onClose`.

  **Solução alternativa:** somente um palco pode ser criado por token de participante. Esse erro ocorre quando mais de uma instância `Stage` é criada com o mesmo token de participante, independentemente de a instância estar em um dispositivo ou em vários dispositivos.
+ Você pode ter problemas para manter um estado `StageParticipantPublishState.PUBLISHED` e pode receber estados `StageParticipantPublishState.ATTEMPTING_PUBLISH` repetidos ao receber o evento `StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED`.

  **Solução alternativa:** restrinja a resolução do vídeo a 720p ao invocar `getUserMedia` ou `getDisplayMedia`. Especificamente, seus valores de restrição `getUserMedia` e `getDisplayMedia` para largura e altura não devem exceder 921600 (1280\$1720) quando multiplicados juntos.
+ Quando `stage.leave()` é invocado ou um participante remoto sai, um erro 404 DELETE aparece no console de depuração do navegador.

  **Solução alternativa:** nenhuma. Esse é um erro inofensivo.

## Limitações do Safari
<a name="broadcast-web-safari-limitations"></a>
+ Para negar um prompt de permissões, é necessário redefinir a permissão nas configurações do site do Safari no nível do sistema operacional.
+ O Safari não detecta nativamente todos os dispositivos com a mesma eficácia que o Firefox ou o Chrome. Por exemplo, a câmera virtual OBS não é detectada.

## Limitações do Firefox
<a name="broadcast-web-firefox-limitations"></a>
+ As permissões do sistema precisam estar habilitadas para que o Firefox compartilhe a tela. Depois de habilitar, o usuário deverá reiniciar o Firefox para que ele funcione corretamente; caso contrário, se as permissões forem percebidas como bloqueadas, o navegador emitirá uma exceção [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions).
+ O método `getCapabilities` está ausente. Isso significa que os usuários não conseguem obter a resolução ou a proporção da faixa de mídia. Veja este [tópico do bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084).
+ Várias propriedades `AudioContext` estão ausentes; por exemplo, latência e contagem de canais. Isso pode representar um problema para usuários avançados que desejem manipular as faixas de áudio.
+ Os feeds de câmera de `getUserMedia` são restritos a uma proporção de 4:3 no macOS. Veja o [tópico 1 do bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640) e o [tópico 2 do bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034).
+ Não há suporte para a captura de áudio com `getDisplayMedia`. Veja este [tópico do bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425).
+ A taxa de quadros na captura de tela está abaixo do ideal (aproximadamente a 15 fps?). Veja este [tópico do bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522).

## Limitações da Web móvel
<a name="broadcast-web-mobile-web-limitations"></a>
+ O compartilhamento de tela [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility) não é suportado em dispositivos móveis.

  **Solução alternativa:** nenhuma.
+ O participante leva de 15 a 30 segundos para sair ao fechar um navegador sem chamar `leave()`.

  **Solução alternativa**: adicione uma interface de usuário que incentive os usuários a se desconectarem adequadamente.
+ A aplicação em segundo plano faz com que a publicação do vídeo pare.

  **Solução alternativa**: exiba uma lista de interface do usuário quando o publicador estiver pausado.
+ A taxa de quadros do vídeo cai por aproximadamente 5 segundos após ativar o som de uma câmera em dispositivos Android.

  **Solução alternativa:** nenhuma.
+ O feed de vídeo fica esticado em rotação para o iOS 16.0.

  **Solução alternativa**: exiba uma interface de usuário descrevendo esse problema conhecido do sistema operacional.
+ A troca do dispositivo de entrada de áudio alterna automaticamente o dispositivo de saída de áudio.

  **Solução alternativa:** nenhuma.
+ Colocar o navegador em segundo plano faz com que o stream de publicação fique preto e produza somente áudio.

  **Solução alternativa:** nenhuma. Isso é por motivos de segurança.

# Tratamento de erros no SDK de Transmissão na Web do IVS \$1 Streaming em tempo real
<a name="broadcast-web-error-handling"></a>

Esta seção é uma visão geral das condições de erros, como o SDK de Transmissão para a Web os relata à aplicação e o que uma aplicação deve fazer quando esses erros são encontrados. Os erros são relatados pelo SDK aos receptores do evento `StageEvents.ERROR`:

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

## Erros de palco
<a name="web-error-handling-stage-errors"></a>

Um StageError é relatado quando o SDK encontra um problema do qual não consegue se recuperar e geralmente requer intervenção da aplicação e reconexão de rede para se recuperar.

Cada `StageError` relatado tem um código (ou `StageErrorCode`), uma mensagem (string) e uma categoria (`StageErrorCategory`). Cada um está relacionado a uma categoria de operação subjacente.

A categoria de operação do erro é determinada com base no fato de estar relacionada à conexão com o palco (`JOIN_ERROR`), ao envio de mídia para o palco (`PUBLISH_ERROR`) ou ao recebimento de um stream de mídia de entrada do palco (`SUBSCRIBE_ERROR`).

A propriedade de código de um `StageError` relata o problema específico:


| Nome | Código | Ação recomendada | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | Crie um token válido e tente instanciar o palco novamente. | 
| TOKEN\$1EXPIRED | 2 | Crie um token não expirado e tente instanciar o palco novamente. | 
| TIMEOUT | 3 | A operação expirou. Se o palco existir e o token for válido, essa falha provavelmente é um problema de rede. Nesse caso, aguarde até que a conectividade do dispositivo se recupere. | 
| FAILED | 4 | Uma condição fatal foi encontrada ao tentar uma operação. Verifique os detalhes do erro. Se o palco existir e o token for válido, essa falha provavelmente é um problema de rede. Nesse caso, aguarde até que a conectividade do dispositivo se recupere. Para a maioria das falhas relacionadas à estabilidade da rede, o SDK tentará novamente internamente por um período de até 30 segundos antes de emitir um erro FAILED.  | 
| CANCELED | 5 | Verifique o código da aplicação e certifique-se de que não haja invocações `join`, `refreshStrategy` ou `replaceStrategy` repetidas, que podem fazer com que operações repetidas sejam iniciadas e canceladas antes da conclusão. | 
| STAGE\$1AT\$1CAPACITY | 6 | Esse erro indica que o estágio ou sua conta está na capacidade máxima. Se o estágio atingiu seu limite de participantes, tente a operação novamente quando o estágio não estiver mais na capacidade máxima, atualizando a estratégia. Se sua conta atingiu sua cota de assinaturas ou publicadores simultâneos, reduza o uso ou solicite um aumento de cota por meio do [console de Service Quotas da AWS.](https://console.aws.amazon.com/servicequotas/)  | 
| CODEC\$1MISMATCH | 7 | O codec não é compatível com o palco. Verifique se o navegador e a plataforma são compatíveis com o codec. Para streaming em tempo real do IVS, os navegadores devem ser compatíveis com o codec H.264 para vídeo e o codec Opus para áudio. | 
| TOKEN\$1NOT\$1ALLOWED | 8 | O token não tem permissão para a operação. Recrie o token com as permissões corretas e tente novamente. | 
| STAGE\$1DELETED | 9 | Nenhum; a tentativa de ingressar em um estágio excluído aciona esse erro. | 
| PARTICIPANT\$1DISCONNECTED | 10 | Nenhum; tentar entrar com um token de um participante desconectado aciona esse erro. | 

### Exemplo de tratamento de StageError
<a name="web-error-handling-stage-errors-example"></a>

Use o código StageError para determinar se o erro é devido a um token expirado:

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

### Erros de rede quando já ingressado
<a name="web-error-handling-stage-errors-network"></a>

Se a conexão de rede do dispositivo cair, o SDK poderá perder a conexão com os servidores dos palcos. Você pode ver erros no console porque o SDK não consegue mais acessar serviços de backend. POSTs em https://broadcast.stats.live-video.net falharão.

Se estiver publicando e/ou assinando, você verá erros no console relacionados a tentativas de publicação/assinatura.

Internamente, o SDK tentará se reconectar com uma estratégia de recuo exponencial.

**Ação**: aguarde até que a conectividade do dispositivo se recupere.

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

Recomendamos que você use esses estados para registro em log das aplicações e para exibir mensagens aos usuários que os alertem sobre problemas de conectividade no palco de um determinado participante.

### Publicar
<a name="errored-states-publish"></a>

O SDK relata `ERRORED` quando uma publicação falha.

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

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

O SDK relata `ERRORED` quando uma assinatura falha. Pode ocorrer devido às condições da rede ou quando um estágio está lotado para assinantes.

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