ExoPlayer spielt die meisten adaptiven Livestreams sofort ohne spezielle Konfiguration ab. Weitere Informationen finden Sie auf der Seite Unterstützte Formate.
Adaptive Livestreams bieten ein Fenster mit verfügbaren Medien, das in regelmäßigen Intervallen aktualisiert wird, um sich mit der aktuellen Echtzeit zu bewegen. Das bedeutet, dass sich die Wiedergabeposition immer irgendwo in diesem Fenster befindet, und zwar in den meisten Fällen nahe bei der aktuellen Echtzeit, in der der Stream produziert wird. Die Differenz zwischen der aktuellen Echtzeit und der Wiedergabeposition wird als Live-Offset bezeichnet.
Live-Wiedergaben erkennen und beobachten
Jedes Mal, wenn ein Live-Fenster aktualisiert wird, erhalten registrierte Player.Listener
-Instanzen ein onTimelineChanged
-Ereignis. Du kannst Details zur aktuellen Livewiedergabe abrufen, indem du verschiedene Player
- und Timeline.Window
-Methoden abfragen, wie unten aufgeführt und in der folgenden Abbildung dargestellt.
Player.isCurrentWindowLive
gibt an, ob das aktuell wiedergegebene Medienelement ein Livestream ist. Dieser Wert gilt auch dann, wenn der Livestream bereits beendet ist.Player.isCurrentWindowDynamic
gibt an, ob das aktuell wiedergegebene Medienelement noch aktualisiert wird. Dies gilt in der Regel für noch nicht beendete Livestreams. Dieses Flag gilt in manchen Fällen auch für Nicht-Livestreams.Player.getCurrentLiveOffset
gibt den Versatz zwischen der aktuellen Echtzeit und der Wiedergabeposition (falls verfügbar) zurück.Player.getDuration
gibt die Länge des aktuellen Live-Fensters zurück.Player.getCurrentPosition
gibt die Wiedergabeposition relativ zum Beginn des Live-Fensters zurück.Player.getCurrentMediaItem
gibt das aktuelle Medienelement zurück, wobeiMediaItem.liveConfiguration
von der App bereitgestellte Überschreibungen für die Parameter des Ziel-Live-Offsets und der Live-Offset-Anpassung enthält.Player.getCurrentTimeline
gibt die aktuelle Medienstruktur in einemTimeline
-Element zurück. Die aktuelleTimeline.Window
kann mitPlayer.getCurrentWindowIndex
undTimeline.getWindow
aus demTimeline
abgerufen werden. InWindow
:Window.liveConfiguration
enthält die Parameter für den Live-Zieloffset und die Live-Offsetanpassung. Diese Werte basieren auf Informationen in den Medien und allen von Apps bereitgestellten Überschreibungen, die inMediaItem.liveConfiguration
festgelegt sind.Window.windowStartTimeMs
ist die Zeit seit der Unix-Epoche, zu der das Live-Fenster beginnt.Window.getCurrentUnixTimeMs
ist die Zeit seit der Unix-Epoche der aktuellen Echtzeit. Dieser Wert kann um eine bekannte Zeitdifferenz zwischen Server und Client korrigiert werden.Window.getDefaultPositionMs
ist die Position im Live-Fenster, an der der Player die Wiedergabe standardmäßig startet.
Suche in Livestreams
Mit Player.seekTo
können Sie zu einer beliebigen Stelle im Live-Fenster springen. Die übergebene Suchposition bezieht sich auf den Beginn des Live-Fensters. So sucht seekTo(0)
beispielsweise zum Anfang des Live-Fensters. Der Player versucht, denselben Live-Offset wie die angesteuerte Position nach einem Suchvorgang beizubehalten.
Das Live-Fenster hat auch eine Standardposition, an der die Wiedergabe starten soll. Diese Position befindet sich normalerweise nahe am Live-Edge. Um zur Standardposition zu wechseln, rufen Sie Player.seekToDefaultPosition
auf.
Benutzeroberfläche für die Live-Wiedergabe
Die Standard-UI-Komponenten von ExoPlayer zeigen die Dauer des Live-Fensters und die aktuelle Wiedergabeposition darin. Das bedeutet, dass die Position bei jeder Aktualisierung des Live-Fensters rückwärts springt. Wenn Sie ein anderes Verhalten benötigen, z. B. die Unix-Zeit oder den aktuellen Live-Offset, können Sie PlayerControlView
verzweigen und an Ihre Anforderungen anpassen.
Parameter für die Live-Wiedergabe konfigurieren
ExoPlayer verwendet einige Parameter, um den Offset der Wiedergabeposition vom Live-Edge aus zu steuern sowie den Bereich der Wiedergabegeschwindigkeiten, mit dem dieser Offset angepasst werden kann.
ExoPlayer ruft die Werte für diese Parameter von drei Stellen in absteigender Reihenfolge nach Priorität ab (der erste gefundene Wert wird verwendet):
- Pro
MediaItem
werden Werte anMediaItem.Builder.setLiveConfiguration
übergeben. - Globale Standardwerte wurden für
DefaultMediaSourceFactory
festgelegt. - Werte werden direkt aus dem Medium gelesen.
Kotlin
// Global settings. val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build() // Per MediaItem settings. val mediaItem = MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build() ) .build() player.setMediaItem(mediaItem)
Java
// Global settings. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build(); // Per MediaItem settings. MediaItem mediaItem = new MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()) .build(); player.setMediaItem(mediaItem);
Verfügbare Konfigurationswerte sind:
targetOffsetMs
: Der Live-Ziel-Offset. Der Player wird versuchen, während der Wiedergabe möglichst nahe an diesen Live-Offset zu kommen.minOffsetMs
: Das minimal zulässige Live-Offset. Auch wenn der Offset an die aktuellen Netzwerkbedingungen angepasst wird, versucht der Player nicht, diesen Offset während der Wiedergabe zu unterschreiten.maxOffsetMs
: Der maximal zulässige Live-Offset. Auch wenn der Offset an die aktuellen Netzwerkbedingungen angepasst wird, versucht der Player nicht, diesen Offset während der Wiedergabe zu überschreiten.minPlaybackSpeed
: Die minimale Wiedergabegeschwindigkeit, die der Player für einen Fallback verwenden kann, wenn versucht wird, den Ziel-Live-Offset zu erreichen.maxPlaybackSpeed
: Die maximale Wiedergabegeschwindigkeit, die der Player verwenden kann, um den Zielwert für den Live-Offset zu erreichen.
Anpassung der Wiedergabegeschwindigkeit
Beim Abspielen eines Livestreams mit niedriger Latenz passt ExoPlayer den Live-Offset durch eine leichte Änderung der Wiedergabegeschwindigkeit an. Der Player versucht, den von den Medien oder der App angegebenen Ziel-Live-Offset zu erreichen, versucht aber auch, auf sich ändernde Netzwerkbedingungen zu reagieren. Wenn es beispielsweise während der Wiedergabe zu einer Neupufferung kommt, verlangsamt der Player die Wiedergabe leicht, um sich weiter weg vom Live-Edge zu bewegen. Wenn das Netzwerk dann stabil genug wird, um wieder näher am Live-Edge zu spielen, beschleunigt der Player die Wiedergabe, um zum Ziel-Live-Offset zurückzukehren.
Wenn die automatische Anpassung der Wiedergabegeschwindigkeit nicht erwünscht ist, kannst du sie deaktivieren, indem du die Eigenschaften minPlaybackSpeed
und maxPlaybackSpeed
auf 1.0f
setzt.
Ebenso kann es für Livestreams ohne niedrige Latenz aktiviert werden. Dazu setzen Sie sie explizit auf andere Werte als 1.0f
. Weitere Informationen zum Festlegen dieser Attribute finden Sie im Abschnitt zur Konfiguration oben.
Algorithmus zur Anpassung der Wiedergabegeschwindigkeit anpassen
Wenn die Geschwindigkeitsanpassung aktiviert ist, definiert ein LivePlaybackSpeedControl
, welche Anpassungen vorgenommen werden. Es ist möglich, eine benutzerdefinierte LivePlaybackSpeedControl
zu implementieren oder die Standardimplementierung DefaultLivePlaybackSpeedControl
anzupassen. In beiden Fällen kann beim Erstellen des Players eine Instanz festgelegt werden:
Kotlin
val player = ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build() ) .build()
Java
ExoPlayer player = new ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( new DefaultLivePlaybackSpeedControl.Builder() .setFallbackMaxPlaybackSpeed(1.04f) .build()) .build();
Für DefaultLivePlaybackSpeedControl
sind folgende Anpassungsparameter relevant:
fallbackMinPlaybackSpeed
undfallbackMaxPlaybackSpeed
: Die minimalen und maximalen Wiedergabegeschwindigkeiten, die zur Anpassung verwendet werden können, wenn weder das Medium noch die von der App bereitgestellteMediaItem
Limits definieren.proportionalControlFactor
: Steuert, wie gleichmäßig die Geschwindigkeitsanpassung erfolgt. Ein hoher Wert führt dazu, dass Anpassungen plötzlicher und reaktiver sind, aber auch mit größerer Wahrscheinlichkeit hörbar sind. Ein kleinerer Wert führt zu einem flüssigeren Übergang zwischen den Geschwindigkeiten, allerdings auf Kosten einer geringeren Geschwindigkeit.targetLiveOffsetIncrementOnRebufferMs
: Dieser Wert wird bei jeder Neuzwischenspeicherung zum Ziel-Live-Offset hinzugefügt, um vorsichtiger fortzufahren. Diese Funktion kann deaktiviert werden, indem Sie den Wert auf 0 setzen.minPossibleLiveOffsetSmoothingFactor
: Ein exponentieller Glättungsfaktor, mit dem das minimal mögliche Live-Offset auf Basis der aktuell zwischengespeicherten Medien verfolgt wird. Ein Wert sehr nahe 1 bedeutet, dass die Schätzung vorsichtiger ist und länger dauern kann, um sich an verbesserte Netzwerkbedingungen anzupassen. Ein niedrigerer Wert bedeutet hingegen, dass die Schätzung schneller angepasst wird und ein höheres Risiko besteht, dass es zu Puffern kommt.
BehindLiveWindowException und ERROR_CODE_Behind_LIVE_WINDOW
Die Wiedergabeposition kann hinter das Live-Fenster fallen, z. B. wenn der Player pausiert ist oder lange genug gepuffert wird. In diesem Fall schlägt die Wiedergabe fehl und über Player.Listener.onPlayerError
wird eine Ausnahme mit dem Fehlercode ERROR_CODE_BEHIND_LIVE_WINDOW
gemeldet. Der Anwendungscode möchte diese Fehler möglicherweise beheben, indem die Wiedergabe an der Standardposition fortgesetzt wird. Die PlayerActivity der Demo-App veranschaulicht diesen Ansatz.
Kotlin
override fun onPlayerError(error: PlaybackException) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition() player.prepare() } else { // Handle other errors } }
Java
@Override public void onPlayerError(PlaybackException error) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition(); player.prepare(); } else { // Handle other errors } }