Veröffentlichen und Abonnieren mit dem IVS Android Broadcast SDK | Streaming in Echtzeit - Amazon IVS

Veröffentlichen und Abonnieren mit dem IVS Android Broadcast SDK | Streaming in Echtzeit

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

Konzepte

Drei Kernkonzepte liegen der Echtzeit-Funktionalität zugrunde: Stage, Strategie und Renderer. Das Designziel besteht in der Minimierung der Menge an clientseitiger Logik, die für die Entwicklung eines funktionierenden Produkts erforderlich ist.

Stufe

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

Stage stage = new Stage(context, token, strategy); try { stage.join(); } catch (BroadcastException exception) { // handle join exception } stage.leave();

In der Klasse Stage erfolgt auch das Anhängen des StageRenderer:

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

Strategie

Über die Schnittstelle Stage.Strategy kann die Hostanwendung dem SDK den gewünschten Status der Bühne mitteilen. Drei Funktionen müssen implementiert werden: shouldSubscribeToParticipant, shouldPublishFromParticipant und stageStreamsToPublishForParticipant. Alle werden im Folgenden behandelt.

Abonnieren von Teilnehmern

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

Wenn ein Remote-Teilnehmer der Bühne 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 Bühne kümmern. Bei Rückgabe von AUDIO_VIDEO wartet das SDK mit dem Abonnieren, bis der Remote-Teilnehmer etwas veröffentlicht. Außerdem aktualisiert das SDK die Hostanwendung während des gesamten Prozesses über den Renderer.

Hier folgt ein Beispiel für eine Implementierung:

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

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. Nutzen Sie die Eigenschaft userInfo für ParticipantInfo, um Teilnehmer anhand der vom Server bereitgestellten Attribute selektiv zu abonnieren:

@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; } }

Hiermit kann eine Bühne 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

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

Wenn ein Remote-Teilnehmer abonniert wird (siehe Teilnehmer abonnieren), 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 in der SDK-Referenzdokumentation.

Hier folgt ein Beispiel für eine Implementierung:

@Override public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) { SubscribeConfiguration config = new SubscribeConfiguration(); config.jitterBuffer.setMinDelay(JitterBufferConfiguration.JitterBufferDelay.MEDIUM()); return config; }

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

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

Sobald die Verbindung zur Bühne 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:

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

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

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

Beim Veröffentlichen wird hiermit bestimmt, welche Audio- und Videostreams veröffentlicht werden sollen. Dieser Punkt wird später unter Veröffentlichen eines Medienstreams ausführlicher behandelt.

Aktualisieren der Strategie

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 shouldPublishFromParticipant 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 shouldPublishFromParticipant geändert hat, startet es den Veröffentlichungsprozess. Wenn alle Funktionen bei einer SDK-Abfrage den gleichen Wert zurückgeben wie zuvor, werden mit dem Aufruf von refreshStrategy keine Änderungen an der Bühne durchgeführt.

Ä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 Bühne 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.

Renderer

Die Schnittstelle StageRenderer teilt der Hostanwendung den Status der Bühne mit. Aktualisierungen in der Benutzeroberfläche der Hostanwendung können in der Regel vollständig über die vom Renderer bereitgestellten Ereignisse gesteuert werden. Der Renderer stellt die folgenden Funktionen bereit:

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

Für die meisten dieser Methoden werden die entsprechende Stage und ParticipantInfo bereitgestellt.

Es wird nicht erwartet, dass sich die vom Renderer bereitgestellten Informationen auf die Rückgabewerte der Strategie auswirken. Es wird beispielsweise nicht erwartet, dass sich der Rückgabewert von shouldSubscribeToParticipant beim Aufruf von onParticipantPublishStateChanged ä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 Bühne und dem gewünschten Status der Strategie zum richtigen Zeitpunkt gehandelt wird.

Der StageRenderer kann der Bühnenklasse angefügt werden:

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

Hinweis: Nur veröffentlichende Teilnehmer lösen onParticipantJoined aus. Wenn Teilnehmer die Veröffentlichung beenden oder die Bühnensitzung verlassen, wird onParticipantLeft ausgelöst.

Veröffentlichen eines Medienstreams

Lokale Geräte wie eingebaute Mikrofone und Kameras werden über DeviceDiscovery erkannt. Hier folgt ein Beispiel für die Auswahl der nach vorne gerichteten Kamera und des Standardmikrofons und deren anschließende Rückgabe als LocalStageStreams zur Veröffentlichung durch das 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; }

Anzeigen und Entfernen von Teilnehmern

Nach Abschluss von Abonnements erhalten Sie über die Funktion onStreamsAdded des Renderers eine Reihe von StageStream-Objekten. Sie können die Vorschau von einem ImageStageStream abrufen:

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

Außerdem können Sie die Statistiken des Audiolevels von einem AudioStageStream abrufen:

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

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

