

# SDK di trasmissione IVS: Guida per web I Streaming in tempo reale
<a name="broadcast-web"></a>

L'SDK di trasmissione Web in tempo reale di IVS offre agli sviluppatori gli strumenti per creare esperienze interattive e in tempo reale sul Web. Questo SDK è rivolto agli sviluppatori che creano applicazioni Web con Amazon IVS.

L'SDK per la trasmissione Web consente ai partecipanti di inviare e ricevere video. L'SDK  supporta le seguenti operazioni:
+ Partecipa a uno stage
+ Pubblica contenuti multimediali per gli altri partecipanti allo stage
+ Iscriviti ai contenuti multimediali degli altri partecipanti allo stage
+ Gestisci e monitora video e audio pubblicati sullo stage
+ Ottieni statistiche WebRTC per ogni connessione peer
+ Tutte le operazioni dell'SDK di trasmissione Web in streaming a bassa latenza di IVS

**Ultima versione dell'SDK di trasmissione Web:** 1.33.0 ([Note di rilascio](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-web-rt)) 

**Documentazione di riferimento:** per informazioni sui metodi più importanti disponibili nell'SDK di trasmissione Web di Amazon IVS, consulta la documentazione di riferimento all'indirizzo [https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Assicurati che sia selezionata la versione più recente dell'SDK.

**Codice di esempio**: gli esempi seguenti sono un buon punto di partenza per iniziare a utilizzare rapidamente l'SDK:
+ [Simple Playback](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [Pubblicazione e sottoscrizione semplice](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [Demo completa sulla collaborazione React in tempo reale](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**Requisiti della piattaforma:** consulta [SDK di trasmissione Amazon IVS](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html) per un elenco delle piattaforme supportate

**Nota:** la pubblicazione da un browser è comoda per gli utenti finali perché non richiede l'installazione di software aggiuntivo. Tuttavia, la pubblicazione basata su browser è soggetta ai vincoli e alla variabilità degli ambienti dei browser. Se è necessario dare priorità alla stabilità (ad esempio, per lo streaming di eventi), in genere consigliamo di pubblicare da una fonte diversa dal browser (ad esempio, OBS Studio o altri codificatori dedicati), che spesso hanno accesso diretto alle risorse di sistema ed evitano le limitazioni del browser. Per ulteriori informazioni sulle opzioni di pubblicazione diverse dal browser, consulta la documentazione di [Acquisizione dei flussi](rt-stream-ingest.md).

# Guida introduttiva a SDK di trasmissione Web IVS \$1 Streaming in tempo reale
<a name="broadcast-web-getting-started"></a>

Questo documento illustra i passaggi necessari per iniziare a utilizzare l'SDK di trasmissione IVS per lo streaming Web in tempo reale.

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

Gli elementi costitutivi per il tempo reale si trovano in un namespace diverso da quello dei moduli di trasmissione principali.

### Utilizzo di un tag di script
<a name="broadcast-web-getting-started-imports-script"></a>

L'SDK di trasmissione Web è distribuito come libreria JavaScript e può essere recuperato all'indirizzo [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).

Le classi e le enumerazioni definite negli esempi seguenti sono individuabili sull'oggetto globale `IVSBroadcastClient`:

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

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

Per installare il pacchetto della `npm`: 

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

Le classi, le enumerazioni e i tipi possono essere importati anche dal modulo del pacchetto:

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

### Support per il rendering lato server
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

La libreria delle fasi dell'SDK di trasmissione per web non può essere caricata in un contesto lato server, poiché fa riferimento alle primitive del browser necessarie per il funzionamento della libreria quando viene caricata. Per ovviare a questo problema, carica la libreria dinamicamente, come mostrato nella demo di [Trasmissione sul web utilizzando Next e React](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31).

## Richiedere autorizzazioni
<a name="broadcast-web-request-permissions"></a>

L'app deve richiedere l'autorizzazione per accedere alla fotocamera e al microfono dell'utente e tale autorizzazione deve utilizzare HTTPS. (Questo non riguarda solo Amazon IVS, ma qualsiasi sito Web che abbia bisogno di accedere alle fotocamere e ai microfoni.)

Ecco un esempio di funzione che mostra come richiedere e ottenere le autorizzazioni per dispositivi audio e 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.');
   }
}
```

Per ulteriori informazioni, consulta l'[API delle autorizzazioni](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).

## Elenco dei dispositivi disponibili
<a name="broadcast-web-request-list-devices"></a>

Per vedere quali dispositivi sono disponibili per l'acquisizione, interroga il metodo [MediaDevices.enumerateDevices()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) del browser:

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

## Recupero di un MediaStream da un dispositivo
<a name="broadcast-web-retrieve-mediastream"></a>

Dopo aver acquisito l'elenco dei dispositivi disponibili, puoi recuperare un flusso da qualsiasi numero di dispositivi. Ad esempio, puoi utilizzare il metodo `getUserMedia()` per recuperare un flusso da una videocamera.

Se desideri specificare da quale dispositivo catturare lo streaming, puoi impostare esplicitamente il `deviceId` nella sezione `audio` o `video` dei vincoli del supporto. In alternativa, puoi omettere `deviceId` e fare in modo che gli utenti selezionino i propri dispositivi dal prompt del browser.

È inoltre possibile specificare una risoluzione ideale della fotocamera utilizzando i vincoli `width` e `height`. (Ulteriori informazioni su questi vincoli sono disponibili [qui](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks).) L'SDK applica automaticamente i limiti di larghezza e altezza che corrispondono alla risoluzione massima di trasmissione; tuttavia, è una buona idea applicarli anche tu stesso in modo da essere certi che le proporzioni dell'aspetto della sorgente non vengano modificate dopo aver aggiunto la sorgente all'SDK.

Per lo streaming in tempo reale, assicurati che i contenuti multimediali siano limitati alla risoluzione di 720p. In particolare, i valori dei vincoli `getUserMedia` e `getDisplayMedia` per larghezza e altezza non devono superare 921600 (1280x720) se moltiplicati tra loro. 

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

# Pubblicazione e sottoscrizione con l'SDK di trasmissione Web IVS \$1 Streaming in tempo reale
<a name="web-publish-subscribe"></a>

Questo documento illustra i passaggi necessari per pubblicare e sottoscrivere una fase utilizzando l'SDK di trasmissione web IVS per lo streaming in tempo reale.

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

La funzionalità in tempo reale si basa su tre concetti fondamentali: [fase](#web-publish-subscribe-concepts-stage), [strategia](#web-publish-subscribe-concepts-strategy) ed [eventi](#web-publish-subscribe-concepts-events). L'obiettivo di progettazione è ridurre al minimo la quantità di logica lato client necessaria per creare un prodotto funzionante.

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

La classe `Stage` è il principale punto di interazione tra l'applicazione host e l'SDK. Rappresenta lo stage stesso e serve per entrare e uscire dallo stage. La creazione e la partecipazione a uno stage richiedono una stringa di token valida e non scaduta dal piano di controllo (control-plane) (rappresentata come `token`). Entrare e uscire da uno stage è semplice:

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

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

stage.leave();
```

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

L'interfaccia `StageStrategy` consente all'applicazione host di comunicare lo stato desiderato dello stage all'SDK. È necessario implementare tre funzioni: `shouldSubscribeToParticipant`, `shouldPublishParticipant` e `stageStreamsToPublish`. Sono tutte analizzate di seguito.

Per utilizzare una strategia definita, passala al costruttore `Stage`. Quello che segue è un esempio completo di applicazione che utilizza una strategia per pubblicare la webcam di un partecipante sullo stage ed eseguire la sottoscrizione a tutti i partecipanti. Lo scopo di ciascuna funzione strategica necessaria è spiegato in modo dettagliato nelle sezioni seguenti.

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

#### Sottoscrizione ai partecipanti
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

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

Quando un partecipante remoto partecipa allo stage, l'SDK interroga l'applicazione host sullo stato della sottoscrizione desiderato per quel partecipante. Le opzioni sono `NONE`, `AUDIO_ONLY` e `AUDIO_VIDEO`. Quando si restituisce un valore per questa funzione, l'applicazione host non deve preoccuparsi dello stato di pubblicazione, dello stato della sottoscrizione corrente o dello stato della connessione allo stage. Se viene restituito `AUDIO_VIDEO`, l'SDK attende che il partecipante remoto effettui la pubblicazione prima della sottoscrizione e aggiorna l'applicazione host emettendo eventi durante tutto il processo.

Di seguito è riportata un'implementazione di esempio:

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

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

Questa è l'implementazione completa di questa funzione per un'applicazione host che vuole sempre che tutti i partecipanti si vedano tra loro, ad esempio un'applicazione di chat video.

Sono possibili anche implementazioni più avanzate. Ad esempio, supponiamo che l'applicazione fornisca un attributo `role` durante la creazione del token con CreateParticipantToken. L'applicazione può utilizzare la proprietà `attributes` su `StageParticipantInfo` per abbonarsi selettivamente ai partecipanti in base agli attributi forniti dal server:

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

Questa può essere usata per creare uno stage in cui i moderatori possano monitorare tutti gli ospiti senza essere visti o ascoltati. L'applicazione host potrebbe utilizzare una logica aziendale aggiuntiva per consentire ai moderatori di vedersi ma rimanendo invisibili agli ospiti.

#### Configurazione dell'abbonamento ai partecipanti
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

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

Se un partecipante moto viene abbonato (consulta la sezione [Abbonamento ai partecipanti](#web-publish-subscribe-concepts-strategy-participants)), l'SDK interroga l'applicazione host su una configurazione di abbonamento personalizzata per tale partecipante. Questa configurazione è facoltativa e consente all'applicazione host di controllare determinati aspetti del comportamento dell'abbonato. Per informazioni sui valori che è possibile configurare, consulta la sezione [SubscribeConfiguration](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration) nella documentazione di riferimento dell'SDK.

Di seguito è riportata un'implementazione di esempio:

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

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

Questa implementazione aggiorna il ritardo minimo del jitter-buffer per tutti i partecipanti abbonati a un valore predefinito di `MEDIUM`.

Come per `shouldSubscribeToParticipant`, sono possibili anche implementazioni più avanzate. Il valore `ParticipantInfo` dato può essere utilizzato per aggiornare selettivamente la configurazione di abbonamento per partecipanti specifici.

Consigliamo di utilizzare i valori predefiniti. Specifica la configurazione personalizzata solo se desideri modificare un comportamento particolare.

#### Pubblicazione
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

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

Una volta connesso allo stage, l'SDK interroga l'applicazione host per vedere se un dato partecipante deve eseguire una pubblicazione. Viene richiamata solo per i partecipanti locali che hanno il permesso di pubblicare in base al token fornito.

Di seguito è riportata un'implementazione di esempio:

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

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

Si tratta di un'applicazione di chat video standard in cui gli utenti vogliono sempre pubblicare. Possono disattivare e riattivare l'audio e il video per essere nascosti o visti/ascoltati immediatamente. Possono anche usare il comando di pubblicazione/annullamento della pubblicazione, ma è molto più lento. È preferibile disattivare/riattivare l'audio nei casi d'uso in cui è consigliabile modificare spesso la visibilità.

#### Scelta dei flussi da pubblicare
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

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

Durante la pubblicazione, serve a determinare quali flussi audio e video devono essere pubblicati. Questo argomento verrà trattato dettagliatamente più avanti in [Pubblicazione di un flusso multimediale](#web-publish-subscribe-publish-stream).

#### Aggiornamento della strategia
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

La strategia è pensata per essere dinamica: è possibile modificare i valori restituiti da una qualsiasi delle funzioni precedenti in qualsiasi momento. Ad esempio, se l'applicazione host non desidera pubblicare finché l'utente finale non tocca un pulsante, è possibile restituire una variabile da `shouldPublishParticipant` (del tipo `hasUserTappedPublishButton`). Quando quella variabile cambia in base a un'interazione da parte dell'utente finale, chiama `stage.refreshStrategy()` per segnalare all'SDK che dovrebbe eseguire una query sulla strategia per i valori più recenti, applicando solo quanto modificato. Se l'SDK rileva che il valore `shouldPublishParticipant` è cambiato, avvia il processo di pubblicazione. Se le query dell'SDK e tutte le funzioni restituiscono lo stesso valore di prima, la chiamata `refreshStrategy` non modifica lo stage.

Se il valore restituito di `shouldSubscribeToParticipant` cambia da `AUDIO_VIDEO` a `AUDIO_ONLY`, il flusso video viene rimosso per tutti i partecipanti con valori restituiti modificati, se in precedenza esisteva un flusso video.

In genere, lo stage utilizza la strategia per applicare in modo più efficiente la differenza tra le strategie precedenti e quelle attuali, senza che l'applicazione host debba preoccuparsi di tutto lo stato necessario per gestirla correttamente. Per questo motivo, considera la chiamata a `stage.refreshStrategy()` come un'operazione a basso costo, perché non viene eseguita a meno che la strategia non cambi.

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

Un'istanza `Stage` è un emettitore di eventi. Usando `stage.on()`, lo stato dello stage viene comunicato all'applicazione host. Gli aggiornamenti all'interfaccia utente dell'applicazione host in genere possono essere supportati interamente dagli eventi. Gli eventi sono i seguenti:

```
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) => {})
```

Per la maggior parte di questi metodi, viene fornito il `ParticipantInfo` corrispondente.

Non è previsto che le informazioni fornite dagli eventi influiscano sui valori restituiti della strategia. Ad esempio, non è previsto che il valore restituito di `shouldSubscribeToParticipant` cambi quando viene chiamato `STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED`. Se l'applicazione host desidera effettuare la sottoscrizione a un particolare partecipante, deve restituire il tipo di abbonamento desiderato indipendentemente dallo stato di pubblicazione di quel partecipante. L'SDK è responsabile di garantire che lo stato desiderato della strategia venga applicato al momento giusto in base allo stato dello stage.

## Pubblicazione di un flusso multimediale
<a name="web-publish-subscribe-publish-stream"></a>

I dispositivi locali come microfoni e fotocamere vengono recuperati utilizzando gli stessi passaggi descritti sopra in [Recupero di un MediaStream da un dispositivo](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream). Nell'esempio utilizziamo `MediaStream` per creare un elenco di oggetti `LocalStageStream` utilizzati per la pubblicazione dall'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
    }
}
```

## Pubblicazione di una condivisione dello schermo
<a name="web-publish-subscribe-publish-screenshare"></a>

Spesso le applicazioni devono pubblicare una condivisione dello schermo in aggiunta alla webcam dell'utente. La pubblicazione di una condivisione dello schermo richiede la creazione di un token aggiuntivo per la fase, in particolare per la pubblicazione dei contenuti multimediali della condivisione dello schermo. Utilizza `getDisplayMedia` e limita la risoluzione a un massimo di 720p. Dopodiché, i passaggi sono simili a quelli per la pubblicazione di una videocamera sulla 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();
```

## Visualizzazione e rimozione dei partecipanti
<a name="web-publish-subscribe-participants"></a>

Una volta completata la sottoscrizione, riceverai una serie di oggetti `StageStream` tramite l'evento `STAGE_PARTICIPANT_STREAMS_ADDED`. L'evento fornisce anche informazioni sui partecipanti per aiutarti a visualizzare i flussi multimediali:

```
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 un partecipante interrompe la pubblicazione o annulla l'iscrizione a un flusso, la funzione `STAGE_PARTICIPANT_STREAMS_REMOVED` viene chiamata con i flussi che sono stati rimossi. Le applicazioni host devono utilizzarlo come segnale per rimuovere il flusso video del partecipante dal DOM.

`STAGE_PARTICIPANT_STREAMS_REMOVED` viene richiamato per tutti gli scenari in cui un flusso potrebbe essere rimosso, tra cui:
+ Il partecipante remoto interrompe la pubblicazione.
+ Un dispositivo locale annulla l'iscrizione o modifica l'abbonamento da `AUDIO_VIDEO` a `AUDIO_ONLY`.
+ Il partecipante remoto lascia lo stage.
+ Il partecipante locale lascia lo stage.

Poiché `STAGE_PARTICIPANT_STREAMS_REMOVED` viene richiamato per tutti gli scenari, non è richiesta alcuna logica aziendale personalizzata per la rimozione dei partecipanti dall'interfaccia utente durante le operazioni di abbandono remote o locali.

## Disattivazione e riattivazione dell'audio dei flussi multimediali
<a name="web-publish-subscribe-mute-streams"></a>

Gli oggetti `LocalStageStream` hanno una funzione `setMuted` che controlla se l'audio del flusso è disattivato. Questa funzione può essere richiamata sul flusso prima o dopo la restituzione dalla funzione della strategia `stageStreamsToPublish`.

**Importante**: se una nuova istanza di oggetto `LocalStageStream` viene restituita da `stageStreamsToPublish` dopo una chiamata a `refreshStrategy`, lo stato di silenziamento del nuovo oggetto di flusso viene applicato allo stage. Fai attenzione quando crei nuove istanze `LocalStageStream` per assicurarti che lo stato di silenziamento previsto venga mantenuto.

## Monitoraggio dello stato di silenziamento dei contenuti multimediali dei partecipanti remoti
<a name="web-publish-subscribe-mute-state"></a>

Quando i partecipanti modificano lo stato di silenziamento del video o dell'audio, l'evento `STAGE_STREAM_MUTE_CHANGED` viene attivato con un elenco di flussi che sono stati modificati. Usa la proprietà `isMuted` su `StageStream` per aggiornare l'interfaccia utente di conseguenza:

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

Inoltre, puoi consultare [StageParticipantInfo](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo) per informazioni sullo stato dell'eventuale disattivazione dell'audio o del video:

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

## Ottenimento delle statistiche WebRTC
<a name="web-publish-subscribe-webrtc-stats"></a>

Il metodo `requestQualityStats()` fornisce l'accesso a statistiche WebRTC dettagliate per gli stream locali e remoti. È disponibile su entrambi gli oggetti LocalStageStream e RemoteStageStream. Restituisce parametri di qualità completi, tra cui la qualità della rete, le statistiche sui pacchetti, le informazioni sul bitrate e i parametri relativi ai frame.

Si tratta di un metodo asincrono con il quale è possibile recuperare le statistiche tramite attesa o concatenando una promessa. Restituisce `undefined` quando le statistiche non sono disponibili, ad esempio, quando lo stream non è attivo o le statistiche interne non sono disponibili. Se le statistiche sono disponibili e a seconda dello stream (remoto o locale, video o audio), il metodo restituisce un oggetto [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).

Notare che per i flussi video con simulcast, l'array contiene più oggetti stat (uno per livello).

**Best practice**
+ Frequenza di polling: chiamare `requestQualityStats()` a intervalli ragionevoli (1-5 secondi) per evitare un impatto sulle prestazioni
+ Gestione degli errori: controllare sempre se il valore restituito è `undefined` prima dell'elaborazione
+ Gestione della memoria: cancellare intervalli/timeout quando gli stream non sono più necessari
+ Qualità della rete: utilizzare `networkQuality` per il feedback degli utenti sui possibili danni causati dalla rete. Per i dettagli, consulta [NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality).

**Esempio di utilizzo**

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

## Ottimizzazione dei contenuti multimediali
<a name="web-publish-subscribe-optimizing-media"></a>

Si consiglia di limitare le chiamate `getUserMedia` e `getDisplayMedia` secondo i seguenti vincoli per ottenere prestazioni ottimali:

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

È possibile limitare ulteriormente i contenuti multimediali tramite opzioni aggiuntive passate al costruttore `LocalStageStream`:

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

Nel codice qui sopra:
+ `minBitrate` imposta un bitrate minimo che dovrebbe essere utilizzato dal browser. Tuttavia, un flusso video a bassa complessità può spingere il codificatore a scendere al di sotto di questo bitrate.
+ `maxBitrate` imposta un bitrate massimo che il browser non dovrebbe superare per questo flusso.
+ `maxFramerate` imposta una frequenza di rate massima che il browser non dovrebbe superare per questo flusso.
+ L'opzione `simulcast` può essere utilizzata solo sui browser basati su Chromium. Consente l'invio di tre livelli di rendering del flusso.
  + Ciò consente al server di scegliere quale rendering inviare agli altri partecipanti in base alle loro limitazioni di rete.
  + Quando `simulcast` viene specificato insieme a un valore di `maxBitrate` e/o `maxFramerate`, si prevede che il livello di rendering più alto venga configurato tenendo conto di questi valori, a condizione che `maxBitrate` non scenda al di sotto del valore predefinito interno `maxBitrate` del secondo livello più alto dell'SDK di 900 kbps.
  + Se viene specificato un valore troppo basso di `maxBitrate` rispetto al valore predefinito del secondo livello più alto, `simulcast` sarà disabilitato.
  + `simulcast` non può essere attivato e disattivato senza ripubblicare il file multimediale tramite una sequenza in cui `shouldPublishParticipant` restituisce `false`, richiama `refreshStrategy`, `shouldPublishParticipant` restituisce `true` e richiama di nuovo `refreshStrategy`.

## Ottieni gli attributi dei partecipanti
<a name="web-publish-subscribe-participant-attributes"></a>

Se specifichi gli attributi nella richiesta dell'operazione `CreateParticipantToken`, puoi visualizzare gli attributi nelle proprietà `StageParticipantInfo`:

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

## Supplemental Enhancement Information (SEI)
<a name="web-publish-subscribe-sei-attributes"></a>

L'unità NAL Supplemental Enhancement Information (SEI) viene utilizzata per archiviare i metadati allineati al fotogramma insieme al video. È utilizzabile per la pubblicazione e l'abbonamento a flussi video H.264. Non è garantito che i payload SEI arrivino agli abbonati, specialmente in condizioni di rete non ottimali. Poiché il payload SEI memorizza i dati direttamente all'interno della struttura del frame H.264, questa funzionalità non può essere utilizzata per flussi di solo audio.

### Inserimento di payload SEI
<a name="sei-attributes-inserting-sei-payloads"></a>

I client di pubblicazione possono inserire payload SEI in un flusso di fase in corso di pubblicazione configurando il LocalStageStream del proprio video in modo da abilitare `inBandMessaging` e, successivamente, richiamando il metodo `insertSeiMessage`. L'abilitazione di `inBandMessaging` aumenta l'utilizzo della memoria SDK.

I payload devono essere del tipo [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). La dimensione del payload deve essere maggiore di 0 KB e inferiore a 1 KB. Il numero di messaggi SEI inseriti al secondo non deve superare i 10 KB al secondo.

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

#### Ripetizione dei payload SEI
<a name="sei-attributes-repeating-sei-payloads"></a>

È possibile fornire un `repeatCount` per ripetere l'inserimento dei payload SEI per i N frame successivi inviati, il che potrebbe essere utile per mitigare la perdita intrinseca che può verificarsi a causa del protocollo di trasporto UDP sottostante utilizzato per inviare video. Il valore deve essere compreso tra 0 e 30. I client di ricezione devono disporre di una logica per deduplicare il messaggio.

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

### Leggere i payload SEI
<a name="sei-attributes-reading-sei-payloads"></a>

I clienti abbonati possono leggere i payload SEI di un publisher che pubblica video H.264, se presente, configurando l'elemento `SubscribeConfiguration` degli abbonati per attivare `inBandMessaging` e ascoltare l'evento `StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED`, come illustrato nell'esempio seguente:

```
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 a livelli con Simulcast
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

La codifica a livelli con simulcast è una funzionalità di streaming in tempo reale IVS che consente ai publisher di inviare più livelli di qualità video differenti e agli abbonati di modificare dinamicamente o manualmente tali livelli. La funzionalità è descritta più approfonditamente nel documento [Ottimizzazioni dello streaming](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html).

### Configurazione della codifica a livelli (Publisher)
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

Per abilitare la codifica a più livelli con simulcast, il publisher deve aggiungere la seguente configurazione a `LocalStageStream` all'istanziazione:

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

A seconda della risoluzione di input del dispositivo videocamera, verrà codificato e inviato un determinato numero di livelli come definito nella sezione [Livelli, qualità e framerate predefiniti](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers) di *Ottimizzazioni dello streaming*.

Inoltre, puoi facoltativamente configurare singoli livelli dall'interno della configurazione 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, 
   }
})
```

In alternativa, puoi creare configurazioni di livelli personalizzate, fino a un massimo di tre livelli. Se viene fornita una matrice vuota o non viene specificato alcun valore, vengono utilizzate le impostazioni predefinite sopra descritte. I livelli sono descritti con le seguenti proprietà obbligatorie:
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

A partire dai preset, è possibile sovrascrivere le singole proprietà o creare una configurazione completamente nuova:

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

Per i valori massimi, i limiti e gli errori che possono essere attivati durante la configurazione di singoli livelli, consulta la documentazione di riferimento dell'SDK.

### Configurazione della codifica a livelli (Abbonato)
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

L'abbonato non deve eseguire alcuna operazione per abilitare la codifica a livelli. Se un publisher invia layer simulcast, per impostazione predefinita il server si adatta dinamicamente tra i livelli per scegliere la qualità ottimale in base al dispositivo e alle condizioni di rete dell'abbonato.

In alternativa, per scegliere layer espliciti inviati dal publisher, sono disponibili diverse opzioni, descritte di seguito.

### Opzione 1: preferenza di qualità del livello iniziale
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

Usando la strategia `subscribeConfiguration`, è possibile scegliere quale livello iniziale si desidera ricevere come abbonato:

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

Per impostazione predefinita, agli abbonati viene sempre inviato per primo il livello di qualità più bassa; questo livello passa lentamente al livello di qualità più alta. Ciò ottimizza il consumo di larghezza di banda da parte dell'utente finale e offre il tempo ottimale per i video, riducendo i blocchi iniziali del video per gli utenti su reti più deboli.

Queste opzioni sono disponibili per `InitialLayerPreference`:
+ `LOWEST_QUALITY` — Il server fornisce prima il livello video con la qualità più bassa. In questo modo, si ottimizza il consumo di larghezza di banda e il tempo di accesso ai contenuti multimediali. La qualità è definita come combinazione di dimensioni, bitrate e framerate del video. Ad esempio, un video 720p ha una qualità inferiore rispetto a un video 1080p.
+ `HIGHEST_QUALITY` — Il server offre prima il livello video con la qualità più alta. Ciò ottimizza la qualità ma può aumentare il tempo di visualizzazione dei contenuti multimediali. La qualità è definita come combinazione di dimensioni, bitrate e framerate del video. Ad esempio, un video 1080p è di qualità superiore rispetto a un video 720p.

**Nota**: per rendere effettive le preferenze iniziali del livello (la chiamata `initialLayerPreference`), è necessario effettuare un nuovo abbonamento poiché questi aggiornamenti non si applicano all'abbonamento attivo.



### Opzione 2: livello preferito per lo streaming
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

Una volta avviato un flusso, puoi utilizzare il metodo strategico `preferredLayerForStream `. Questo metodo strategico espone il partecipante e le informazioni sul flusso.

Il metodo strategico può essere restituito con quanto segue:
+ L'oggetto del livello direttamente in base a ciò che `RemoteStageStream.getLayers` restituisce 
+ La stringa dell'etichetta dell'oggetto del livello, basata su `StageStreamLayer.label`
+ Non definito o nullo, indicante che non deve essere selezionato alcun livello e che è preferibile l'adattamento dinamico

Ad esempio, la strategia seguente prevede che gli utenti selezionino sempre il livello di video con la qualità più bassa disponibile:

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

Per reimpostare la selezione del livello e tornare all'adattamento dinamico, restituire null o non definito nella strategia. In questo esempio `appState` è una variabile fittizia che rappresenta il possibile stato dell'applicazione.

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

### Opzione 3: helper per livelli RemoteStageStream
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream` dispone di diversi helper che possono essere usati per prendere decisioni sulla selezione dei livelli e visualizzare le selezioni corrispondenti agli utenti finali:
+ **Eventi dei livelli**: oltre a `StageEvents`, l'oggetto `RemoteStageStream` include eventi che comunicano modifiche di adattamento di livelli e simulcast:
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **Metodi dei livelli**: `RemoteStageStream` include diversi metodi helper che possono essere usati per ottenere informazioni sul flusso e sui livelli presentati. Questi metodi sono disponibili sul flusso remoto fornito nella strategia `preferredLayerForStream `, nonché sui flussi remoti esposti tramite `StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

Per i dettagli, consulta la classe `RemoteStageStream` nella [Documentazione di riferimento dell'SDK](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Per il motivo `LAYER_SELECTED`, se viene restituito `UNAVAILABLE`, allora il livello richiesto non può essere selezionato. Per mantenere la stabilità del flusso, al suo posto viene effettuata la migliore selezione, che in genere è un livello di qualità inferiore.

## Gestione dei problemi di rete
<a name="web-publish-subscribe-network-issues"></a>

Quando si perde la connessione di rete del dispositivo locale, l'SDK tenta internamente di riconnettersi senza alcuna azione da parte dell'utente. In alcuni casi, l'SDK non funziona ed è necessaria un'azione da parte dell'utente.

In generale, lo stato dello stage può essere gestito tramite l'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;
    }
})
```

