

# Optimierungen für IVS-Echtzeit-Streaming
<a name="real-time-streaming-optimization"></a>

Um sicherzustellen, dass Ihre Benutzer das beste Erlebnis beim Streamen und Ansehen von Videos mithilfe von IVS Echtzeit-Streaming haben, gibt es verschiedene Möglichkeiten, das Erlebnis zu verbessern oder Teile des Erlebnisses zu optimieren, indem Sie die Features verwenden, die wir heute anbieten. 

## Einführung
<a name="real-time-streaming-optimization-intro"></a>

Bei der Optimierung der Benutzererlebnisqualität ist es wichtig, die gewünschte Benutzererfahrung zu berücksichtigen. Diese kann sich je nach den Inhalten, die sie sich ansehen, und den Netzwerkbedingungen ändern. 

In diesem Leitfaden konzentrieren wir uns auf Benutzer, die entweder *Publisher* von Streams oder *Subscriber* von Streams sind und wir berücksichtigen die gewünschten Aktionen und Erfahrungen dieser Nutzer. 

Mit den IVS-SDKs können Sie die maximale Bitrate, Framerate und Auflösung von Streams konfigurieren. Wenn es bei Publishern zu Netzwerküberlastungen kommt, nimmt das SDK automatisch eine Anpassung vor und verringert die Videoqualität, indem es die Bitrate, Framerate und Auflösung senkt. Unter Android und iOS ist es möglich, die Einstellung zur Leistungsreduzierung bei Überlastungen auswählen. Das gleiche Verhalten tritt unabhängig davon auf, ob Sie die mehrschichtige Codierung mit Simulcast aktivieren oder die Standardkonfiguration beibehalten.

## Adaptives Streaming: Mehrschichtige Kodierung mit Simulcast
<a name="real-time-streaming-optimization-adaptive"></a>

Dieses Feature wird nur von den folgenden Client-Versionen unterstützt:
+ iOS und Android 1.18.0\+
+ Web 1.12.0\+

Bei Verwendung der [Echtzeit-Broadcast-SDKs](broadcast.md) von IVS können Publisher standardmäßig mehrere Video-Layer codieren und die Subscriber übernehmen automatisch die für ihr Netzwerk am besten geeignete Qualität oder wechseln zu dieser. Wir nennen das *mehrschichtige Kodierung mit Simulcast*.

Das Codieren von Layern mit Simulcast wird unter Android und iOS sowie in den Chrome- und Edge-Desktopbrowsern (für Windows und macOS) unterstützt. Wir unterstützen keine mehrschichtige Kodierung in anderen Browsern. 

In der Abbildung unten sendet der Host drei Videoqualitäten (hoch, mittel und niedrig). IVS leitet auf der Grundlage der verfügbaren Bandbreite das Video von höchster Qualität an jeden Zuschauer weiter. Dies bietet jedem Zuschauer ein optimales Erlebnis. Wenn sich die Netzwerkverbindung von Zuschauer 1 von gut zu schlecht ändert, beginnt IVS automatisch damit, Video mit geringerer Qualität an Zuschauer 1 zu senden, sodass Zuschauer 1 den Stream weiterhin ohne Unterbrechung ansehen kann (mit der bestmöglichen Qualität).

