

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

L'SDK di trasmissione per lo streaming in tempo reale IVS per Android consente ai partecipanti di inviare e ricevere video su Android.

Il pacchetto `com.amazonaws.ivs.broadcast` implementa l'interfaccia descritta in questo documento. 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 per lo streaming a bassa latenza di IVS per Android

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

**Documentazione di riferimento:** per informazioni sui metodi più importanti disponibili nell'SDK di trasmissione di Amazon IVS per Android, consulta la documentazione di riferimento all'indirizzo [https://aws.github.io/amazon-ivs-'-docs/1.40.0/android/](https://aws.github.io/amazon-ivs-broadcast-docs/1.40.0/android/).

**Codice di esempio:** vedere il repository di esempio Android su GitHub: [https://github.com/aws-samples/amazon-ivs-real-time-streaming-android-samples](https://github.com/aws-samples/amazon-ivs-real-time-streaming-android-samples).

**Requisiti della piattaforma:** Android 9.0\$1

# Guida introduttiva all'SDK di trasmissione IVS su Android \$1 Streaming in tempo reale
<a name="broadcast-android-getting-started"></a>

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

## Installare la libreria
<a name="broadcast-android-install"></a>

Esistono diversi modi per aggiungere la libreria di trasmissione Amazon IVS per Android al proprio ambiente di sviluppo Android: è possibile utilizzare direttamente Gradle o i cataloghi delle versioni Gradle oppure installare l'SDK manualmente.

**Utilizzo diretto di Gradle**: aggiungi la libreria al file `build.gradle` del modulo, come mostrato qui (per l'ultima versione dell'SDK di trasmissione IVS):

```
repositories {
    mavenCentral()
}
 
dependencies {
     implementation 'com.amazonaws:ivs-broadcast:1.40.0:stages@aar'
}
```

**Utilizzo dei cataloghi delle versioni Gradle**: per prima cosa, includi quanto segue nel file `build.gradle` del modulo:

```
implementation(libs.ivs){
   artifact {
      classifier = "stages"
      type = "aar"
   }
}
```

Quindi includi quanto segue nel file `libs.version.toml` (per l'ultima versione dell'SDK di trasmissione IVS):

```
[versions]
ivs="1.40.0"

[libraries]
ivs = {module = "com.amazonaws:ivs-broadcast", version.ref = "ivs"}
```

**Installazione manuale dell'SDK**: scarica la versione più recente da questo percorso:

[https://search.maven.org/artifact/com.amazonaws/ivs-broadcast](https://search.maven.org/artifact/com.amazonaws/ivs-broadcast)

Assicurati di scaricare `aar` con `-stages` aggiunto.

**Consenti all'SDK di controllare anche il vivavoce**: a prescindere dal metodo di installazione scelto, aggiungi la seguente autorizzazione al tuo manifesto per consentire all'SDK di abilitare e disabilitare il vivavoce:

```
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
```

## Utilizzo dell'SDK con i simboli di debug
<a name="broadcast-android-using-debug-symbols-rt"></a>

Pubblichiamo anche una versione dell'SDK di trasmissione per Android che include i simboli di debug. È possibile utilizzare questa versione per migliorare la qualità dei report di debug (tracce dello stack) in Firebase Crashlytics se si verificano arresti anomali nell'SDK di trasmissione IVS, ad esempio `libbroadcastcore.so`. Quando segnali questi arresti anomali al team dell'SDK di IVS, le tracce dello stack di qualità superiore facilitano la risoluzione dei problemi.

Per utilizzare questa versione dell'SDK, inserisci quanto segue nei tuoi file di build di Gradle:

```
implementation "com.amazonaws:ivs-broadcast:$version:stages-unstripped@aar"
```

Utilizza la riga precedente invece di questa:

```
implementation "com.amazonaws:ivs-broadcast:$version:stages@aar"
```

### Caricamento dei simboli in Firebase Crashlytics
<a name="android-debug-symbols-rt-firebase-crashlytics"></a>

Assicurati che i tuoi file di build Gradle siano configurati per Firebase Crashlytics. Segui le istruzioni di Google qui:

[https://firebase.google.com/docs/crashlytics/ndk-reports](https://firebase.google.com/docs/crashlytics/ndk-reports)

Assicurati di includere `com.google.firebase:firebase-crashlytics-ndk` come dipendenza.

Quando crei l'app per il rilascio, il plug-in Firebase Crashlytics dovrebbe caricare i simboli automaticamente. Per caricare i simboli manualmente, esegui uno dei comandi seguenti:

```
gradle uploadCrashlyticsSymbolFileRelease
```

```
./gradlew uploadCrashlyticsSymbolFileRelease
```

Non è un problema se i simboli vengono caricati due volte, automaticamente e manualmente.

### Impedire che .apk Release diventi più grande
<a name="android-debug-symbols-rt-sizing-apk"></a>

Prima di impacchettare il file `.apk` di rilascio, il plug-in Android Gradle tenta automaticamente di rimuovere le informazioni di debug dalle librerie condivise (inclusa la libreria `libbroadcastcore.so` dell'SDK di trasmissione IVS). Tuttavia, a volte ciò non accade. Di conseguenza, il file `.apk` potrebbe diventare più grande e si potrebbe ricevere un messaggio di avviso dal plug-in Android Gradle che indica che non è in grado di rimuovere i simboli di debug e sta impacchettando i file `.so` così come sono. In tal caso, segui questa procedura:
+ Installa un NDK per Android. Va bene qualsiasi versione recente.
+ Aggiungi `ndkVersion <your_installed_ndk_version_number>` al file `build.gradle` dell'applicazione. Fallo anche se l'applicazione non contiene codice nativo.

Per ulteriori informazioni, consulta questo [report sul problema](https://issuetracker.google.com/issues/353554169).

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

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

Qui, controlliamo se l'utente ha già concesso le autorizzazioni e, in caso contrario, le chiediamo:

```
final String[] requiredPermissions =
         { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };

for (String permission : requiredPermissions) {
    if (ContextCompat.checkSelfPermission(this, permission) 
                != PackageManager.PERMISSION_GRANTED) {
        // If any permissions are missing we want to just request them all.
        ActivityCompat.requestPermissions(this, requiredPermissions, 0x100);
        break;
    }
}
```

Qui, otteniamo la risposta dell'utente:

```
@Override
public void onRequestPermissionsResult(int requestCode, 
                                      @NonNull String[] permissions,
                                      @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,
               permissions, grantResults);
    if (requestCode == 0x100) {
        for (int result : grantResults) {
            if (result == PackageManager.PERMISSION_DENIED) {
                return;
            }
        }
        setupBroadcastSession();
    }
}
```

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

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

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

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

### Stage
<a name="android-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. 

```
Stage stage = new Stage(context, token, strategy);

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

stage.leave();
```

La classe `Stage` è anche il luogo in cui può essere collegato lo `StageRenderer`:

```
stage.addRenderer(renderer); // multiple renderers can be added
```

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

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

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

```
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

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 tramite il renderer durante tutto il processo.

Di seguito è riportata un'implementazione di esempio:

```
@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return Stage.SubscribeType.AUDIO_VIDEO;
}
```

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. Utilizza la proprietà `userInfo` su `ParticipantInfo` per iscriverti selettivamente ai partecipanti in base agli attributi forniti dal server:

```
@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	switch(participantInfo.userInfo.get(“role”)) {
		case “moderator”:
			return Stage.SubscribeType.NONE;
		case “guest”:
			return Stage.SubscribeType.AUDIO_VIDEO;
		default:
			return Stage.SubscribeType.NONE;
	}
}
```

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 moderati di vedersi, ma rimanendo invisibili agli ospiti.

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

```
SubscribeConfiguration subscribeConfigurationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

Se un partecipante moto viene abbonato (consulta la sezione [Abbonamento ai partecipanti](#android-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:

```
@Override
public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
    SubscribeConfiguration config = new SubscribeConfiguration();

    config.jitterBuffer.setMinDelay(JitterBufferConfiguration.JitterBufferDelay.MEDIUM());

    return config;
}
```

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="android-publish-subscribe-concepts-strategy-publishing"></a>

```
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

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:

```
@Override
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return true;
}
```

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="android-publish-subscribe-concepts-strategy-streams"></a>

```
@Override
List<LocalStageStream> stageStreamsToPublishForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
}
```

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](#android-publish-subscribe-publish-stream).

#### Aggiornamento della strategia
<a name="android-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 `shouldPublishFromParticipant` (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 `shouldPublishFromParticipant` è cambiato, avvierà il processo di pubblicazione. Se le query dell'SDK e tutte le funzioni restituiscono lo stesso valore di prima, la chiamata `refreshStrategy` non apporterà alcuna modifica allo stage.

Se il valore restituito di `shouldSubscribeToParticipant` cambia da `AUDIO_VIDEO` a `AUDIO_ONLY`, il flusso video verrà 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.

### Renderer
<a name="android-publish-subscribe-concepts-renderer"></a>

L'interfaccia `StageRenderer` comunica lo stato desiderato dello stage all'applicazione host. Gli aggiornamenti all'interfaccia utente dell'applicazione host in genere possono essere alimentati interamente dagli eventi forniti dal renderer. Il renderer fornisce le funzioni seguenti:

```
void onParticipantJoined(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);

void onParticipantLeft(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);

void onParticipantPublishStateChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull Stage.PublishState publishState);

void onParticipantSubscribeStateChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull Stage.SubscribeState subscribeState);

void onStreamsAdded(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onStreamsRemoved(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onStreamsMutedChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onError(@NonNull BroadcastException exception);

void onConnectionStateChanged(@NonNull Stage stage, @NonNull Stage.ConnectionState state, @Nullable BroadcastException exception);
                
void onStreamAdaptionChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, boolean adaption);

void onStreamLayersChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, @NonNull List<RemoteStageStream.Layer> layers);

void onStreamLayerSelected(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, @Nullable RemoteStageStream.Layer layer, @NonNull RemoteStageStream.LayerSelectedReason reason);
```

Per la maggior parte di questi metodi, vengono forniti `Stage` e `ParticipantInfo` corrispondenti.

Non è previsto che le informazioni fornite dal renderer influiscano sui valori restituiti della strategia. Ad esempio, non è previsto che il valore restituito di `shouldSubscribeToParticipant` cambi quando viene chiamato `onParticipantPublishStateChanged`. 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.

Lo `StageRenderer` può essere collegato alla classe dello stage:

```
stage.addRenderer(renderer); // multiple renderers can be added
```

Ricorda che solo i partecipanti alla pubblicazione attivano `onParticipantJoined` e ogni volta che un partecipante interrompe la pubblicazione o abbandona la sessione dello stage viene attivato `onParticipantLeft`.

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

I dispositivi locali, come microfoni e fotocamere integrati, vengono rilevati tramite `DeviceDiscovery`. Ecco un esempio di selezione della fotocamera frontale e del microfono predefinito, che vengono poi restituiti come `LocalStageStreams` per la pubblicazione dall'SDK:

```
DeviceDiscovery deviceDiscovery = new DeviceDiscovery(context);

List<Device> devices = deviceDiscovery.listLocalDevices();
List<LocalStageStream> publishStreams = new ArrayList<LocalStageStream>();

Device frontCamera = null;
Device microphone = null;

// Create streams using the front camera, first microphone
for (Device device : devices) {
	Device.Descriptor descriptor = device.getDescriptor();
	if (!frontCamera && descriptor.type == Device.Descriptor.DeviceType.Camera && descriptor.position = Device.Descriptor.Position.FRONT) {
		front Camera = device;
	}
	if (!microphone && descriptor.type == Device.Descriptor.DeviceType.Microphone) {
		microphone = device;
	}
}

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera);
AudioLocalStageStream microphoneStream = new AudioLocalStageStream(microphoneDevice);

publishStreams.add(cameraStream);
publishStreams.add(microphoneStream);

// Provide the streams in Stage.Strategy
@Override
@NonNull List<LocalStageStream> stageStreamsToPublishForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return publishStreams;
}
```

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

Una volta completata la sottoscrizione, riceverai una serie di oggetti `StageStream` tramite la funzione `onStreamsAdded` del renderer. Puoi recuperare l'anteprima da un `ImageStageStream`:

```
ImagePreviewView preview = ((ImageStageStream)stream).getPreview();