In generale, è possibile ignorare uno stato di errore che si verifica dopo essersi aggiunti correttamente in una fase, poiché l'SDK tenterà di ripristinarlo internamente. Se l'SDK riporta uno stato `ERRORED` e la fase rimane nello stato `CONNECTING` per un periodo di tempo prolungato (ad esempio, 30 secondi o più), probabilmente è avvenuta la disconnessione dalla rete.

## Trasmissione della fase a un canale IVS
<a name="web-publish-subscribe-broadcast-stage"></a>

Per trasmettere uno stage, creare una sessione `IVSBroadcastClient` separata e segui le consuete istruzioni per la trasmissione con l'SDK descritte sopra. L'elenco dei `StageStream` esposti tramite `STAGE_PARTICIPANT_STREAMS_ADDED` può essere utilizzato per recuperare i flussi multimediali dei partecipanti che possono essere applicati alla composizione del flusso di trasmissione, come segue:

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

Facoltativamente, puoi comporre una fase e trasmetterla a un canale IVS a bassa latenza in modo da raggiungere un pubblico più vasto. Consulta [Abilitazione di più host su un flusso Amazon IVS](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html) nella Guida per l'utente dello streaming a bassa latenza di IVS.

# Problemi noti e soluzioni alternative per l'SDK di trasmissione Web IVS \$1 Streaming in tempo reale
<a name="broadcast-web-known-issues"></a>