![Verwenden Sie die mehrschichtige Kodierung mit Simulcast, um die Videoqualität an die Qualität der Netzwerkverbindung eines Zuschauers anzupassen.](https://docs.aws.amazon.com/de_de/ivs/latest/RealTimeUserGuide/images/Layered_Encoding_1.png)


### Standard-Layers, Eigenschaften und Framerates
<a name="real-time-streaming-optimization-default-layers"></a>

Die Standardqualitäten und Ebenen, die für Mobil- und Webbenutzer bereitgestellt werden, lauten wie folgt:


| Mobil (Android, iOS) | Web (Chrome) | 
| --- | --- | 
| Hohe Schicht (oder benutzerdefiniert):+  Maximale Bitrate: 900 000 bps <br />+  Bildrate: 15 fps  | Hohe Schicht (oder benutzerdefiniert):+  Maximale Bitrate: 1 700 000 bps <br />+  Bildrate: 30 fps  | 
| Mittelschicht: keine (nicht erforderlich, da der Unterschied zwischen den Bitraten auf hoher und niedriger Ebene auf Mobilgeräten gering ist) | Mittelschicht:+  Maximale Bitrate: 700 000 bps <br />+  Bildrate: 20 fps  | 
| Niedrige Schicht:+  Maximale Bitrate: 100 000 BpS <br />+  Bildrate: 15 fps  | Niedrige Schicht:+  Maximale Bitrate: 200 000 bps <br />+  Bildrate: 15 fps  | 

### Auflösung von Layern
<a name="real-time-streaming-optimization-layer-resolution"></a>

Die Auflösungen der mittleren und unteren Layer werden gegenüber dem oberen Layer automatisch herunterskaliert, um das gleiche Seitenverhältnis beizubehalten.

Mittlere und niedrige Layer werden ausgeschlossen, wenn ihre Auflösungen zu nahe an der Auflösung des darüber liegenden Layers liegen. Wenn die konfigurierte Auflösung beispielsweise 320 × 180 ist, sendet das SDK nicht auch Layer mit niedrigerer Auflösung.

Die folgende Tabelle zeigt die Auflösungen von Layern, die für verschiedene konfigurierte Auflösungen generiert wurden. Die aufgeführten Werte sind für das Querformat gedacht, können aber auch umgekehrt für Inhalte im Hochformat angewendet werden.


| Eingabeauflösung | Auflösungen des Ausgabe-Layers: Mobil | Auflösungen des Ausgabe-Layers: Web | 
| --- | --- | --- | 
| 720p (1280 × 720) | Hoch (1280 × 720)<br />Niedrig (320 × 180) | Hoch (1280 × 720)<br />Mittel (640 × 360)<br />Niedrig (320 × 180) | 
| 540p (960 × 540) | Hoch (960 × 540)<br />Niedrig (320 × 180) | Hoch (960 × 540)<br />Niedrig (320 × 180) | 
| 360p (640 × 360) | Hoch (640 × 360)<br />Niedrig (360 × 180) | Hoch (640 × 360)<br />Niedrig (360 × 180) | 
| 270p (480 × 270) | Hoch (480 × 270) | Hoch (480 × 270) | 
| 180p (320 × 180) | Hoch (320 × 180) | Hoch (320 × 180) | 

Benutzerdefinierte Eingabeauflösungen, die oben nicht abgebildet sind, können Sie sie [mit dem folgenden Tool](https://codepen.io/amazon-ivs/full/ZENQQvo) berechnen.

### Konfigurieren mehrschichtiger Kodierung mit Simulcast (Publisher)
<a name="real-time-streaming-optimization-simulcast"></a>

Um die Codierung von Layern mit Simulcast verwenden zu können, müssen Sie [das Feature auf dem Client aktiviert](#real-time-streaming-optimization-adaptive) haben. Wenn Sie es aktivieren, werden Sie feststellen, dass der Publisher mehr Upload-Bandbreite nutzt, was möglicherweise dazu führt, dass das Video für Zuschauer weniger einfriert.

**Android**

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

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
// Enable Simulcast
let config = IVSLocalStageStreamVideoConfiguration()
config.simulcast.enabled = true

let cameraStream = IVSLocalStageStream(device: camera, configuration: config)

// Other Stage implementation code
```

**Web**

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

// Other Stage implementation code
```

Ausführliche Informationen zur Konfiguration einzelner Ebenen finden Sie unter „Konfigurieren mehrschichtiger Kodierung (Publisher)“ in jedem Broadcast-SDK-Handbuch: [Android](android-publish-subscribe.md#android-layered-encoding-simulcast-configure-publisher), [iOS](ios-publish-subscribe.md#ios-layered-encoding-simulcast-configure-publisher) und [Web](web-publish-subscribe.md#web-layered-encoding-simulcast-configure-publisher).

### Konfigurieren mehrschichtiger Kodierung mit Simulcast (Subscriber)
<a name="real-time-streaming-optimization-simulcast-subscriber"></a>

Informationen zum Konfigurieren der Schichten, die von Subscribern empfangen werden, finden Sie in den Abschnitten unter „Mehrschichtige Kodierung mit Simulcast“ in den SDK-Leitfäden zum Echtzeit-Streaming:
+ [Broadcast-SDK für Android](android-publish-subscribe.md#android-publish-subscribe-layered-encoding-simulcast)
+ [Broadcast-SDK für iOS](ios-publish-subscribe.md#ios-publish-subscribe-layered-encoding-simulcast)
+ [Web-Broadcast-SDK](web-publish-subscribe.md#web-publish-subscribe-layered-encoding-simulcast)

Mit der Subscriber-Konfiguration lässt sich die `InitialLayerPreference` definieren. Dies bestimmt, in welcher Qualität Videos anfänglich wiedergegeben werden, sowie den `preferredLayerForStream`, was wiederum bestimmt, welche Schicht bei der Videowiedergabe ausgewählt wird. Es gibt Ereignisse und Streaming-Methoden zur Benachrichtigung für den Fall, dass sich Schichten ändern, Anpassungen vorgenommen werden oder eine Schichtauswahl getroffen wird.

## Streamingkonfigurationen
<a name="real-time-streaming-configurations"></a>

In diesem Abschnitt werden andere Konfigurationen beschrieben, die Sie an Ihren Video- und Audiostreams vornehmen können.

### Ändern der Bitrate des Video-Streams
<a name="real-time-streaming-changing-bitrate"></a>

Verwenden Sie die folgenden Konfigurationsbeispiele, um die Bitrate Ihres Video-Streams zu ändern.

**Android**

```
StageVideoConfiguration config = new StageVideoConfiguration();

// Update Max Bitrate to 1.5mbps
config.setMaxBitrate(1500000);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamVideoConfiguration();

// Update Max Bitrate to 1.5mbps
try! config.setMaxBitrate(1500000);

let cameraStream = IVSLocalStageStream(device: camera, configuration: config);

// Other Stage implementation code
```

**Web**

```
let cameraStream = new LocalStageStream(camera.getVideoTracks()[0], {
   // Update Max Bitrate to 1.5mbps or 1500kbps
   maxBitrate: 1500
})

// Other Stage implementation code
```

### Ändern der Framerate des Video-Streams
<a name="real-time-streaming-changing-framerate"></a>

Verwenden Sie die folgenden Konfigurationsbeispiele, um die Framerate Ihres Video-Streams zu ändern.

**Android**

```
StageVideoConfiguration config = new StageVideoConfiguration();

// Update target framerate to 10fps
config.targetFramerate(10);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamVideoConfiguration();

// Update target framerate to 10fps
try! config.targetFramerate(10);

let cameraStream = IVSLocalStageStream(device: camera, configuration: config);

// Other Stage implementation code
```

**Web**

```
// Note: On web it is also recommended to configure the framerate of your device from userMedia
const camera = await navigator.mediaDevices.getUserMedia({
   video: {
      frameRate: {
         ideal: 10,
         max: 10,
      },
   },
});

let cameraStream = new LocalStageStream(camera.getVideoTracks()[0], {
   // Update Max Framerate to 10fps
   maxFramerate: 10
})
// Other Stage implementation code
```

### Optimieren der Audio-Bitrate und Stereo-Unterstützung
<a name="real-time-streaming-optimize-audio-stream"></a>

Verwenden Sie die folgenden Konfigurationsbeispiele, um die Bitrate und Stereoeinstellungen Ihres Audio-Streams zu ändern.

**Web**

```
// Note: Disable autoGainControl, echoCancellation, and noiseSuppression when enabling stereo.
const camera = await navigator.mediaDevices.getUserMedia({
   audio: {
      autoGainControl: false,
      echoCancellation: false,
      noiseSuppression: false
   },
});

let audioStream = new LocalStageStream(camera.getAudioTracks()[0], {
   // Optional: Update Max Audio Bitrate to 96Kbps. Default is 64Kbps
   maxAudioBitrateKbps: 96,

   // Signal stereo support. Note requires dual channel input source.
   stereo: true
})

// Other Stage implementation code
```

**Android**

```
StageAudioConfiguration config = new StageAudioConfiguration();

// Update Max Bitrate to 96Kbps. Default is 64Kbps.
config.setMaxBitrate(96000);

AudioLocalStageStream microphoneStream = new AudioLocalStageStream(microphone, config);

// Other Stage implementation code
```

**iOS**

```
let config = IVSLocalStageStreamConfiguration();

// Update Max Bitrate to 96Kbps. Default is 64Kbps.
try! config.audio.setMaxBitrate(96000);

let microphoneStream = IVSLocalStageStream(device: microphone, config: config);

// Other Stage implementation code
```

### Ändern der Mindestverzögerung des Jitter-Puffers für Subscriber
<a name="real-time-streaming-jitter-buffer-min-delay"></a>

Um die Mindestverzögerung des Jitter-Puffers für einen abonnierten Teilnehmer zu ändern, kann ein benutzerdefinierter `subscribeConfiguration`-Wert verwendet werden. Der Jitter-Puffer bestimmt, wie viele Pakete gespeichert werden, bevor die Wiedergabe beginnt. Die Mindestverzögerung stellt das Ziel für die minimale Datenmenge dar, die gespeichert werden soll. Eine Änderung der Mindestverzögerung kann dazu beitragen, dass die Wiedergabe bei Paketverlusten/Verbindungsproblemen stabiler wird.

Der Nachteil beim Vergrößern des Jitter-Puffers besteht darin, dass dadurch auch die Verzögerung vor dem Beginn der Wiedergabe erhöht wird. Eine Erhöhung der Mindestverzögerung sorgt für mehr Stabilität, geht jedoch zu Lasten der Zeit bis zum Video. Beachten Sie, dass eine Erhöhung der Mindestverzögerung bei der Wiedergabe einen ähnlichen Effekt hat: Die Wiedergabe wird kurz unterbrochen, damit der Jitter-Puffer gefüllt werden kann.

Wenn mehr Stabilität erforderlich ist, empfehlen wir, mit der Voreinstellung `MEDIUM` für die Mindestverzögerung zu beginnen und die Abonnementkonfiguration festzulegen, bevor die Wiedergabe beginnt.

Beachten Sie, dass die Mindestverzögerung nur angewendet wird, wenn ein Teilnehmer nur abonniert ist. Wenn ein Teilnehmer sicht selbst veröffentlicht, wird die Mindestverzögerung nicht angewendet. Dadurch soll sichergestellt werden, dass mehrere Publisher ohne zusätzliche Verzögerung miteinander sprechen können.

In den folgenden Beispielen wird die voreingestellte Mindestverzögerung `MEDIUM` verwendet. Alle möglichen Werte finden Sie in der SDK-Referenzdokumentation.

**Web**

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

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

**Android**

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

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

    return config;
}
```

**iOS**

```
func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration {
    let config = IVSSubscribeConfiguration()
    try! config.jitterBuffer.setMinDelay(.medium())
    return config
}
```

## Verkürzung der Zeit bis zum Video beim Wechseln zwischen den Stages
<a name="real-time-streaming-stage-switching"></a>

Mithilfe von Anwendungen können Benutzer möglicherweise einen Feed mit Live-Streams durchsuchen. Ein Benutzer tritt einer Stage bei, wechselt zu einem anderen Stream, verlässt die aktuelle stage und tritt schnell der nächsten bei. Das Erstellen einer neuen Verbindung für jeden Stage-Übergang erfordert das Einrichten einer neuen Netzwerkverbindung, wodurch sich die Zeit bis zur Verfügbarkeit von Video verlängern kann.

Verwenden Sie `RealTimeConnection`, um eine Netzwerkverbindung offen zu halten, während der Benutzer Streams durchsucht. Erstellen Sie die Verbindung einmal, stellen Sie sie optional vor dem Beitritt zur ersten Stage her und verwenden Sie sie Stage-übergreifend wieder. Jede Stage verwendet weiterhin ihr eigenes Teilnehmer-Token und verwaltet ihre eigenen Teilnehmer, Streams und ihren eigenen Lebenszyklus.

Erstellen und speichern Sie `RealTimeConnection` für die Dauer der Browsersitzung in einem Objekt, das eine einzelne Stage überdauert, z. B. einem Anwendungskoordinator, einem Navigationscontroller oder einem Anzeigemodell. Erstellen Sie es nicht bei jedem Stage-Übergang und trennen Sie die Verbindung.

**Android**

Im folgenden Beispiel wird der `RealTimeConnection`-Lebenszyklus dem im Android-Beispiel verwendeten MainViewModel hinzugefügt. Das Anzeigemodell implementiert Stage.Strategy und StageRenderer.

```
private var realTimeConnection: RealTimeConnection? = null
private var stage: Stage? = null

private fun setupConnection(connectionToken: String) {
    try {
        val connection = RealTimeConnection(getApplication(), connectionToken)

        // Establish the shared transport before the first Stage join.
        connection.connect()

        realTimeConnection = connection
    } catch (error: BroadcastException) {
        Log.e("BasicRealTime", "Unable to create the RealTimeConnection", error)
    }
}

private fun joinStage(participantToken: String) {
    val realTimeConnection = realTimeConnection ?: return

    try {
        stage?.leave()
        stage?.release()

        val stage = Stage(
            getApplication(),
            participantToken,
            realTimeConnection,
            this
        )
        stage.addRenderer(this)
        stage.join()

        this.stage = stage
    } catch (error: BroadcastException) {
        Log.e("BasicRealTime", "Unable to join the Stage", error)
    }
}

override fun onCleared() {
    stage?.leave()
    stage?.release()
    stage = null

    realTimeConnection?.disconnect()
    realTimeConnection?.release()
    realTimeConnection = null

    super.onCleared()
}
```

Das Aufrufen von `connect()` ist optional. Wenn die Verbindung nicht geöffnet ist, wenn Sie einer Stage beitreten, öffnet das SDK sie automatisch. Rufen Sie `connect()` vor dem Beitritt zur nächsten Stage auf, um die Verbindung im Voraus herzustellen und die Zeit bis zum Video zu verkürzen. In dem Beispiel wird zwar jeweils nur eine Verbindung zu einer Stage hergestellt, eine `RealTimeConnection` kann jedoch gleichzeitig mit mehreren Stages verbunden werden.

Rufen Sie `release()` auf, wenn die Anwendung `RealTimeConnection` nicht mehr benötigt. Nach der Veröffentlichung kann dies nicht wiederverwendet werden.

**iOS**

Im folgenden Beispiel wird davon ausgegangen, dass die Anwendung ein Verbindungstoken erhält, wenn der Benutzer den mehrstufigen Ablauf startet, und dass sie für jede Stage, der der Benutzer beitritt, ein Teilnehmer-Token erhält.

```
private var realTimeConnection: IVSRealTimeConnection?
private var stage: IVSStage?

private func setupConnection(connectionToken: String) throws {
    let connection = try IVSRealTimeConnection(token: connectionToken)

    // Establish the shared transport before the first Stage join.
    try connection.connect()

    realTimeConnection = connection
}

private func joinStage(participantToken: String) throws {
    guard let realTimeConnection else {
        return
    }

    stage?.leave()

    let stage = try IVSStage(
        token: participantToken,
        on: realTimeConnection,
        strategy: self
    )
    stage.addRenderer(self)
    try stage.join()

    self.stage = stage
}

private func endStageTransitionFlow() {
    stage?.leave()
    stage = nil

    realTimeConnection?.disconnect()
    realTimeConnection = nil
}
```

Das Aufrufen von `connect()` ist optional. Wenn die Verbindung nicht geöffnet ist, wenn Sie einer Stage beitreten, öffnet das SDK sie automatisch. Rufen Sie `connect()` vor dem Beitritt zur nächsten Stage auf, um die Verbindung im Voraus herzustellen und die Zeit bis zum Video zu verkürzen. Das Beispiel stellt zwar jeweils nur eine Verbindung zu einer Stage her, `IVSRealTimeConnection` kann aber gleichzeitig mit mehreren Stages verbunden werden.

Behalten Sie einen starken Verweis auf `IVSRealTimeConnection` bei, während die Stages es verwenden. Beim Aufrufen von `disconnect()` verlassen alle Stages die Verbindung, die sie verwenden.

## Empfohlene Optimierungen
<a name="real-time-streaming-optimization-suggested"></a>


| Szenario | Empfehlungen | 
| --- | --- | 
| Streams mit Text oder sich langsam bewegenden Inhalten wie Präsentationen oder Folien  | Verwenden Sie [für Simulcast die Codierung auf mehreren Ebenen](#real-time-streaming-optimization-adaptive) oder [konfigurieren Sie Streams mit einer niedrigeren Framerate](#real-time-streaming-changing-framerate).  | 
| Streams mit Action oder viel Bewegung | Verwenden Sie [für Simulcast die Codierung auf mehreren Ebenen](#real-time-streaming-optimization-adaptive).  | 
| Ströme mit Konversation oder wenig Bewegung  | Verwenden Sie [für Simulcast die Codierung auf mehreren Ebenen](#real-time-streaming-optimization-adaptive) oder wählen Sie „Nur Audio“ (siehe „Teilnehmer abonnieren“ in den SDK-Leitfäden für Echtzeit-Streaming-Broadcasts: [Web](web-publish-subscribe.md#web-publish-subscribe-concepts-strategy-participants), [Android](android-publish-subscribe.md#android-publish-subscribe-concepts-strategy-participants) und [iOS](ios-publish-subscribe.md#ios-publish-subscribe-concepts-strategy-participants).)  | 
| Nutzer streamen mit begrenztem Datenvolumen  | Verwenden Sie [für Simulcast die Codierung auf mehreren Ebenen](#real-time-streaming-optimization-adaptive) oder, wenn Sie eine geringere Datennutzung für alle wünschen, [konfigurieren Sie eine niedrigere Framerate](#real-time-streaming-changing-framerate) und [senken Sie die Bitrate manuell](#real-time-streaming-changing-bitrate).  | 
| Benutzer durchsuchen einen Feed mit Live-Streams und wechseln schnell von einer Stage zur nächsten  | Verwenden Sie ein RealTimeConnection für die Browsersitzung wieder. Rufen Sie connect() vor dem ersten Beitritt zu einer Stage auf, um die Verbindung im Voraus herzustellen.  | 