// Add the view to your view hierarchy
LinearLayout previewHolder = findViewById(R.id.previewHolder);
preview.setLayoutParams(new LinearLayout.LayoutParams(
		LinearLayout.LayoutParams.MATCH_PARENT,
		LinearLayout.LayoutParams.MATCH_PARENT));
previewHolder.addView(preview);
```

Puoi recuperare le statistiche del livello audio da un `AudioStageStream`:

```
((AudioStageStream)stream).setStatsCallback((peak, rms) -> {
	// handle statistics
});
```

Quando un partecipante interrompe la pubblicazione o annulla l'iscrizione, la funzione `onStreamsRemoved` viene chiamata con i flussi che sono stati rimossi. Le applicazioni host devono utilizzarlo come segnale per rimuovere il flusso video del partecipante dalla gerarchia delle visualizzazioni.

`onStreamsRemoved` 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é `onStreamsRemoved` 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="android-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 `streamsToPublishForParticipant`.

**Importante**: se una nuova istanza di oggetto `LocalStageStream` viene restituita da `streamsToPublishForParticipant` 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="android-publish-subscribe-mute-state"></a>

Quando un partecipante modifica lo stato di silenziamento del proprio flusso video o audio, la funzione `onStreamMutedChanged` del renderer viene richiamata con un elenco di flussi che sono stati modificati. Usa il metodo `getMuted` su `StageStream` per aggiornare l'interfaccia utente di conseguenza. 

```
@Override
void onStreamsMutedChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams) {
	for (StageStream stream : streams) {
		boolean muted = stream.getMuted();
		// handle UI changes
	}
}
```

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

Per ottenere le statistiche WebRTC più recenti per un flusso di pubblicazione o un flusso di iscrizione, usa `requestRTCStats` su `StageStream`. Quando una raccolta è completata, riceverai statistiche tramite il `StageStream.Listener` che può essere impostato su `StageStream`.

```
stream.requestRTCStats();