Questo documento elenca i problemi noti che potresti riscontrare durante l'utilizzo dello Streaming in tempo reale di Amazon IVS per la trasmissione Web e suggerisce possibili soluzioni alternative.
+ Quando si chiudono le schede o si esce dal browser senza chiamare `stage.leave()`, gli utenti possono comunque apparire nella sessione con un frame bloccato o una schermata nera per un massimo di 10 secondi.

  **Soluzione alternativa:** nessuna.
+ Le sessioni di Safari vengono visualizzate in modo intermittente con una schermata nera agli utenti che si iscrivono dopo l'inizio di una sessione.

  **Soluzione alternativa:** aggiorna il browser e ricollega la sessione.
+ Quando si passa da una rete all'altra, il ripristino di Safari non avviene correttamente.

  **Soluzione alternativa:** aggiorna il browser e ricollega la sessione.
+ La console per sviluppatori ripete un errore `Error: UnintentionalError at StageSocket.onClose`.

  **Soluzione alternativa:** è possibile creare un solo stage per token di partecipazione. Questo errore si verifica quando viene creata più di un'istanza `Stage`con lo stesso token di partecipazione, indipendentemente dal fatto che l'istanza si trovi su uno o più dispositivi.
+ Potresti avere problemi a mantenere uno stato `StageParticipantPublishState.PUBLISHED` e potresti ricevere stati `StageParticipantPublishState.ATTEMPTING_PUBLISH` ripetuti durante l'ascolto dell'evento `StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED`.

  **Soluzione alternativa:** limita la risoluzione video a 720p quando invochi `getUserMedia` o `getDisplayMedia`. In particolare, i valori dei vincoli `getUserMedia` e `getDisplayMedia` per larghezza e altezza non devono superare 921600 (1280x720) se moltiplicati tra loro.