onStreamsRemoved 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 Bühne.

  • Der lokale Teilnehmer verlässt die Bühne.

Da onStreamsRemoved 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

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 streamsToPublishForParticipant zurückgegeben wird.

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

Überwachen des Medien-Stummschaltungsstatus von Remote-Teilnehmern

Wenn ein Teilnehmer den Stummschaltungsstatus seines Video- oder Audiostreams ändert, wird die Funktion onStreamMutedChanged des Renderers mit einer Liste der Streams aufgerufen, die sich geändert haben. Verwenden Sie die Methode getMuted für StageStream, um die Benutzeroberfläche entsprechend zu aktualisieren.

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

Abrufen von WebRTC-Statistiken

Um die neuesten WebRTC-Statistiken für einen veröffentlichten oder abonnierten Stream abzurufen, verwenden Sie requestRTCStats für StageStream. Nach Abschluss einer Erfassung erhalten Sie Statistiken über den StageStream.Listener, der für StageStream eingestellt werden kann.

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

Abrufen von Teilnehmerattributen

Wenn Sie Attribute in der Endpunktanfrage CreateParticipantToken angeben, können Sie die Attribute in den Eigenschaften von ParticipantInfo einsehen:

@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()); } }

Fortsetzen der Sitzung im Hintergrund

Wenn die App in den Hintergrund wechselt, können Sie die Veröffentlichung beenden oder das Abonnement auf das Audio anderer Remote-Teilnehmer beschränken. Dazu aktualisieren Sie die Implementierung Ihrer Strategy, um die Veröffentlichung zu beenden und AUDIO_ONLY zu abonnieren (oder gegebenenfalls NONE).

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

Aktivieren/Deaktivieren der mehrschichtigen Kodierung mit Simulcast

Bei der Veröffentlichung eines Medienstreams überträgt das SDK Videostreams in hoher und niedriger Qualität, sodass externe Teilnehmer den Stream abonnieren können, auch wenn sie nur über eine begrenzte Downlink-Bandbreite verfügen. Die mehrschichtige Kodierung mit Simulcast ist standardmäßig aktiviert. Sie können sie deaktivieren, indem Sie die StageVideoConfiguration.Simulcast-Klasse verwenden:

// Disable Simulcast StageVideoConfiguration config = new StageVideoConfiguration(); config.simulcast.setEnabled(false); ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config); // Other Stage implementation code

Einschränkungen der Videokonfiguration

Das SDK unterstützt kein Erzwingen des Hoch- oder Querformats mit StageVideoConfiguration.setSize(BroadcastConfiguration.Vec2 size). Im Hochformat wird die kleinere Dimension als Breite verwendet, im Querformat als Höhe. Das bedeutet, dass die folgenden beiden Aufrufe von setSize die gleiche Auswirkung auf die Videokonfiguration haben:

StageVideo Configuration config = new StageVideo Configuration(); config.setSize(BroadcastConfiguration.Vec2(720f, 1280f); config.setSize(BroadcastConfiguration.Vec2(1280f, 720f);

Umgang mit Netzwerkproblemen

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. Es gibt zwei Hauptfehler im Zusammenhang mit der Unterbrechung der Netzwerkverbindung:

  • Fehlercode 1400, Meldung: „Die PeerConnection wurde aufgrund eines unbekannten Netzwerkfehlers unterbrochen.“

  • Fehlercode 1300, Meldung: „Die Zahl der Wiederholungsversuche ist ausgeschöpft.“

Wenn der erste Fehler empfangen wird, der zweite jedoch nicht, ist das SDK immer noch mit der Bühne verbunden und versucht, die Verbindungen automatisch wiederherzustellen. Zur Sicherheit können Sie refreshStrategy ohne Änderungen an den Rückgabewerten der Strategiemethode aufrufen, um einen manuellen Neuverbindungsversuch auszulösen.

Wenn der zweite Fehler empfangen wird, sind die Neuverbindungsversuche des SDK fehlgeschlagen und das lokale Gerät ist nicht mehr mit der Bühne verbunden. Versuchen Sie in diesem Fall, der Bühne erneut beizutreten, indem Sie join aufrufen, nachdem die Netzwerkverbindung wiederhergestellt wurde.

Im Allgemeinen deutet das Auftreten von Fehlern nach dem erfolgreichen Beitritt zu einer Bühne darauf hin, dass das SDK beim Wiederherstellen einer Verbindung nicht erfolgreich war. Erstellen Sie ein neues Stage-Objekt und versuchen Sie, der Bühne beizutreten, wenn sich die Netzwerkbedingungen verbessern.

Verwenden von Bluetooth-Mikrofonen

Um mit Bluetooth-Mikrofongeräten zu veröffentlichen, müssen Sie eine Bluetooth-SCO-Verbindung herstellen:

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