@Override
void onRTCStats(Map<String, Map<String, String>> statsMap) {
	for (Map.Entry<String, Map<String, string>> stat : statsMap.entrySet()) {
		for(Map.Entry<String, String> member : stat.getValue().entrySet()) {
			Log.i(TAG, stat.getKey() + “ has member “ + member.getKey() + “ with value “ + member.getValue());
		}
	}
}
```

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

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

```
@Override
void onParticipantJoined(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	for (Map.Entry<String, String> entry : participantInfo.userInfo.entrySet()) {
		Log.i(TAG, “attribute: “ + entry.getKey() + “ = “ + entry.getValue());
	}
}
```

## Incorpora messaggi
<a name="android-publish-subscribe-embed-messages"></a>

Il metodo `embedMessage` su ImageDevice consente di inserire payload di metadati direttamente nei frame video durante la pubblicazione. Ciò consente la messaggistica sincronizzata con i frame per applicazioni in tempo reale. L’embedding dei messaggi è disponibile solo quando si utilizza l'SDK per la pubblicazione in tempo reale (non per la pubblicazione a bassa latenza).

Non è garantito che i messaggi incorporati arrivino agli abbonati perché sono incorporati direttamente nei frame video e trasmessi tramite UDP, il che non garantisce la consegna dei pacchetti. La perdita di pacchetti durante la trasmissione può causare la perdita di messaggi, soprattutto in condizioni di rete precarie. Per mitigare questo problema, il metodo `embedMessage` include un parametro `repeatCount` che duplica il messaggio su più frame consecutivi, aumentando l'affidabilità della consegna. Questa funzione è disponibile solo per i flussi video.

### Usa embedMessage
<a name="android-embed-messages-using-embedmessage"></a>

I client di pubblicazione possono incorporare i payload dei messaggi nel loro flusso video utilizzando il metodo `embedMessage` su ImageDevice. La dimensione del payload deve essere maggiore di 0 KB e inferiore a 1 KB. Il numero di messaggi incorporati inseriti al secondo non deve superare i 10 KB al secondo. 

```
val surfaceSource: SurfaceSource = imageStream.device as SurfaceSource
val message = "hello world"
val messageBytes = message.toByteArray(StandardCharsets.UTF_8)

