

# IVS-Broadcast-SDK: Web-Handbuch \$1 Echtzeit-Streaming
<a name="broadcast-web"></a>

Das Web-Broadcast-SDK von IVS gibt Entwicklern die Werkzeuge an die Hand, um interaktive Echtzeit-Erlebnisse im Web zu schaffen. Dieses SDK ist für Entwickler gedacht, die Webanwendungen mit Amazon IVS erstellen.

Das Web-Broadcast-SDK ermöglicht es den Teilnehmern, Videos zu senden und zu empfangen. Das SDK unterstützt die folgenden Vorgänge:
+ Einer Stage beitreten
+ Medien für andere Teilnehmer auf der Stage veröffentlichen
+ Medien anderer Teilnehmer auf der Stage abonnieren
+ Auf der Stage veröffentlichte Videos und Audios verwalten und überwachen
+ WebRTC-Statistiken für jede Peer-Verbindung beziehen
+ Alle Operationen aus dem Web-Broadcast-SDK für IVS-Streaming mit niedriger Latenz

**Aktuelle Version des Web-Broadcast-SDK:** 1.33.0 ([Versionshinweise](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-web-rt)) 

**Referenzdokumentation:** Informationen zu den wichtigsten Methoden, die im Amazon IVS Web Broadcast SDK verfügbar sind, finden Sie unter [https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Stellen Sie sicher, dass die neueste Version des SDK ausgewählt ist.

**Beispielcode**: Die folgenden Beispiele sind ein guter Ausgangspunkt, um schnell mit dem SDK loszulegen:
+ [Einfache Wiedergabe](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [Einfaches Publishing und Abonnieren](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [Umfassende Demo zur Echtzeit-Zusammenarbeit in React](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**Plattformanforderungen**: Eine Liste der unterstützten Plattformen finden Sie unter [Amazon IVS Broadcast SDK](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html).

**Hinweis:** Die Veröffentlichung über einen Browser ist für Endbenutzer praktisch, da keine zusätzliche Software installiert werden muss. Die browserbasierte Veröffentlichung unterliegt jedoch den Einschränkungen und Schwankungen der Browser-Umgebungen. Wenn Stabilität für Sie Priorität hat (beispielsweise für Ereignis-Streaming) empfehlen wir generell die Veröffentlichung über eine Quelle außerhalb des Browsers (z. B. OBS Studio oder andere dedizierte Encoder), die oft direkten Zugriff auf Systemressourcen haben und Browser-Beschränkungen umgehen. Weitere Informationen zu Optionen der Veröffentlichung außerhalb des Browsers finden Sie in der Dokumentation zu [Stream Ingest](rt-stream-ingest.md).

# Erste Schritte mit dem IVS Web Broadcast SDK \$1 Streaming in Echtzeit
<a name="broadcast-web-getting-started"></a>

Dieses Dokument führt Sie durch die Schritte zum Einstieg in das Web Broadcast SDK von IVS-Streaming in Echtzeit.

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

Die Bausteine für Echtzeit befinden sich in einem anderen Namespace als die Root-Broadcasting-Module.

### Verwenden eines Skript-Tags
<a name="broadcast-web-getting-started-imports-script"></a>

Das Web Broadcast SDK wird als JavaScript-Bibliothek verteilt und kann unter [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) abgerufen werden.

Die in den folgenden Beispielen definierten Klassen und Aufzählungen befinden sich im globalen Objekt `IVSBroadcastClient`:

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

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

So installieren Sie das `npm`-Paket: 

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

Die Klassen, Enums und Typen können auch aus dem Paketmodul importiert werden:

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

### Serverseitige Rendering-Unterstützung
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

Die Stagebibliothek des Web-Broadcast-SDK kann nicht in einem serverseitigen Kontext geladen werden, da sie auf Browser-Primitive verweist, die für das Funktionieren der Bibliothek beim Laden erforderlich sind. Um dieses Problem zu umgehen, laden Sie die Bibliothek dynamisch, wie in der [Web-Broadcast-Demo mit „Next“ und „React“](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31) gezeigt.

## Berechtigungen anfordern
<a name="broadcast-web-request-permissions"></a>

Ihre App muss die Berechtigung für den Zugriff auf die Kamera und das Mikrofon des Benutzers anfordern und muss über HTTPS bereitgestellt werden. (Das gilt nicht nur für Amazon IVS, sondern für alle Websites, die Zugriff auf Kameras und Mikrofone benötigen.)

Die folgende Beispielfunktion zeigt, wie Sie Berechtigungen für Audio- und Videogeräte anfordern und erfassen können:

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

Weitere Informationen finden Sie in der [Berechtigungs-API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) und unter [MediaDevices.getUserMedia()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).

## Auflisten der verfügbaren Geräte
<a name="broadcast-web-request-list-devices"></a>

Um festzustellen, welche Geräte für die Erfassung verfügbar sind, fragen Sie die Methode [MediaDevices.enumerateDevices()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) des Browsers ab:

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

## Abrufen eines MediaStream von einem Gerät
<a name="broadcast-web-retrieve-mediastream"></a>

Nachdem Sie die Liste der verfügbaren Geräte erfasst haben, können Sie einen Stream von einer beliebigen Anzahl von Geräten abrufen. Sie können zum Beispiel mit der Methode `getUserMedia()` einen Stream von einer Kamera abrufen.

Wenn Sie angeben möchten, von welchem Gerät der Stream erfasst werden soll, können Sie die `deviceId` im Bereich `audio` oder `video` der Medieneinschränkungen explizit festlegen. Alternativ können Sie die `deviceId` weglassen und Benutzer ihre Geräte über die Eingabeaufforderung des Browsers auswählen lassen.

Zudem können Sie mithilfe der Einschränkungen `width` und `height` eine ideale Kameraauflösung angeben. (Mehr über diese Einschränkungen erfahren Sie [hier](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks).) Das SDK wendet automatisch die Einschränkungen für die Breite und Höhe an, die Ihrer maximalen Übertragungsauflösung entsprechen. Es empfiehlt sich jedoch, diese auch selbst anzuwenden, damit das Seitenverhältnis der Quelle nicht geändert wird, nachdem Sie sie dem SDK hinzugefügt haben.

Stellen Sie für Echtzeit-Streaming sicher, dass die Medienauflösung auf 720p beschränkt ist. Insbesondere dürfen Ihre `getUserMedia`- und `getDisplayMedia`-Beschränkungswerte für Breite und Höhe 921 600 (1280\$1720) nicht überschreiten, wenn sie miteinander multipliziert werden. 

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

# Veröffentlichen und Abonnieren mit dem IVS Web Broadcast SDK \$1 Streaming in Echtzeit
<a name="web-publish-subscribe"></a>

Dieses Dokument führt Sie durch die Schritte zum Veröffentlichen und Abonnieren einer Stage mit dem Web Broadcast SDK von IVS-Streaming in Echtzeit.

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

Drei Kernkonzepte liegen der Echtzeit-Funktionalität zugrunde: [Stage](#web-publish-subscribe-concepts-stage), [Strategie](#web-publish-subscribe-concepts-strategy) und [Ereignisse](#web-publish-subscribe-concepts-events). Das Designziel besteht in der Minimierung der Menge an clientseitiger Logik, die für die Entwicklung eines funktionierenden Produkts erforderlich ist.

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

Die Klasse `Stage` ist der Hauptinteraktionspunkt zwischen der Hostanwendung und dem SDK. Sie stellt die Stage selbst dar und dient dazu, der Stage beizutreten und sie zu verlassen. Für das Erstellen einer Stage und das Beitreten ist eine gültige, noch nicht abgelaufene Token-Zeichenfolge aus der Steuerebene erforderlich (dargestellt als `token`). Einer Stage beizutreten und sie zu verlassen, ist ganz einfach:

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

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

stage.leave();
```

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

Über die Schnittstelle `StageStrategy` kann die Hostanwendung dem SDK den gewünschten Status der Stage mitteilen. Drei Funktionen müssen implementiert werden: `shouldSubscribeToParticipant`, `shouldPublishParticipant` und `stageStreamsToPublish`. Alle werden im Folgenden behandelt.

Um eine definierte Strategie zu verwenden, übergeben Sie sie an den `Stage`-Konstruktor. Im Folgenden finden Sie ein vollständiges Beispiel für eine Anwendung, die mithilfe einer Strategie die Webcam eines Teilnehmers auf der Stage veröffentlicht und alle Teilnehmer abonniert. Der Zweck der einzelnen erforderlichen Strategiefunktionen wird in den folgenden Abschnitten ausführlich erläutert.

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

#### Abonnieren von Teilnehmern
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

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

Wenn ein Remote-Teilnehmer der Stage beitritt, fragt das SDK die Hostanwendung nach dessen gewünschtem Abonnementstatus. Die Optionen lauten `NONE`, `AUDIO_ONLY` und `AUDIO_VIDEO`. Wenn ein Wert für diese Funktion zurückgegeben wird, muss sich die Hostanwendung nicht um den Veröffentlichungs-, den aktuellen Abonnement- oder den Verbindungsstatus des Stage kümmern. Bei Rückgabe von `AUDIO_VIDEO` wartet das SDK mit dem Abonnieren, bis der Remote-Teilnehmer etwas veröffentlicht. Außerdem aktualisiert es die Hostanwendung, indem es während des gesamten Prozesses Ereignisse ausgibt.

Hier folgt ein Beispiel für eine Implementierung:

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

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

Hierbei handelt es sich um die vollständige Implementierung dieser Funktion für eine Hostanwendung, bei der sich alle Teilnehmer stets gegenseitig sehen sollen; z. B. eine Video-Chat-Anwendung.

Weitergehende Implementierungen sind ebenfalls möglich. Beispiel: Angenommen, die Anwendung stellt bei der Erstellung des Tokens mit CreateParticipantToken ein `role`-Attribut bereit. Die Anwendung könnte die `attributes`-Eigenschaft für `StageParticipantInfo` nutzen, um Teilnehmer anhand der vom Server bereitgestellten Attribute selektiv zu abonnieren:

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

Hiermit kann eine Stage erstellt werden, auf der Moderatoren alle Gäste überwachen können, ohne selbst gesehen oder gehört zu werden. Die Hostanwendung könnte eine zusätzliche Geschäftslogik nutzen, damit Moderatoren sich gegenseitig sehen können, für Gäste aber unsichtbar bleiben.

#### Konfiguration für das Abonnieren von Teilnehmern
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

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

Wenn ein Remote-Teilnehmer abonniert wird (siehe [Teilnehmer abonnieren](#web-publish-subscribe-concepts-strategy-participants)), fragt das SDK die Host-Anwendung nach einer benutzerdefinierten Abonnementkonfiguration für diesen Teilnehmer ab. Diese Konfiguration ist optional und ermöglicht es der Hostanwendung, bestimmte Aspekte des Subscriber-Verhaltens zu steuern. Informationen darüber, was konfiguriert werden kann, finden Sie unter [SubscribeConfiguration](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration) in der SDK-Referenzdokumentation.

Hier folgt ein Beispiel für eine Implementierung:

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

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

Diese Implementierung aktualisiert die Mindestverzögerung für den Jitter-Buffer für alle abonnierten Teilnehmer auf die Voreinstellung `MEDIUM`.

Wie bei `shouldSubscribeToParticipant` sind auch hier weitergehende Implementierungen möglich. Die `ParticipantInfo`-Angaben können verwendet werden, um die Abonnementkonfiguration für bestimmte Teilnehmer selektiv zu aktualisieren.

Wir empfehlen die Verwendung der Standardverhaltensweisen. Geben Sie die benutzerdefinierte Konfiguration nur an, wenn Sie ein bestimmtes Verhalten ändern möchten.

#### Veröffentlichen
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

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

Sobald die Verbindung zur Stage hergestellt ist, überprüft das SDK per Anfrage an die Hostanwendung, ob ein bestimmter Teilnehmer etwas veröffentlichen soll. Dies wird nur bei lokalen Teilnehmern aufgerufen, die auf Grundlage des bereitgestellten Tokens zur Veröffentlichung berechtigt sind.

Hier folgt ein Beispiel für eine Implementierung:

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

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

Sie ist für eine normale Video-Chat-Anwendung gedacht, bei der Benutzer immer etwas veröffentlichen möchten. Sie können die Audio- und Videowiedergabe stummschalten und die Stummschaltung aufheben, um umgehend ausgeblendet oder gesehen/gehört zu werden. (Sie können auch „Veröffentlichen/Veröffentlichung aufheben“ verwenden, was aber viel langsamer ist. „Stummschalten/Stummschalten aufheben“ ist für Anwendungsfälle vorzuziehen, in denen eine häufige Änderung der Sichtbarkeit wünschenswert ist.)

#### Auswählen von Streams zur Veröffentlichung
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

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

Beim Veröffentlichen wird hiermit bestimmt, welche Audio- und Videostreams veröffentlicht werden sollen. Dieser Punkt wird später unter [Veröffentlichen eines Medienstreams](#web-publish-subscribe-publish-stream) ausführlicher behandelt.

#### Aktualisieren der Strategie
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

Die Strategie soll dynamisch sein: Die von einer der oben genannten Funktionen zurückgegebenen Werte lassen sich jederzeit ändern. Wenn die Hostanwendung beispielsweise erst veröffentlichen soll, wenn der Endbenutzer auf eine Schaltfläche tippt, können Sie eine Variable aus `shouldPublishParticipant` zurückgeben (zum Beispiel `hasUserTappedPublishButton`). Wenn sich diese Variable aufgrund einer Interaktion des Endbenutzers ändert, signalisieren Sie dem SDK per Aufruf von `stage.refreshStrategy()`, dass es die Strategie nach den neuesten Werten abfragen und nur Dinge anwenden soll, die sich geändert haben. Wenn das SDK feststellt, dass sich der Wert `shouldPublishParticipant` geändert hat, startet es den Veröffentlichungsprozess. Wenn alle Funktionen bei einer SDK-Abfrage den gleichen Wert zurückgeben wie zuvor, wird die Stage mit dem Aufruf von `refreshStrategy` nicht geändert.

Ändert sich der Rückgabewert von `shouldSubscribeToParticipant` von `AUDIO_VIDEO` in `AUDIO_ONLY`, wird der Videostream für alle Teilnehmer mit geänderten Rückgabewerten entfernt, sofern zuvor ein Videostream vorhanden war.

Im Allgemeinen nutzt die Stage die Strategie, um den Unterschied zwischen der vorherigen und der aktuellen Strategie am effizientesten anzuwenden. Dabei muss sich die Hostanwendung nicht um die ganzen Status kümmern, die für eine ordnungsgemäße Verwaltung erforderlich sind. Stellen Sie sich den Aufruf von `stage.refreshStrategy()` daher als einen ressourcenschonenden Vorgang vor, da nur bei einer Änderung der Strategie etwas unternommen wird.

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

Eine `Stage`-Instance ist ein Ereignis-Emitter. Mit `stage.on()` wird der Hostanwendung der Status der Stage mitgeteilt. Aktualisierungen in der Benutzeroberfläche der Hostanwendung können in der Regel vollständig durch die Ereignisse unterstützt werden. Folgende Ereignisse werden unterstützt:

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

Für die meisten dieser Ereignisse wird die entsprechende `ParticipantInfo` bereitgestellt.

Es wird nicht erwartet, dass sich die von den Ereignissen bereitgestellten Informationen auf die Rückgabewerte der Strategie auswirken. Es wird beispielsweise nicht erwartet, dass sich der Rückgabewert von `shouldSubscribeToParticipant` beim Aufruf von `STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` ändert. Wenn die Hostanwendung einen bestimmten Teilnehmer abonnieren möchte, muss sie unabhängig von dessen Veröffentlichungsstatus den gewünschten Abonnementtyp zurückgeben. Das SDK muss dafür sorgen, dass entsprechend dem Status der Stage und dem gewünschten Status der Strategie zum richtigen Zeitpunkt gehandelt wird.

## Veröffentlichen eines Medienstreams
<a name="web-publish-subscribe-publish-stream"></a>

Lokale Geräte wie Mikrofone und Kameras werden mit den gleichen Schritten abgerufen, die oben unter [Abrufen eines MediaStream von einem Gerät](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream) beschrieben sind. In dem Beispiel erstellen wir mit `MediaStream` eine Liste von `LocalStageStream`-Objekten, die für die Veröffentlichung durch das SDK verwendet werden:

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

## Veröffentlichen einer Bildschirmfreigabe
<a name="web-publish-subscribe-publish-screenshare"></a>

Häufig müssen Anwendungen zusätzlich zur Webkamera des Benutzers eine Bildschirmfreigabe veröffentlichen. Das Veröffentlichen einer Bildschirmfreigabe erfordert die Erstellung eines zusätzlichen Tokens für die Stage, insbesonder für die Veröffentlichung der Medien der Bildschirmfreigabe. Verwenden Sie `getDisplayMedia` und beschränken Sie die Auflösung auf maximal 720p. Danach sind die Schritte ähnlich wie beim Veröffentlichen einer Kamera für die Stage.

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

## Anzeigen und Entfernen von Teilnehmern
<a name="web-publish-subscribe-participants"></a>

Nach Abschluss von Abonnements erhalten Sie über das Ereignis `STAGE_PARTICIPANT_STREAMS_ADDED` eine Reihe von `StageStream`-Objekten. Zudem stellt das Ereignis Teilnehmerinformationen bereit, die Ihnen beim Anzeigen von Medienstreams helfen:

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

Wenn ein Teilnehmer die Veröffentlichung beendet oder dessen Abonnement eines Streams beendet wird, wird die Funktion `STAGE_PARTICIPANT_STREAMS_REMOVED` mit den Streams aufgerufen, die entfernt wurden. Hostanwendungen sollten dies als Signal nutzen, um den Videostream des Teilnehmers aus dem DOM zu entfernen.

`STAGE_PARTICIPANT_STREAMS_REMOVED` wird für alle Szenarien aufgerufen, in denen ein Stream entfernt werden könnte, darunter:
+ Der Remote-Teilnehmer beendet die Veröffentlichung.
+ Ein lokales Gerät beendet das Abonnement oder ändert das Abonnement von `AUDIO_VIDEO` in `AUDIO_ONLY`.
+ Der Remote-Teilnehmer verlässt die Stage.
+ Der lokale Teilnehmer verlässt die Stage.

Da `STAGE_PARTICIPANT_STREAMS_REMOVED` bei allen Szenarien aufgerufen wird, ist keine benutzerdefinierte Geschäftslogik erforderlich, um Teilnehmer beim remoten oder lokalen Verlassen aus der Benutzeroberfläche zu entfernen.

## Stummschalten von Medienstreams und Aufheben der Stummschaltung
<a name="web-publish-subscribe-mute-streams"></a>

`LocalStageStream`-Objekte verfügen über eine `setMuted`-Funktion, die das Stummschalten des Streams steuert. Diese Funktion kann für den Stream aufgerufen werden, bevor oder nachdem er von der Strategiefunktion `stageStreamsToPublish` zurückgegeben wird.

**Wichtig**: Wenn nach einem Aufruf von `refreshStrategy` eine neue `LocalStageStream`-Objekt-Instance von `stageStreamsToPublish` zurückgegeben wird, wird der Stummschaltungsstatus des neuen Streamobjekts auf die Stage angewendet. Seien Sie vorsichtig beim Erstellen neuer `LocalStageStream`-Instances, um sicherzustellen, dass der erwartete Stummschaltungsstatus beibehalten wird.

## Überwachen des Medien-Stummschaltungsstatus von Remote-Teilnehmern
<a name="web-publish-subscribe-mute-state"></a>

Wenn Teilnehmer den Stummschaltungsstatus ihres Videos oder Audios ändern, wird das Ereignis `STAGE_STREAM_MUTE_CHANGED` mit einer Liste der Streams ausgelöst, die sich geändert haben. Verwenden Sie die Eigenschaft `isMuted` für `StageStream`, um die Benutzeroberfläche entsprechend zu aktualisieren:

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

Sie können auch unter [StageParticipantInfo](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo) nach Statusinformationen darüber suchen, ob Audio oder Video stummgeschaltet sind:

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

## Abrufen von WebRTC-Statistiken
<a name="web-publish-subscribe-webrtc-stats"></a>

Die Methode `requestQualityStats()` bietet Zugriff auf detaillierte WebRTC-Statistiken für lokale und Remote-Streams. Sie stehen für LocalStageStream- und für RemoteStageStream-Objekte zur Verfügung. Die Methode gibt umfassende Qualitätsmetriken zurück, darunter Netzwerkqualität, Paketstatistiken, Informationen zur Bitrate und einzelbildbezogene Metriken.

Hierbei handelt es sich um eine asynchrone Methode, mit der Sie Statistiken entweder über await oder durch Verkettung eines Promise abrufen können. Sind keine Statistiken verfügbar, gibt sie `undefined` zurück, z. B. wenn der Stream nicht aktiv ist oder interne Statistiken nicht verfügbar sind. Wenn Statistiken verfügbar sind, gibt die Methode je nach Stream (remote oder lokal, Video oder Audio) das Objekt [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) oder [RemoteAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteAudioStats) zurück.

Beachten Sie, dass das Array bei Videostreams mit Simulcast mehrere Statistikobjekte enthält (eines pro Schicht).

**Bewährte Methoden**
+ Abfragehäufigkeit – Rufen Sie `requestQualityStats()` in angemessenen Intervallen (1 bis 5 Sekunden) auf, um Leistungseinbußen zu vermeiden.
+ Fehlerbehandlung – Prüfen Sie vor der Verarbeitung stets, ob der zurückgegebene Wert `undefined` lautet.
+ Verwaltung des Arbeitsspeichers – Löschen Sie Intervalle/Timeouts, wenn Streams nicht mehr benötigt werden.
+ Netzwerkqualität – Nutzen Sie `networkQuality` für Benutzerfeedback zu möglichen Beeinträchtigungen, die vom Netzwerk verursacht werden. Einzelheiten finden Sie unter [NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality).

**Beispielverwendung**

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

## Optimieren von Medien
<a name="web-publish-subscribe-optimizing-media"></a>

Für eine optimale Leistung wird empfohlen, Aufrufe von `getUserMedia` und `getDisplayMedia` entsprechend den folgenden Einschränkungen zu begrenzen:

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

Sie können die Medien durch zusätzliche Optionen, die an den `LocalStageStream`-Konstruktor übergeben werden, weiter einschränken:

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

Im obigen Code:
+ `minBitrate` legt eine Mindestbitrate fest, die der Browser voraussichtlich verwenden sollte. Ein Videostream mit geringer Komplexität kann jedoch dazu führen, dass der Encoder diese Bitrate unterschreitet.
+ `maxBitrate` legt eine maximale Bitrate fest, von der erwartet werden sollte, dass sie vom Browser für diesen Stream nicht überschritten wird.
+ `maxFramerate` legt eine maximale Framerate fest, von der erwartet werden sollte, dass sie vom Browser für diesen Stream nicht überschritten wird.
+ Die Option `simulcast` ist nur in Chromium-basierten Browsern verwendbar. Sie ermöglicht das Senden von drei Wiedergabeebenen des Streams.
  + Auf diese Weise kann der Server anhand ihrer Netzwerkbeschränkungen auswählen, welche Wiedergabeversion an andere Teilnehmer gesendet werden soll.
  + Wenn `simulcast` zusammen mit einem `maxBitrate` und/oder `maxFramerate` Wert angegeben wird, wird erwartet, dass die höchste Wiedergabe-Ebene unter Berücksichtigung dieser Werte konfiguriert wird, vorausgesetzt, `maxBitrate` unterschreitet nicht die Standardeinstellung der zweithöchsten Ebene des internen SDK-Standardwerts `maxBitrate` von 900 kbps.
  + Wenn `maxBitrate` im Vergleich zum Standardwert der zweithöchsten Ebene als zu niedrig angegeben wird, wird `simulcast` deaktiviert.
  + `simulcast` kann nicht ein- und ausgeschaltet werden, ohne die Medien erneut zu veröffentlichen, indem `shouldPublishParticipant` `false` zurückgibt, `refreshStrategy` aufruft, `shouldPublishParticipant` `true` zurückgibt, und `refreshStrategy` wieder aufruft.

## Abrufen von Teilnehmerattributen
<a name="web-publish-subscribe-participant-attributes"></a>

Wenn Sie Attribute in der Vorgangsanfrage `CreateParticipantToken` angeben, können Sie die Attribute in den Eigenschaften von `StageParticipantInfo` einsehen:

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

## SEI (Supplemental Enhancement Information, Ergänzende Informationen zur Verbesserung)
<a name="web-publish-subscribe-sei-attributes"></a>

Die NAL-Einheit für Supplemental Enhancement Information (SEI) wird verwendet, um Frame-orientierte Metadaten zusammen mit dem Video zu speichern. Sie können beim Veröffentlichen und Abonnieren von H.264-Videostreams verwendet werden. Es kann nicht garantiert werden, dass SEI-Nutzdaten bei Subscribern ankommen, insbesondere bei schlechten Netzwerkbedingungen. Da die SEI-Nutzdaten direkt in der H.264-Frame-Struktur gespeichert werden, kann diese Funktion nicht für reine Audio-Streams genutzt werden.

### Einfügen von SEI-Nutzdaten
<a name="sei-attributes-inserting-sei-payloads"></a>

Veröffentlichende Clients können SEI-Nutzdaten in einen Stage-Stream einfügen, der gerade veröffentlicht wird, indem sie den LocalStageStream ihres Videos so konfigurieren, dass `inBandMessaging` aktiviert wird, und anschließend die Methode `insertSeiMessage` aufrufen. Beachten Sie, dass die Aktivierung von `inBandMessaging` die SDK-Speichernutzung erhöht.

[Nutzdaten müssen vom Typ ArrayBuffer sein.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) Die Nutzdaten müssen größer als 0 KB und kleiner als 1 KB sein. Die Anzahl der pro Sekunde eingefügten SEI-Nachrichten darf 10 KB pro Sekunde nicht überschreiten.

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

#### Sich wiederholende SEI-Nutzdaten
<a name="sei-attributes-repeating-sei-payloads"></a>

Geben Sie optional eine `repeatCount` an, um das Einfügen von SEI-Nutzdaten für die nächsten N gesendeten Frames zu wiederholen. Dies könnte hilfreich sein, um den inhärenten Verlust zu verringern, der aufgrund des zugrunde liegenden UDP-Transportprotokolls entstehen kann, das zum Senden von Videos verwendet wird. Beachten Sie, dass dieser Wert zwischen 0 und 30 liegen muss. Empfangende Clients müssen über eine Logik verfügen, um die Nachricht zu deduplizieren.

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

### Lesen von SEI-Nutzdaten
<a name="sei-attributes-reading-sei-payloads"></a>

Abonnierende Clients können SEI-Nutzdaten von einem Publisher lesen, der H.264-Videos veröffentlicht, sofern vorhanden. Dazu wird das `SubscribeConfiguration`-Element der Subscriber für die Aktivierung von `inBandMessaging` konfiguriert und auf das `StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED`-Ereignis gelauscht, wie im folgenden Beispiel gezeigt:

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

## Mehrschichtige Kodierung mit Simulcast
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

Bei der mehrschichtigen Kodierung mit Simulcast handelt es sich um ein Feature für IVS-Echtzeit-Streaming, mit dessen Hilfe Publisher mehrere Videoschichten unterschiedlicher Qualität senden können. Subscriber können diese Schichten dynamisch oder manuell ändern. Das Feature wird im Dokument [Streaming-Optimierungen](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html) ausführlicher beschrieben.

### Konfigurieren mehrschichtiger Kodierung (Publisher)
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

Um als Publisher die mehrschichtige Kodierung mit Simulcast zu aktivieren, fügen Sie dem `LocalStageStream` bei der Instanziierung die folgende Konfiguration hinzu:

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

Je nach Eingangsauflösung der Kamera wird eine festgelegte Anzahl von Schichten kodiert und gesendet, wie im Abschnitt [Standardmäßige Schichten, Qualitäten und Bildraten](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers) von *Streaming-Optimierungen* definiert.

Außerdem können Sie optional einzelne Ebenen innerhalb der Simulcast-Konfiguration konfigurieren:

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

Alternativ können Sie eigene benutzerdefinierte Ebenenkonfigurationen für bis zu drei Ebenen erstellen. Wenn Sie ein leeres Array oder keinen Wert angeben, werden die oben beschriebenen Standardwerte verwendet. Ebenen werden mit den folgenden erforderlichen Eigenschaften beschrieben:
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

Ausgehend von den Voreinstellungen können Sie entweder einzelne Eigenschaften überschreiben oder eine völlig neue Konfiguration erstellen:

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

Informationen zu Höchstwerten, Grenzwerten und Fehlern, die bei der Konfiguration einzelner Ebenen ausgelöst werden können, finden Sie in der SDK-Referenzdokumentation.

### Konfigurieren mehrschichtiger Kodierung (Subscriber)
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

Subscriber müssen nichts unternehmen, um die mehrschichtige Kodierung zu aktivieren. Wenn ein Publisher Simulcast-Schichten sendet, passt sich der Server standardmäßig dynamisch den Schichten an, um je nach Gerät und Netzwerkbedingungen des Subscribers die optimale Qualität auszuwählen.

Alternativ gibt es mehrere nachfolgend beschriebene Optionen, um explizite Schichten auszuwählen, die der Publisher sendet.

### Option 1: Einstellung für die Qualität der Anfangsschicht
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

Mit der Strategie `subscribeConfiguration` können Sie auswählen, welche Anfangsschicht Sie als Subscriber erhalten möchten:

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

Standardmäßig wird Subscribern zunächst immer die Schicht mit der niedrigsten Qualität gesendet. Nach und nach wird die Qualität gesteigert, bis die Schicht mit der höchsten Qualität erreicht ist. Das optimiert den Bandbreitenverbrauch der Endbenutzer, verkürzt die Zeit bis zum Abspielen des Videos und verringert das anfängliche Einfrieren von Videos bei Benutzern in Netzwerken mit geringerer Bandbreite.

Folgende Optionen sind für `InitialLayerPreference` verfügbar:
+ `LOWEST_QUALITY` – Der Server stellt zuerst die Videoschicht mit der niedrigsten Qualität bereit. Dadurch werden der Bandbreitenverbrauch und die Zeit bis zum Abspielen von Medien optimiert. Die Qualität ist definiert als die Kombination aus Größe, Bitrate und Bildrate des Videos. Beispielsweise weisen 720p-Videos eine geringere Qualität auf als 1080p-Videos.
+ `HIGHEST_QUALITY` – Der Server stellt zuerst die Videoschicht mit der höchsten Qualität bereit. Das optimiert die Qualität, kann aber die Zeit bis zum Abspielen von Medien verlängern. Die Qualität ist definiert als die Kombination aus Größe, Bitrate und Bildrate des Videos. Beispielsweise weisen 1080p-Videos eine höhere Qualität auf als 720p-Videos.

**Hinweis:** Damit die anfänglichen Schichteinstellungen (der Aufruf `initialLayerPreference`) wirksam werden, muss ein neues Abonnement abgeschlossen werden, da diese Updates für das aktive Abonnement nicht gelten.



### Option 2: Bevorzugte Schicht für Streams
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

Sobald ein Stream gestartet wurde, können Sie die Strategiemethode `preferredLayerForStream ` nutzen. Diese Strategiemethode legt den Teilnehmer und die Stream-Informationen offen.

Die Strategiemethode kann mit folgenden Elementen zurückgegeben werden:
+ dem Schichtobjekt direkt, basierend auf der Rückgabe von `RemoteStageStream.getLayers` 
+ der Bezeichnung des Schichtobjekts, basierend auf `StageStreamLayer.label`
+ undefiniert oder null, was bedeutet, dass keine Schicht ausgewählt werden sollte und eine dynamische Anpassung bevorzugt wird

Bei der folgenden Strategie wählen die Benutzer beispielsweise immer die Videoschicht mit der niedrigsten verfügbaren Qualität aus:

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

Um die Schichtauswahl zurückzusetzen und zur dynamischen Anpassung zurückzukehren, geben Sie in der Strategie null oder undefiniert zurück. In diesem Beispiel ist `appState` eine Dummy-Variable, die den möglichen Anwendungsstatus darstellt.

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

### Option 3: Helferobjekte für RemoteStageStream-Schicht
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream` weist mehrere Helferobjekte auf, mit deren Hilfe Entscheidungen über die Schichtauswahl getroffen und Endbenutzern die entsprechende Auswahl angezeigt werden kann:
+ **Schichtereignisse** – Neben `StageEvents` verfügt das Objekt `RemoteStageStream` selbst über Ereignisse, die Änderungen bei der Schicht- und Simulcast-Anpassung kommunizieren:
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **Schichtmethoden** – `RemoteStageStream` verfügt über mehrere Helfermethoden, mit denen Informationen über den Stream und die präsentierten Schichten abgerufen werden können. Diese Methoden sind sowohl für den in der Strategie `preferredLayerForStream ` bereitgestellten Remote-Stream als auch für Remote-Streams verfügbar, die über `StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED` verfügbar gemacht werden.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

Einzelheiten finden Sie im Abschnitt zur Klasse `RemoteStageStream` in der [SDK-Referenzdokumentation](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Falls als Grund für `LAYER_SELECTED` `UNAVAILABLE` zurückgegeben wird, bedeutet das, dass die angeforderte Schicht nicht ausgewählt werden konnte. Stattdessen wird eine bestmögliche Auswahl getroffen. Dabei handelt es sich in der Regel um eine Schicht mit niedrigerer Qualität, um die Stabilität des Streams zu gewährleisten.

## Umgang mit Netzwerkproblemen
<a name="web-publish-subscribe-network-issues"></a>

Bei Unterbrechung der Netzwerkverbindung des lokalen Geräts versucht das SDK intern, die Verbindung ohne Benutzeraktion wiederherzustellen. In einigen Fällen ist das SDK nicht erfolgreich, weshalb eine Benutzeraktion erforderlich ist.

Generell kann der Status der Stage über das Ereignis `STAGE_CONNECTION_STATE_CHANGED` gesteuert werden:

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

Im Allgemeinen können Sie einen fehlerhaften Status ignorieren, der nach dem erfolgreichen Beitritt zu einer Stage auftritt, da das SDK versuchen wird, die Verbindung intern wiederherzustellen. Wenn das SDK einen `ERRORED`-Status meldet und die Stage über einen längeren Zeitraum (z. B. 30 Sekunden oder länger) im `CONNECTING`-Status verbleibt, sind Sie wahrscheinlich vom Netzwerk getrennt worden.

## Übertragung der Stage auf einen IVS-Kanal
<a name="web-publish-subscribe-broadcast-stage"></a>

Zum Übertragen einer Stage erstellen Sie eine separate `IVSBroadcastClient`-Sitzung und folgen Sie dann den oben beschriebenen üblichen Anweisungen für die Übertragung mit dem SDK. Mithilfe der Liste der über `STAGE_PARTICIPANT_STREAMS_ADDED` offengelegten `StageStream` können die Medienstreams der Teilnehmer abgerufen werden, die wie folgt auf die Zusammensetzung der übertragenen Streams angewendet werden können:

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

Optional können Sie eine Stage zusammenstellen und sie auf einen IVS-Kanal mit niedriger Latenz übertragen, um ein größeres Publikum zu erreichen. Sehen Sie [Aktivierung mehrerer Hosts in einem Amazon-IVS-Stream](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html) im Benutzerhandbuch für IVS-Streaming mit niedriger Latenz.

# Bekannte Probleme und Behelfslösungen im IVS Web Broadcast SDK \$1 Streaming in Echtzeit
<a name="broadcast-web-known-issues"></a>

In diesem Dokument werden bekannte Probleme aufgeführt, die bei der Verwendung des Web Broadcast SDK von Amazon-IVS-Streaming in Echtzeit auftreten können, und es werden mögliche Problemumgehungen vorgeschlagen.
+ Wenn Browser-Tabs oder Browser ohne Aufruf von `stage.leave()` geschlossen werden, können Benutzer noch bis zu 10 Sekunden lang mit einem eingefrorenen Frame oder einem schwarzen Bildschirm in der Sitzung zu sehen sein.

  **Problemumgehung:** Keine.
+ Safari-Sitzungen werden für Benutzer, die nach Beginn einer Sitzung beitreten, mitunter mit einem schwarzen Bildschirm angezeigt.

  **Problemumgehung:** Aktualisieren Sie den Browser und stellen Sie die Verbindung zur Sitzung erneut her.
+ Safari stellt Sitzungen bei einem Netzwerkwechsel nicht ordnungsgemäß wieder her.

  **Problemumgehung:** Aktualisieren Sie den Browser und stellen Sie die Verbindung zur Sitzung erneut her.
+ Die Entwicklerkonsole wiederholt den Fehler `Error: UnintentionalError at StageSocket.onClose`.

  **Problemumgehung:** Pro Teilnehmertoken kann nur eine Stage erstellt werden. Dieser Fehler tritt auf, wenn mehr als eine `Stage`-Instance mit demselben Teilnehmertoken erstellt wird, unabhängig davon, ob sich die Instance auf einem oder mehreren Geräten befindet.
+ Es kann zu Problemen bei der Aufrechterhaltung eines `StageParticipantPublishState.PUBLISHED`-Status kommen und Sie können wiederholte `StageParticipantPublishState.ATTEMPTING_PUBLISH`-Status erhalten, wenn Sie das Ereignis `StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` abhören.

  **Umgehung:** Beschränken Sie die Videoauflösung auf 720p, wenn Sie `getUserMedia` oder `getDisplayMedia` aufrufen. Insbesondere dürfen Ihre `getUserMedia`- und `getDisplayMedia`-Beschränkungswerte für Breite und Höhe 921 600 (1280\$1720) nicht überschreiten, wenn sie miteinander multipliziert werden.
+ Wenn `stage.leave()` aufgerufen wird oder ein Remote-Teilnehmer die Stage verlässt, wird in der Debug-Konsole des Browsers der Fehler „404 DELETE“ angezeigt.

  **Problemumgehung:** Keine. Hierbei handelt es sich um einen harmlosen Fehler.

## Einschränkungen von Safari
<a name="broadcast-web-safari-limitations"></a>
+ Wenn bei einer entsprechenden Aufforderung die Erteilung einer Berechtigung verweigert wird, muss die Berechtigung in den Einstellungen auf der Safari-Website auf Betriebssystemebene zurückgesetzt werden.
+ Safari erkennt nicht alle Geräte nativ so effektiv wie Firefox oder Chrome. OBS Virtual Camera wird beispielsweise nicht erkannt.

## Einschränkungen von Firefox
<a name="broadcast-web-firefox-limitations"></a>
+ Damit Firefox den Bildschirm freigeben kann, müssen Systemberechtigungen aktiviert sein. Nach deren Aktivierung muss Firefox neu gestartet werden, damit es ordnungsgemäß funktioniert. Andernfalls löst der Browser eine [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions)-Ausnahme aus, wenn Berechtigungen als gesperrt betrachtet werden.
+ Die Methode `getCapabilities` fehlt. Das bedeutet, dass Benutzer die Auflösung oder das Seitenverhältnis der Medienspur nicht abrufen können. Weitere Informationen finden Sie in diesem [Bugzilla-Thread](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084).
+ Es fehlen mehrere `AudioContext`-Eigenschaften, z. B. die Latenz und die Kanalanzahl. Dies könnte für erfahrene Benutzer, die die Audiospuren bearbeiten möchten, ein Problem darstellen.
+ Kamera-Feeds von `getUserMedia` sind unter macOS auf ein Seitenverhältnis von 4:3 beschränkt. Weitere Informationen finden Sie im [Bugzilla-Thread 1](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640) und im [Bugzilla-Thread 2](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034).
+ Die Audioerfassung wird mit `getDisplayMedia` nicht unterstützt. Weitere Informationen finden Sie in diesem [Bugzilla-Thread](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425).
+ Die Framerate bei der Bildschirmerfassung ist suboptimal (ungefähr 15 Bilder pro Sekunde?). Weitere Informationen finden Sie in diesem [Bugzilla-Thread](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522).

## Einschränkungen im mobilen Web
<a name="broadcast-web-mobile-web-limitations"></a>
+ Die Bildschirmfreigabe von [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility) wird auf Mobilgeräten nicht unterstützt.

  **Problemumgehung:** Keine.
+ Beim Schließen eines Browsers dauert es 15 bis 30 Sekunden, bis der Teilnehmer den Browser verlässt, ohne `leave()` aufzurufen.

  **Problemumgehung**: Fügen Sie eine Benutzeroberfläche hinzu, die Benutzer dazu ermutigt, die Verbindung ordnungsgemäß zu trennen.
+ Die Hintergrund-App führt dazu, dass die Veröffentlichung von Videos beendet wird.

  **Problemumgehung**: Zeigen Sie ein UI-Slate an, wenn der Publisher angehalten ist.
+ Nach dem Aufheben der Stummschaltung einer Kamera auf Android-Geräten sinkt die Video-Framerate für etwa 5 Sekunden.

  **Problemumgehung:** Keine.
+ Der Video-Feed wird bei der Rotation für iOS 16.0 gestreckt.

  **Problemumgehung**: Zeigen Sie eine Benutzeroberfläche an, die dieses bekannte Betriebssystemproblem beschreibt.
+ Beim Wechseln des Audio-Eingabegeräts wird automatisch auch das Audio-Ausgabegerät umgeschaltet.

  **Problemumgehung:** Keine.
+ Wenn der Browser in den Hintergrund gestellt wird, wird der Veröffentlichungsstream schwarz und es wird nur Audio erzeugt.

  **Problemumgehung:** Keine. Dies geschieht aus Sicherheitsgründen.

# Fehlerbehandlung im IVS Web Broadcast SDK \$1 Streaming in Echtzeit
<a name="broadcast-web-error-handling"></a>

Dieser Abschnitt gibt einen Überblick über die Fehlerbedingungen, wie das Web-Broadcast-SDK sie an die Anwendung meldet und wie eine Anwendung reagieren sollte, wenn diese Fehler auftreten. Fehler werden vom SDK an die Listener des `StageEvents.ERROR`-Ereignisses gemeldet:

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

## Stagefehler
<a name="web-error-handling-stage-errors"></a>

Ein StageError-Fehler wird gemeldet, wenn das SDK auf ein Problem stößt, das nicht behoben werden kann und für dessen Behebung im Allgemeinen ein Eingreifen der App und/oder eine erneute Netzwerkverbindung erforderlich ist.

Jeder gemeldete `StageError` hat einen Code (oder `StageErrorCode`), eine Meldung (Zeichenfolge) und eine Kategorie (`StageErrorCategory`). Alles davon bezieht sich auf eine zugrunde liegende Vorgangskategorie.

Die Vorgangskategorie des Fehlers wird danach bestimmt, ob er mit der Verbindung zur Stage (`JOIN_ERROR`), dem Senden von Medien an die Stage (`PUBLISH_ERROR`) oder dem Empfangen eines eingehenden Medienstreams von der Stage (`SUBSCRIBE_ERROR`) zusammenhängt.

Die Codeeigenschaft eines `StageError` meldet das spezifische Problem:


| Name | Code | Empfohlene Aktion | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | Erstellen Sie ein gültiges Token und versuchen Sie erneut, die Stage zu instanziieren. | 
| TOKEN\$1EXPIRED | 2 | Erstellen Sie ein noch nicht abgelaufenes Token und versuchen Sie erneut, die Stage zu instanziieren. | 
| TIMEOUT | 3 | Bei der Operation ist eine Zeitüberschreitung aufgetreten. Wenn die Stage vorhanden und das Token gültig ist, handelt es sich bei diesem Fehler wahrscheinlich um ein Netzwerkproblem. Warten Sie in diesem Fall, bis die Konnektivität des Geräts wiederhergestellt ist. | 
| FEHLGESCHLAGEN | 4 | Beim Versuch, einen Vorgang auszuführen, ist ein schwerwiegender Fehler aufgetreten. Überprüfen Sie Fehlerdetails. Wenn die Stage vorhanden und das Token gültig ist, handelt es sich bei diesem Fehler wahrscheinlich um ein Netzwerkproblem. Warten Sie in diesem Fall, bis die Konnektivität des Geräts wiederhergestellt ist. Bei den meisten Fehlern im Zusammenhang mit der Netzwerkstabilität versucht das SDK intern für einen Zeitraum von bis zu 30 Sekunden erneut, eine Verbindung herzustellen, bevor ein FAILED-Fehler ausgegeben wird.  | 
| CANCELED | 5 | Überprüfen Sie den Anwendungscode und stellen Sie sicher, dass es keine wiederholten `join`-, `refreshStrategy`- oder `replaceStrategy`-Aufrufe gibt, die dazu führen könnten, dass wiederholte Vorgänge gestartet und vor Abschluss abgebrochen werden. | 
| STAGE\$1AT\$1CAPACITY | 6 | Dieser Fehler weist darauf hin, dass die Stage oder Ihr Konto voll ausgelastet ist. Falls die Stage das Teilnehmerlimit erreicht hat, wiederholen Sie den Vorgang, wenn die Stage nicht mehr voll ausgelastet ist, indem Sie die Strategie aktualisieren. Wenn Ihr Konto das Kontingent für gleichzeitige Abonnements oder Publisher erreicht hat, reduzieren Sie die Nutzung oder fordern Sie über die [AWS-Service-Quotas-Konsole](https://console.aws.amazon.com/servicequotas/) eine Erhöhung des Kontingents an.  | 
| CODEC\$1MISMATCH | 7 | Der Codec wird von der Stage nicht unterstützt. Überprüfen Sie den Browser und die Plattform auf Codec-Unterstützung. Für IVS-Echtzeit-Streaming müssen Browser den H.264-Codec für Video und den Opus-Codec für Audio unterstützen. | 
| TOKEN\$1NOT\$1ALLOWED | 8 | Das Token hat keine Berechtigung für den Vorgang. Erstellen Sie das Token mit den richtigen Berechtigungen neu und versuchen Sie es erneut. | 
| STAGE\$1DELETED | 9 | Keine; der Versuch, einer gelöschten Stage beizutreten, löst diesen Fehler aus. | 
| PARTICIPANT\$1DISCONNECTED | 10 | Keine; der Versuch, mit dem Token eines Teilnehmers beizutreten, dessen Verbindung getrennt wurde, löst diesen Fehler aus. | 

### Beispiel für die Behandlung von StageError
<a name="web-error-handling-stage-errors-example"></a>

Verwenden Sie den StageError-Code, um festzustellen, ob der Fehler auf ein abgelaufenes Token zurückzuführen ist:

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

### Netzwerkfehler, wenn bereits eine Verbindung hergestellt wurde
<a name="web-error-handling-stage-errors-network"></a>

Wenn die Netzwerkverbindung des Geräts ausfällt, verliert das SDK möglicherweise die Verbindung zu den Stageservern. Möglicherweise werden in der Konsole Fehler angezeigt, da das SDK die Backend-Dienste nicht mehr erreichen kann. POSTs auf https://broadcast.stats.live-video.net schlagen fehl.

Wenn Sie etwas veröffentlichen und/oder abonnieren, werden in der Konsole Fehler angezeigt, die sich auf Versuche beziehen, etwas zu veröffentlichen/zu abonnieren.

Intern versucht das SDK, die Verbindung mithilfe einer exponentiellen Backoff-Strategie wiederherzustellen.

**Aktion**: Warten Sie, bis die Konnektivität des Geräts wiederhergestellt ist.

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

Es wird empfohlen, diese Status für die Anwendungsprotokollierung zu verwenden und Benutzern Nachrichten anzuzeigen, die sie über Verbindungsprobleme mit der Stage für einen bestimmten Teilnehmer informieren.

### Veröffentlichen
<a name="errored-states-publish"></a>

Das SDK meldet `ERRORED`, wenn eine Veröffentlichung fehlschlägt.

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

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

Das SDK meldet `ERRORED`, wenn ein Abonnement fehlschlägt. Dies kann auf Netzwerkbedingungen zurückzuführen sein oder wenn eine Stage für Abonnenten ausgelastet ist.

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