+ Quando `stage.leave()` viene richiamato o un partecipante remoto esce, viene visualizzato un errore 404 DELETE nella console di debug del browser.

  **Soluzione alternativa:** nessuna. Si tratta di un errore innocuo.

## Limiti di Safari
<a name="broadcast-web-safari-limitations"></a>
+ Per negare un prompt di autorizzazione è necessario reimpostare l'autorizzazione nelle impostazioni del sito Web di Safari a livello di sistema operativo.
+ Safari non rileva nativamente tutti i dispositivi con la stessa efficacia di Firefox o Chrome. Ad esempio, OBS Virtual Camera non viene rilevata.

## Limitazioni di Firefox
<a name="broadcast-web-firefox-limitations"></a>
+ Per consentire a Firefox di condividere lo schermo devono essere abilitate le autorizzazioni di sistema. Dopo averle abilitate, perché funzioni correttamente Firefox deve essere riavviato altrimenti, se le autorizzazioni vengono percepite come bloccate, il browser genererà un'eccezione [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions).
+ Manca il metodo `getCapabilities`. Ciò significa che gli utenti non possono ottenere la risoluzione o le proporzioni della traccia multimediale. Consulta questo [thread di bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084).
+ Mancano diverse proprietà `AudioContext`, ad esempio latenza e numero di canali. Ciò potrebbe rappresentare un problema per gli utenti esperti che desiderano manipolare le tracce audio.
+ I feed della fotocamera da `getUserMedia` su MacOS sono limitati a un rapporto di aspetto 4:3. Consulta il [thread 1 di bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640) e [thread 2 di bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034).
+ L'acquisizione audio non è supportata con `getDisplayMedia`. Consulta questo [thread di bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425).
+ La frequenza di fotogrammi nell'acquisizione dello schermo non è ottimale (circa 15 fps?). Consulta questo [thread di bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522).