try {
    surfaceSource.embedMessage(messageBytes, 0)
} catch (e: BroadcastException) {
    Log.e("EmbedMessage", "Failed to embed message: ${e.message}")
}
```

### Ripetizione dei payload del messaggio
<a name="android-embed-messages-repeat-payloads"></a>

Utilizza `repeatCount` per duplicare il messaggio su più frame per una maggiore affidabilità. Il valore deve essere compreso tra 0 e 30. I client di ricezione devono disporre di una logica per deduplicare il messaggio.

```
try {
    surfaceSource.embedMessage(messageBytes, 5)
    // repeatCount: 0-30, receiving clients should handle duplicates
} catch (e: BroadcastException) {
    Log.e("EmbedMessage", "Failed to embed message: ${e.message}")
}
```

### Lettura dei messaggi incorporati
<a name="android-embed-messages-read-messages"></a>

Vedi «Ottieni informazioni supplementari sul miglioramento (SEI)» di seguito per sapere come leggere i messaggi incorporati dai flussi in entrata.

## Ottenimento di dati Supplemental Enhancement Information (SEI)
<a name="android-publish-subscribe-sei-attributes"></a>

L'unità NAL Supplemental Enhancement Information (SEI) viene utilizzata per archiviare i metadati allineati al fotogramma insieme al video. I clienti abbonati possono leggere i payload SEI di un publisher che pubblica video H.264 ispezionando la proprietà `embeddedMessages` sugli oggetti `ImageDeviceFrame` che provengono da `ImageDevice` del publisher. A tal fine, acquisire `ImageDevice` di un publisher, quindi osservare ogni frame tramite un callback fornito a `setOnFrameCallback`, come mostrato nell'esempio seguente:

```
// in a StageRenderer’s onStreamsAdded function, after acquiring the new ImageStream

