ExoPlayer spielt die meisten adaptiven Livestreams direkt und ohne spezielle Konfiguration ab. Weitere Informationen finden Sie auf der Seite Unterstützte Formate.
Bei adaptiven Livestreams wird ein Fenster mit verfügbaren Medien angezeigt, das in regelmäßigen Abständen aktualisiert wird, um die aktuelle Echtzeit widerzuspiegeln. Das bedeutet, dass sich die Wiedergabeposition immer irgendwo in diesem Fenster befindet und in den meisten Fällen in den meisten Fällen annähernd der aktuellen Echtzeit entspricht, in der der Stream produziert wird. Die Differenz zwischen der aktuellen Echtzeit und der Wiedergabeposition wird als Live-Offset bezeichnet.
Erkennen und Überwachen von Livewiedergaben
Jedes Mal, wenn ein Livefenster aktualisiert wird, erhalten registrierte Player.Listener
-Instanzen ein onTimelineChanged
-Ereignis. Details zur aktuellen Livewiedergabe kannst du mithilfe verschiedener Player
- und Timeline.Window
-Methoden abrufen, die unten aufgeführt und in der folgenden Abbildung dargestellt sind.
Player.isCurrentWindowLive
gibt an, ob es sich bei dem gerade wiedergegebenen Medienelement um einen Livestream handelt. Dieser Wert gilt auch dann, wenn der Livestream beendet ist.Player.isCurrentWindowDynamic
gibt an, ob das aktuell wiedergegebene Medienelement noch aktualisiert wird. Das ist in der Regel bei Livestreams der Fall, die noch nicht beendet sind. Hinweis: Dieses Flag gilt in einigen Fällen auch für nicht live übertragene Streams.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-Tracking-Zeitraums zurück.Player.getCurrentPosition
gibt die Wiedergabeposition relativ zum Beginn des Live-Zeitfensters zurück.Player.getCurrentMediaItem
gibt das aktuelle Medienelement zurück.MediaItem.liveConfiguration
enthält von der App bereitgestellte Überschreibungen für die Parameter „Ziel-Live-Offset“ und „Anpassung des Live-Offsets“.Player.getCurrentTimeline
gibt die aktuelle Medienstruktur in einerTimeline
zurück. Der aktuelleTimeline.Window
kann mitPlayer.getCurrentMediaItemIndex
undTimeline.getWindow
aus demTimeline
abgerufen werden. Im BereichWindow
:Window.liveConfiguration
enthält die Parameter für den Ziel-Live-Offset und die Anpassung des Live-Offsets. Diese Werte basieren auf Informationen in den Medien und allen von der App bereitgestellten Überschreibungen, die inMediaItem.liveConfiguration
festgelegt wurden.Window.windowStartTimeMs
ist der Zeitpunkt seit der Unix-Epoche, zu dem das Live-Fenster beginnt.Window.getCurrentUnixTimeMs
ist der Zeitpunkt seit der Unix-Epoche der aktuellen Echtzeit. Dieser Wert kann durch eine bekannte Zeitabweichung zwischen dem Server und dem Client korrigiert werden.Window.getDefaultPositionMs
ist die Position im Live-Fenster, an der der Player die Wiedergabe standardmäßig startet.
In Livestreams vor- und zurückspringen
Mit Player.seekTo
kannst du dir eine beliebige Stelle im Live-Fenster ansehen. Die übergebene Position für die Suche bezieht sich auf den Beginn des Live-Zeitfensters. Mit seekTo(0)
kannst du beispielsweise zum Anfang des Live-Streams springen. Der Spieler versucht, den Live-Versatz wie an der Position, zu der nach einer Suche gesucht wird, beizubehalten.
Das Livefenster hat auch eine Standardposition, an der die Wiedergabe beginnen soll. Diese Position befindet sich normalerweise in der Nähe des aktiven Rands. Sie können Player.seekToDefaultPosition
aufrufen, um zur Standardposition zu springen.
Benutzeroberfläche für die Wiedergabe von Livestreams
Die standardmäßigen UI-Komponenten von ExoPlayer zeigen die Dauer des Live-Zeitfensters und die aktuelle Wiedergabeposition darin an. Das bedeutet, dass die Position jedes Mal, wenn das Livefenster aktualisiert wird, scheinbar zurückspringt. Wenn Sie ein anderes Verhalten benötigen, z. B. die Unix-Zeit oder den aktuellen Live-Offset anzeigen lassen möchten, können Sie PlayerControlView
forken und nach Ihren Wünschen anpassen.
Parameter für die Livewiedergabe konfigurieren
ExoPlayer verwendet einige Parameter, um den Versatz der Wiedergabeposition vom Live-Rand und den Bereich der Wiedergabegeschwindigkeiten zu steuern, mit dem dieser Versatz angepasst werden kann.
ExoPlayer ruft Werte für diese Parameter an drei Stellen ab, in absteigender Prioritätsreihenfolge (der erste gefundene Wert wird verwendet):
- Pro
MediaItem
-Wert, der anMediaItem.Builder.setLiveConfiguration
übergeben wird. - Globale Standardwerte, die unter
DefaultMediaSourceFactory
festgelegt wurden. - Werte, die direkt aus den Medien gelesen werden.
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:
targetOffsetMs
: Der Ziel-Live-Offset. Der Player versucht nach Möglichkeit, während der Wiedergabe an diesen Live-Offset zu kommen.minOffsetMs
: Der zulässige Mindest-Live-Offset. Auch wenn der Offset an die aktuellen Netzwerkbedingungen angepasst wird, versucht der Player während der Wiedergabe nicht, unter diesen Offset zu fallen.maxOffsetMs
: Der maximal zulässige Live-Offset. Auch wenn der Offset an die aktuellen Netzwerkbedingungen angepasst wird, versucht der Player während der Wiedergabe nicht, diesen Offset zu überschreiten.minPlaybackSpeed
: Die minimale Wiedergabegeschwindigkeit, auf die der Player zurückgreifen kann, wenn er versucht, den Ziel-Live-Offset zu erreichen.maxPlaybackSpeed
: Die maximale Wiedergabegeschwindigkeit, mit der der Player den aktuellen Live-Zeitpunkt erreichen kann.
Anpassung der Wiedergabegeschwindigkeit
Bei der Wiedergabe eines Livestreams mit niedriger Latenz passt ExoPlayer den Live-Offset an, indem er die Wiedergabegeschwindigkeit leicht ändert. Der Player versucht, den vom Medium oder der App bereitgestellten Ziel-Live-Offset anzupassen, reagiert aber auch auf sich ändernde Netzwerkbedingungen. Wenn beispielsweise während der Wiedergabe ein erneutes Puffern auftritt, verlangsamt der Player die Wiedergabe etwas, bis der Live-Rand weiter weg ist. Wenn das Netzwerk dann stabil genug ist, um die Wiedergabe wieder näher am Live-Edge zu unterstützen, beschleunigt der Player die Wiedergabe, um wieder auf den Ziel-Live-Offset zuzusteuern.
Wenn die automatische Anpassung der Wiedergabegeschwindigkeit nicht gewünscht ist, kannst du sie deaktivieren, indem du die Properties minPlaybackSpeed
und maxPlaybackSpeed
auf 1.0f
setzt.
Ebenso kann sie für Livestreams ohne niedrige Latenz aktiviert werden, indem du für diese Livestreams explizit andere Werte als 1.0f
festlegst. Weitere Informationen zum Festlegen dieser Properties finden Sie oben im Abschnitt „Konfiguration“.
Algorithmus zur Anpassung der Wiedergabegeschwindigkeit anpassen
Wenn die Geschwindigkeitsanpassung aktiviert ist, wird mit einer LivePlaybackSpeedControl
festgelegt, welche Anpassungen vorgenommen werden. Sie können einen benutzerdefinierten LivePlaybackSpeedControl
implementieren oder die Standardimplementierung anpassen, die DefaultLivePlaybackSpeedControl
ist. 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();
Relevante Anpassungsparameter von DefaultLivePlaybackSpeedControl
sind:
fallbackMinPlaybackSpeed
undfallbackMaxPlaybackSpeed
: Die minimale und maximale Wiedergabegeschwindigkeit, die zur Anpassung verwendet werden kann, wenn weder die Medien noch die von der App bereitgestellteMediaItem
Grenzen festlegen.proportionalControlFactor
: Bestimmt, wie flüssig die Geschwindigkeit angepasst wird. Ein hoher Wert führt zu abrupteren und schnelleren Anpassungen, die aber auch eher hörbar sind. Ein kleinerer Wert führt zu einem flüssigeren Übergang zwischen den Geschwindigkeiten, aber zu einer geringeren Geschwindigkeit.targetLiveOffsetIncrementOnRebufferMs
: Dieser Wert wird dem Ziel-Live-Offset hinzugefügt, wenn ein erneutes Puffern auftritt, um vorsichtiger vorzugehen. Diese Funktion kann deaktiviert werden, indem Sie den Wert auf „0“ setzen.minPossibleLiveOffsetSmoothingFactor
: Ein exponentieller Glättefaktor, mit dem der minimal mögliche Live-Offset basierend auf den derzeit gepufferten Medien erfasst wird. Ein Wert, der sehr nahe an 1 liegt, bedeutet, dass die Schätzung vorsichtiger ist und es möglicherweise länger dauert, bis sie sich an verbesserte Netzwerkbedingungen anpasst. Ein niedrigerer Wert bedeutet, dass sich die Schätzung schneller anpasst, aber das Risiko von Pufferungen höher ist.
BehindLiveWindowException und ERROR_CODE_BEHIND_LIVE_WINDOW
Die Wiedergabeposition kann hinter dem Live-Window zurückfallen, z. B. wenn der Player pausiert oder für einen längeren Zeitraum 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 kann solche Fehler behandeln, 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 } }