## Limitazioni Web per dispositivi mobili
<a name="broadcast-web-mobile-web-limitations"></a>
+ La condivisione dello schermo [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility) non è supportata sui dispositivi mobili.

  **Soluzione alternativa:** nessuna.
+ Il partecipante impiega 15-30 secondi per uscire quando chiude un browser senza chiamare `leave()`.

  **Soluzione alternativa**: aggiungi un'interfaccia utente che incoraggi gli utenti a disconnettersi correttamente.
+ L'app in backgrounding interrompe la pubblicazione del video.

  **Soluzione alternativa**: visualizza uno stato dell'interfaccia utente quando il publisher è in pausa.
+ La frequenza dei fotogrammi video diminuisce per circa 5 secondi dopo aver riattivato l'audio di una fotocamera su dispositivi Android.

  **Soluzione alternativa:** nessuna.
+ Il feed video viene allungato in fase di rotazione per iOS 16.0.

  **Soluzione alternativa**: visualizza un'interfaccia utente che descrive questo problema noto del sistema operativo.
+ La commutazione del dispositivo di ingresso audio commuta automaticamente il dispositivo di uscita audio.

  **Soluzione alternativa:** nessuna.
+ Lo sfondo del browser fa sì che il flusso di pubblicazione diventi nero e produca solo audio.

  **Soluzione alternativa:** nessuna. Ciò è dovuto a motivi di sicurezza.