val imageDevice = imageStream.device as ImageDevice
imageDevice.setOnFrameCallback(object : ImageDevice.FrameCallback {
	override fun onFrame(frame: ImageDeviceFrame) {
    		for (message in frame.embeddedMessages) {
        		if (message is UserDataUnregisteredSeiMessage) {
            		val seiMessageBytes = message.data
            		val seiMessageUUID = message.uuid
           	 
            		// interpret the message's data based on the UUID
        		}
    		}
	}
})
```

## Continuazione della sessione in background
<a name="android-publish-subscribe-background-session"></a>

Quando l'app entra in background, potresti voler interrompere la pubblicazione o iscriverti solo all'audio degli altri partecipanti remoti. A tale scopo, aggiorna l'implementazione `Strategy` per interrompere la pubblicazione e iscriviti a `AUDIO_ONLY` (o `NONE`, se applicabile).

```
// Local variables before going into the background
boolean shouldPublish = true;
Stage.SubscribeType subscribeType = Stage.SubscribeType.AUDIO_VIDEO;

// Stage.Strategy implementation
@Override
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return shouldPublish;
}

@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return subscribeType;
}

// In our Activity, modify desired publish/subscribe when we go to background, then call refreshStrategy to update the stage
@Override
void onStop() {
	super.onStop();
	shouldPublish = false;
	subscribeTpye = Stage.SubscribeType.AUDIO_ONLY;
	stage.refreshStrategy();
}
```

## Codifica a livelli con Simulcast
<a name="android-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 configurare dinamicamente o manualmente tali livelli. La funzionalità è descritta più approfonditamente nel documento [Ottimizzazioni dello streaming](real-time-streaming-optimization.md).

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

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

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

A seconda della risoluzione impostata nella configurazione video, un determinato numero di livelli verrà codificato e inviato 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: 

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

List<StageVideoConfiguration.Simulcast.Layer> simulcastLayers = new ArrayList<>();
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_720);
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_180);

config.simulcast.setLayers(simulcastLayers);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

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 i seguenti setter di proprietà obbligatori:
+ `setSize: Vec2;`
+ `setMaxBitrate: integer;`
+ `setMinBitrate: integer;`
+ `setTargetFramerate: integer;`

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

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

List<StageVideoConfiguration.Simulcast.Layer> simulcastLayers = new ArrayList<>();

// Configure high quality layer with custom framerate
StageVideoConfiguration.Simulcast.Layer customHiLayer = StagePresets.SimulcastLocalLayer.DEFAULT_720;
customHiLayer.setTargetFramerate(15);

// Add layers to the list
simulcastLayers.add(customHiLayer);
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_180);

config.simulcast.setLayers(simulcastLayers);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

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="android-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="android-layered-encoding-simulcast-layer-quality-preference"></a>

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

```
@Override
public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
    SubscribeConfiguration config = new SubscribeConfiguration();

    config.simulcast.setInitialLayerPreference(SubscribeSimulcastConfiguration.InitialLayerPreference.LOWEST_QUALITY);

    return config;
}
```

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 `setInitialLayerPreference`), è necessario effettuare un nuovo abbonamento poiché questi aggiornamenti non si applicano all'abbonamento attivo.

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

Il metodo strategico `preferredLayerForStream` consente di selezionare un livello dopo l'inizio del flusso. Questo metodo di strategia riceve le informazioni sul partecipante e sul flusso, permettendoti di selezionare un livello singolarmente per ciascun partecipante. L’SDK chiama questo metodo in risposta a eventi specifici, come quando cambiano i livelli del flusso, lo stato del partecipante o quando l’applicazione host aggiorna la strategia.

Il metodo di strategia restituisce un oggetto `RemoteStageStream.Layer`, che può essere uno dei seguenti:
+ Un oggetto di livello, ad esempio uno restituito da `RemoteStageStream.getLayers`.
+ null, 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:

```
@Nullable
@Override
public RemoteStageStream.Layer preferredLayerForStream(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream) {
    return stream.getLowestQualityLayer();
}
```

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

```
@Nullable
@Override
public RemoteStageStream.Layer preferredLayerForStream(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream) {
    if (appState.isAutoMode) {
        return null;
    } else {
        return appState.layerChoice;
    }
}
```

### Opzione 3: helper per livelli RemoteStageStream
<a name="android-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 `StageRenderer`, `RemoteStageStream.Listener` include eventi che comunicano modifiche di adattamento di livelli e simulcast:
  + `void onAdaptionChanged(boolean adaption)`
  + `void onLayersChanged(@NonNull List<Layer> layers)`
  + `void onLayerSelected(@Nullable Layer layer, @NonNull LayerSelectedReason 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 `StageRenderer.onStreamsAdded`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`
  + `stream.getLayersWithConstraints`

Per i dettagli, consulta la classe `RemoteStageStream` nella [Documentazione di riferimento dell'SDK](https://aws.github.io/amazon-ivs-broadcast-docs/latest/android/). Per il motivo `LayerSelected`, 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.

## Limitazioni alla configurazione video
<a name="android-publish-subscribe-video-limits"></a>

L'SDK non supporta l'uso forzato della modalità verticale o della modalità orizzontale `StageVideoConfiguration.setSize(BroadcastConfiguration.Vec2 size)`. Nell'orientamento verticale, la dimensione più piccola viene utilizzata come larghezza; nell'orientamento orizzontale, l'altezza. Ciò significa che le due chiamate seguenti a `setSize` avranno lo stesso effetto sulla configurazione video:

```
StageVideo Configuration config = new StageVideo Configuration();

config.setSize(BroadcastConfiguration.Vec2(720f, 1280f);
config.setSize(BroadcastConfiguration.Vec2(1280f, 720f);
```

## Gestione dei problemi di rete
<a name="android-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. Esistono due errori principali relativi alla perdita della connessione di rete:
+ Codice di errore 1400, messaggio: "PeerConnection is lost due to unknown network error" (Connessione peer interrotta a causa di un errore di rete sconosciuto)
+ Codice di errore 1300, messaggio: "Retry attempts are exhausted" (Nuovi tentativi esauriti)

Se viene ricevuto il primo errore ma il secondo no, l'SDK è ancora connesso allo stage e tenterà di ristabilire automaticamente le connessioni. Come misura di sicurezza, puoi chiamare `refreshStrategy` senza modificare i valori restituiti dal metodo di strategia, per attivare un tentativo di riconnessione manuale.

Se viene ricevuto il secondo errore, i tentativi di riconnessione dell'SDK sono falliti e il dispositivo locale non è più connesso allo stage. In questo caso, prova a rientrare nello stage chiamando `join` dopo aver ristabilito la connessione di rete.

In generale, il verificarsi di errori dopo l'accesso corretto a uno stage indica che l'SDK non è riuscito a ristabilire una connessione. Crea un nuovo oggetto `Stage` e prova ad accedere quando le condizioni della rete migliorano.

## Uso dei microfoni Bluetooth
<a name="android-publish-subscribe-bluetooth-microphones"></a>

Per pubblicare utilizzando dispositivi microfonici Bluetooth, è necessario avviare una connessione Bluetooth SCO:

```
Bluetooth.startBluetoothSco(context);
// Now bluetooth microphones can be used
…
// Must also stop bluetooth SCO
Bluetooth.stopBluetoothSco(context);
```

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

Questo documento elenca i problemi noti che potresti riscontrare quando utilizzi lo Streaming in tempo reale di Amazon IVS per la trasmissione su Android e suggerisce possibili soluzioni alternative.
+ Quando un dispositivo Android entra in modalità sospensione e si riattiva, è possibile che l'anteprima sia bloccata.

  **Soluzione alternativa:** crea e usa una nuova `Stage`.
+ Quando un partecipante accede con un token utilizzato da un altro partecipante, la prima connessione viene disconnessa senza un errore specifico.

  **Soluzione alternativa:** nessuna. 
+ Può verificarsi un problema raro per cui il publisher sta pubblicando, ma lo stato di pubblicazione che gli abbonati ricevono è `inactive`.

  **Soluzione alternativa:** prova a uscire e poi a partecipare alla sessione. Se il problema persiste, crea un nuovo token per il publisher.
+ Durante una sessione di stage può verificarsi un raro problema di distorsione audio a intermittenza, in genere durante le chiamate di lunga durata.

  **Soluzione alternativa:** il partecipante con audio distorto può uscire e accedere nuovamente alla sessione oppure annullare la pubblicazione e ripubblicare l'audio per risolvere il problema.
+ I microfoni esterni non sono supportati durante la pubblicazione su uno stage.

  **Soluzione alternativa:** non utilizzare un microfono esterno collegato tramite USB per la pubblicazione su uno stage.
+ La pubblicazione su uno stage con condivisione dello schermo usando `createSystemCaptureSources` non è supportata.

  **Soluzione alternativa:** gestisci l'acquisizione del sistema manualmente, utilizzando sorgenti di input di immagini personalizzate e sorgenti di input audio personalizzate.
+ Quando una `ImagePreviewView` viene rimossa da un elemento padre (ad esempio, `removeView()` viene chiamato dall'elemento padre), `ImagePreviewView` viene rilasciata immediatamente. `ImagePreviewView` non mostra alcun frame quando viene aggiunta a un'altra vista principale.

  **Soluzione alternativa:** richiedi un'altra anteprima utilizzando `getPreview`.
+ Quando partecipi a uno stage con un Samsung Galaxy S22/\$1 con Android 12, potresti riscontrare un errore 1401 e il dispositivo locale non riesce ad accedere allo stage o accede ma senza audio.

  **Soluzione alternativa:** esegui l'aggiornamento ad Android 13.
+ Quando accedi a uno stage con un Nokia X20 su Android 13, la fotocamera potrebbe non aprirsi e viene generata un'eccezione.

  **Soluzione alternativa:** nessuna.
+ I dispositivi con il chipset MediaTek Helio potrebbero non renderizzare correttamente i video dei partecipanti remoti.

  **Soluzione alternativa:** nessuna.
+ Su alcuni dispositivi, il sistema operativo del dispositivo può scegliere un microfono diverso da quello selezionato tramite l'SDK. Questo perché l'SDK di trasmissione Amazon IVS non può controllare come viene definito il percorso audio `VOICE_COMMUNICATION`, poiché varia in base ai diversi produttori di dispositivi.

  **Soluzione alternativa:** nessuna.
+ Alcuni codificatori video Android non possono essere configurati con dimensioni video inferiori a 176x176. La configurazione di una dimensione inferiore causa un errore e impedisce lo streaming.

  **Soluzione alternativa:** configura la dimensione del video in modo che non sia inferiore a 176x176.

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

Questa sezione fornisce una panoramica delle condizioni di errore, del modo in cui l'SDK di trasmissione IVS per lo streaming in tempo reale su Android le segnala all'applicazione e di cosa dovrebbe fare un'applicazione quando si verificano tali errori.

## Errori irreversibili e non irreversibili
<a name="broadcast-android-fatal-vs-nonfatal-errors"></a>

L'oggetto errore ha un campo booleano "è irreversibile" di `BroadcastException`.

In generale, gli errori irreversibili sono legati alla connessione al server degli stage (ad es. non è possibile stabilire una connessione oppure la connessione viene interrotta e non può essere recuperata). L'applicazione dovrebbe ricreare lo stage e riaccedervi, possibilmente con un nuovo token o quando la connettività del dispositivo viene ripristinata.

Gli errori non irreversibili sono generalmente correlati allo stato di pubblicazione/sottoscrizione e vengono gestiti dall'SDK, che riprova l'operazione di pubblicazione/sottoscrizione.

Puoi controllare questa proprietà:

```
try {
  stage.join(...)
} catch (e: BroadcastException) {
  If (e.isFatal) { 
    // the error is fatal
```

## Errori di accesso
<a name="broadcast-android-stage-join-errors"></a>

### Token non conforme
<a name="broadcast-android-stage-join-errors-malformed-token"></a>

Ciò accade quando il token dello stage non è conforme.

L'SDK genera un'eccezione Java da una chiamata a `stage.join`, con codice di errore = 1000 e fatal = true.

**Azione**: crea un token valido e riprova a partecipare.

### Token scaduto
<a name="broadcast-android-stage-join-errors-expired-token"></a>

Ciò accade quando il token dello stage è scaduto.

L'SDK genera un'eccezione Java da una chiamata a `stage.join`, con codice di errore = 1001 e fatal = true.

**Azione**: crea un nuovo token e riprova a partecipare.

### Token non valido o revocato
<a name="broadcast-android-stage-join-errors-invalid-token"></a>

Ciò accade quando il token dello stage è conforme ma viene rifiutato dal server degli stage. Ciò viene segnalato in modo asincrono tramite il renderer dello stage fornito dall'applicazione.

L'SDK chiama `onConnectionStateChanged` con un'eccezione, con codice di errore = 1026 e fatal = true.

**Azione**: crea un token valido e riprova a partecipare.

### Errori di rete per l'accesso iniziale
<a name="broadcast-android-stage-join-errors-network-initial-join"></a>

Ciò accade quando l'SDK non riesce a contattare il server degli stage per stabilire una connessione. Ciò viene segnalato in modo asincrono tramite il renderer dello stage fornito dall'applicazione.

L'SDK chiama `onConnectionStateChanged` con un'eccezione, con codice di errore = 1300 e fatal = true.

**Azione**: attendi il ripristino della connettività del dispositivo e riprova a connetterti.

### Errori di rete quando è già stato effettuato l'accesso
<a name="broadcast-android-stage-join-errors-network-already-joined"></a>

Se la connessione di rete del dispositivo si interrompe, l'SDK potrebbe perdere la connessione ai server dello stage. Ciò viene segnalato in modo asincrono tramite il renderer dello stage fornito dall'applicazione.

L'SDK chiama `onConnectionStateChanged` con un'eccezione, con codice di errore = 1300 e fatal = true.

**Azione**: attendi il ripristino della connettività del dispositivo e riprova a connetterti.

## Errori di pubblicazione/sottoscrizione
<a name="broadcast-android-publish-subscribe-errors"></a>

### Initial
<a name="broadcast-android-publish-subscribe-errors-initial"></a>

Esistono diversi tipi di errori:
+ MultihostSessionOfferCreationFailPublish (1020)
+ MultihostSessionOfferCreationFailSubscribe (1021)
+ MultihostSessionNoIceCandidates (1022)
+ MultihostSessionStageAtCapacity (1024)
+ SignallingSessionCannotRead (1201)
+ SignallingSessionCannotSend (1202)
+ Sessione di segnalazione: risposta errata (1203)

Questi vengono segnalati in modo asincrono tramite il renderer dello stage fornito dall'applicazione.

L'SDK riprova l'operazione per un numero limitato di volte. Durante i nuovi tentativi, lo stato di pubblicazione/sottoscrizione è `ATTEMPTING_PUBLISH`/`ATTEMPTING_SUBSCRIBE`. Se i nuovi tentativi hanno esito positivo, lo stato diventa `PUBLISHED`/`SUBSCRIBED`.

L'SDK chiama `onError` con il codice di errore pertinente e fatal = false.

**Azione**: non è necessaria alcuna azione, poiché l'SDK riprova automaticamente. Facoltativamente, l'applicazione può aggiornare la strategia per imporre ulteriori tentativi.

### Già stabilita, poi fallita
<a name="broadcast-android-publish-subscribe-errors-established"></a>

Una pubblicazione o una sottoscrizione possono fallire una volta stabilite, molto probabilmente a causa di un errore di rete. Il codice di errore per una "connessione peer interrotta a causa di un errore di rete" è 1400.

Ciò viene segnalato in modo asincrono tramite il renderer dello stage fornito dall'applicazione.

L'SDK riprova l'operazione di pubblicazione/sottoscrizione. Durante i nuovi tentativi, lo stato di pubblicazione/sottoscrizione è `ATTEMPTING_PUBLISH`/`ATTEMPTING_SUBSCRIBE`. Se i nuovi tentativi hanno esito positivo, lo stato diventa `PUBLISHED`/`SUBSCRIBED`.

L'SDK chiama `onError` con il codice di errore = 1400 e fatal = false.

**Azione**: non è necessaria alcuna azione, poiché l'SDK riprova automaticamente. Facoltativamente, l'applicazione può aggiornare la strategia per imporre ulteriori tentativi. In caso di perdita totale della connettività, è probabile che anche la connessione agli stage fallisca.