# Gestione degli errori nell'SDK di trasmissione Web IVS \$1 Streaming in tempo reale
<a name="broadcast-web-error-handling"></a>

Questa sezione fornisce una panoramica delle condizioni di errore, del modo in cui l'SDK di trasmissione per web le segnala all'applicazione e di cosa dovrebbe fare un'applicazione quando si verificano tali errori. Gli errori vengono segnalati dall'SDK ai listener dell'evento `StageEvents.ERROR`:

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

## Errori di fase
<a name="web-error-handling-stage-errors"></a>

Se l'SDK rileva un problema da cui non può essere ripristinato viene segnalato uno StageError, la cui risoluzione in genere richiede l'intervento dell'app e/o la riconnessione di rete.

Ogni `StageError` segnalato ha un codice (o `StageErrorCode`), un messaggio (stringa) e una categoria (`StageErrorCategory`). Ciascuno è correlato a una categoria operativa sottostante.

La categoria di operazione dell'errore viene determinata in base al fatto che sia correlata alla connessione alla fase (`JOIN_ERROR`), all'invio di file multimediali alla fase (`PUBLISH_ERROR`) o alla ricezione di un flusso multimediale in entrata dalla fase (`SUBSCRIBE_ERROR`).

La proprietà codice di uno `StageError` riporta il problema specifico:


| Name | Codice | Operazione consigliata | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | Crea un token valido e prova a riavviare l'istanza della fase. | 
| TOKEN\$1EXPIRED | 2 | Crea un token non scaduto e prova a riavviare l'istanza della fase. | 
| TIMEOUT | 3 | Timeout dell'operazione. Se la fase esiste e il token è valido, l'errore è probabilmente un problema di rete. In tal caso, attendi il ripristino della connettività del dispositivo. | 
| NON RIUSCITO | 4 | Durante il tentativo di intervento si è verificata una condizione fatale. Verifica i dettagli dell'errore. Se la fase esiste e il token è valido, l'errore è probabilmente un problema di rete. In tal caso, attendi il ripristino della connettività del dispositivo. Per la maggior parte degli errori relativi alla stabilità della rete, l'SDK riproverà internamente per un periodo massimo di 30 secondi prima di emettere un errore FAILED.  | 
| CANCELED (ANNULLATO) | 5 | Controlla il codice dell'applicazione e assicurati che non vi siano invocazioni `join`, `refreshStrategy` o `replaceStrategy` ripetute, che potrebbero causare l'avvio e l'annullamento di operazioni ripetute prima del completamento. | 
| STAGE\$1AT\$1CAPACITY | 6 | Questo errore indica che lo stage o l'account sono al massimo della capacità. Se lo stage ha raggiunto il limite di partecipanti, prova a eseguire nuovamente l'operazione quando lo stage non è più a piena capacità aggiornando la strategia. Se il tuo account ha raggiunto la quota di abbonamenti o publisher simultanei, riduci l'utilizzo o richiedi un aumento della quota tramite la [console AWS Service Quotas.](https://console.aws.amazon.com/servicequotas/)  | 
| CODEC\$1MISMATCH | 7 | Il codec non è supportato dalla fase. Controlla il supporto del codec per il browser e la piattaforma. Per lo streaming in tempo reale IVS, i browser devono supportare il codec H.264 per il video e il codec Opus per l'audio. | 
| TOKEN\$1NOT\$1ALLOWED | 8 | Il token non dispone dell'autorizzazione per l'operazione. Ricrea il token con le autorizzazioni corrette e riprova. | 
| STAGE\$1DELETED | 9 | Nessuno; il tentativo di entrare in uno stage eliminato attiva questo errore. | 
| PARTICIPANT\$1DISCONNESSO | 10 | Nessuno; il tentativo di partecipare con il token di un partecipante disconnesso attiva questo errore. | 

### Esempio di gestione di StageError
<a name="web-error-handling-stage-errors-example"></a>

Utilizza il codice StageError per determinare se l'errore è dovuto a un token scaduto:

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

### Errori di rete quando è già stato effettuato l'accesso
<a name="web-error-handling-stage-errors-network"></a>

Se la connessione di rete del dispositivo si interrompe, l'SDK potrebbe perdere la connessione ai server della fase. È possibile che vengano visualizzati errori nella console perché l'SDK non è più in grado di raggiungere i servizi di backend. I POST su https://broadcast.stats.live-video.net falliranno.

Se stai pubblicando e/o ti stai iscrivendo, vedrai errori nella console relativi ai tentativi di pubblicazione/sottoscrizione.

Internamente, l'SDK proverà a riconnettersi con una strategia di backoff esponenziale.

**Azione**: attendi il ripristino della connettività del dispositivo.

## Stati con errore
<a name="web-error-handling-errored-states"></a>

Ti consigliamo di utilizzare questi stati per la registrazione delle applicazioni e per mostrare agli utenti dei messaggi che li avvisano in merito ai problemi di connettività alla fase per un determinato partecipante.

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

L'SDK segnala `ERRORED` quando una pubblicazione non va a buon fine.

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

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

L'SDK segnala `ERRORED` quando una sottoscrizione fallisce. Ciò può verificarsi a causa delle condizioni della rete o se uno stage ha raggiunto la capacità massima di abbonati.

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