ExoPlayer unterstützt eine Vielzahl von Anforderungen an die Wiedergabeanalyse. Letztendlich geht es bei der Analyse um das Sammeln, Interpretieren, Aggregieren und Zusammenfassen von Daten aus Wiedergaben. Diese Daten können entweder auf dem Gerät verwendet werden – z. B. für Protokollierung, Fehlerbehebung oder zur Entscheidungsfindung bei zukünftigen Wiedergaben – oder an einen Server gesendet werden, um Wiedergaben auf allen Geräten zu überwachen.
In einem Analysesystem müssen in der Regel zuerst Ereignisse erfasst und dann weiterverarbeitet werden, damit sie aussagekräftig sind:
- Ereignisabfrage: Dazu können Sie eine
AnalyticsListener
in einerExoPlayer
-Instanz registrieren. Registrierte Analyse-Listener erhalten Ereignisse, die während der Nutzung des Players auftreten. Jedes Ereignis ist mit dem entsprechenden Medienelement in der Playlist sowie den Metadaten zur Wiedergabeposition und zum Zeitstempel verknüpft. - Ereignisverarbeitung: Einige Analysesysteme laden Rohereignisse auf einen Server hoch. Die gesamte Ereignisverarbeitung erfolgt dann serverseitig. Es ist auch möglich, Ereignisse auf dem Gerät zu verarbeiten. Das kann einfacher sein oder die Menge der hochzuladenden Informationen reduzieren. ExoPlayer bietet
PlaybackStatsListener
, mit dem Sie die folgenden Verarbeitungsschritte ausführen können:- Ereignisinterpretation: Damit Ereignisse für Analysen verwendet werden können, müssen sie im Kontext einer einzelnen Wiedergabe interpretiert werden. Das Rohereignis einer Spielerstatusänderung zu
STATE_BUFFERING
kann beispielsweise der anfänglichen Pufferung, einer erneuten Pufferung oder der Pufferung nach einem Suchvorgang entsprechen. - Status-Tracking: In diesem Schritt werden Ereignisse in Zähler umgewandelt. So können Statusänderungsereignisse beispielsweise in Zähler umgewandelt werden, mit denen erfasst wird, wie viel Zeit in jedem Wiedergabestatus verbracht wird. Das Ergebnis ist ein grundlegender Satz von Analysedatenwerten für eine einzelne Wiedergabe.
- Aggregation: In diesem Schritt werden die Analysedaten mehrerer Wiedergaben zusammengeführt, in der Regel durch Addition der Zähler.
- Berechnung von Zusammenfassungsmesswerten: Viele der nützlichsten Messwerte sind solche, mit denen Durchschnittswerte berechnet oder die grundlegenden Analysedaten auf andere Weise kombiniert werden. Zusammenfassungsmesswerte können für einzelne oder mehrere Wiedergaben berechnet werden.
- Ereignisinterpretation: Damit Ereignisse für Analysen verwendet werden können, müssen sie im Kontext einer einzelnen Wiedergabe interpretiert werden. Das Rohereignis einer Spielerstatusänderung zu
Ereigniserhebung mit AnalyticsListener
Die vom Player wiedergegebenen Rohdaten werden an AnalyticsListener
-Implementierungen gemeldet. Sie können ganz einfach einen eigenen Listener hinzufügen und nur die Methoden überschreiben, die Sie interessieren:
Kotlin
exoPlayer.addAnalyticsListener( object : AnalyticsListener { override fun onPlaybackStateChanged( eventTime: EventTime, @Player.State state: Int ) {} override fun onDroppedVideoFrames( eventTime: EventTime, droppedFrames: Int, elapsedMs: Long, ) {} } )
Java
exoPlayer.addAnalyticsListener( new AnalyticsListener() { @Override public void onPlaybackStateChanged( EventTime eventTime, @Player.State int state) {} @Override public void onDroppedVideoFrames( EventTime eventTime, int droppedFrames, long elapsedMs) {} });
Über EventTime
, das an jeden Callback übergeben wird, wird das Ereignis mit einem Medienelement in der Playlist sowie mit Wiedergabeposition und Zeitstempelmetadaten verknüpft:
realtimeMs
: Die Uhrzeit des Ereignisses.timeline
,windowIndex
undmediaPeriodId
: Hiermit werden die Playlist und das Element in der Playlist definiert, zu dem das Ereignis gehört.mediaPeriodId
enthält optionale zusätzliche Informationen, z. B. ob das Ereignis zu einer Anzeige im Element gehört.eventPlaybackPositionMs
: Die Wiedergabeposition im Artikel, an der das Ereignis aufgetreten ist.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
undcurrentPlaybackPositionMs
: Wie oben, aber für das gerade wiedergegebene Element. Das aktuell wiedergegebene Element kann sich von dem Element unterscheiden, zu dem das Ereignis gehört, z. B. wenn das Ereignis der Vorabpufferung des nächsten wiedergegebenen Elements entspricht.
Ereignisverarbeitung mit PlaybackStatsListener
PlaybackStatsListener
ist ein AnalyticsListener
, der die Ereignisverarbeitung auf dem Gerät implementiert. PlaybackStats
wird mit Zählern und abgeleiteten Messwerten berechnet, darunter:
- Zusammenfassungsmesswerte, z. B. die Gesamtwiedergabezeit.
- Messwerte zur adaptiven Wiedergabequalität, z. B. die durchschnittliche Videoauflösung.
- Rendering-Qualitätsmesswerte, z. B. die Rate der ausgelassenen Frames.
- Messwerte zur Ressourcennutzung, z. B. die Anzahl der über das Netzwerk gelesenen Byte.
Eine vollständige Liste der verfügbaren Zählungen und abgeleiteten Messwerte finden Sie in der PlaybackStats
Javadoc-Anleitung.
PlaybackStatsListener
berechnet separate PlaybackStats
für jedes Medienelement in der Playlist und jede clientseitige Anzeige, die in diese Elemente eingefügt wird. Du kannst einen Callback für PlaybackStatsListener
bereitstellen, um über beendete Wiedergaben informiert zu werden. Mit dem EventTime
, das an den Callback übergeben wurde, kannst du feststellen, welche Wiedergabe beendet ist. Du kannst die Analysedaten für mehrere Wiedergaben zusammenfassen. Es ist auch möglich, den PlaybackStats
für die aktuelle Wiedergabesitzung jederzeit mit PlaybackStatsListener.getPlaybackStats()
abzufragen.
Kotlin
exoPlayer.addAnalyticsListener( PlaybackStatsListener(/* keepHistory= */ true) { eventTime: EventTime?, playbackStats: PlaybackStats?, -> // Analytics data for the session started at `eventTime` is ready. } )
Java
exoPlayer.addAnalyticsListener( new PlaybackStatsListener( /* keepHistory= */ true, (eventTime, playbackStats) -> { // Analytics data for the session started at `eventTime` is ready. }));
Der Konstruktor von PlaybackStatsListener
bietet die Möglichkeit, den vollständigen Verlauf der verarbeiteten Ereignisse beizubehalten. Je nach Länge der Wiedergabe und Anzahl der Ereignisse kann dies zu einem unbekannten Arbeitsspeicheraufwand führen. Sie sollten sie daher nur aktivieren, wenn Sie Zugriff auf den vollständigen Verlauf der verarbeiteten Ereignisse und nicht nur auf die endgültigen Analysedaten benötigen.
Hinweis: Bei PlaybackStats
wird eine erweiterte Reihe von Status verwendet, um nicht nur den Status der Medien, sondern auch die Wiedergabeabsicht des Nutzers und detailliertere Informationen wie den Grund für die Unterbrechung oder Beendigung der Wiedergabe anzugeben:
Wiedergabestatus | Spielabsicht der Nutzer | Keine Absicht, zu spielen |
---|---|---|
Vor der Wiedergabe | JOINING_FOREGROUND |
NOT_STARTED , JOINING_BACKGROUND |
Aktive Wiedergabe | PLAYING |
|
Unterbrochene Wiedergabe | BUFFERING , SEEKING |
PAUSED , PAUSED_BUFFERING , SUPPRESSED , SUPPRESSED_BUFFERING , INTERRUPTED_BY_AD |
Endzustände | ENDED , STOPPED , FAILED , ABANDONED |
Die Wiedergabeabsicht des Nutzers ist wichtig, um Zeiten zu unterscheiden, in denen der Nutzer aktiv auf die Fortsetzung der Wiedergabe gewartet hat, von passiven Wartezeiten. PlaybackStats.getTotalWaitTimeMs
gibt beispielsweise die Gesamtzeit zurück, die im Status JOINING_FOREGROUND
, BUFFERING
und SEEKING
verbracht wurde, aber nicht die Zeit, in der die Wiedergabe pausiert wurde. In ähnlicher Weise gibt PlaybackStats.getTotalPlayAndWaitTimeMs
die Gesamtzeit mit der Nutzerabsicht zurück, also die gesamte aktive Wartezeit und die Gesamtzeit, die im Status PLAYING
verbracht wurde.
Verarbeitete und interpretierte Ereignisse
Sie können verarbeitete und interpretierte Ereignisse mit PlaybackStatsListener
und keepHistory=true
erfassen. Die resultierende PlaybackStats
enthält die folgenden Ereignislisten:
playbackStateHistory
: Eine sortierte Liste der erweiterten Wiedergabestatus mit demEventTime
, zu dem sie angewendet wurden. Sie können auchPlaybackStats.getPlaybackStateAtTime
verwenden, um den Status zu einem bestimmten Zeitpunkt abzurufen.mediaTimeHistory
: Ein Verlauf von Zeitpaaren aus Echtzeit und Medienzeit, mit dem Sie nachvollziehen können, welche Teile der Medien zu welcher Zeit abgespielt wurden. MitPlaybackStats.getMediaTimeMsAtRealtimeMs
kannst du auch die Wiedergabeposition zu einer bestimmten Uhrzeit abrufen.videoFormatHistory
undaudioFormatHistory
: Sortierte Listen der Video- und Audioformate, die während der Wiedergabe verwendet wurden, mit demEventTime
, ab dem sie verwendet wurden.fatalErrorHistory
undnonFatalErrorHistory
: sortierte Listen schwerwiegender und nicht schwerwiegender Fehler mit demEventTime
, zu dem sie aufgetreten sind. Schwerwiegende Fehler führen zur Beendigung der Wiedergabe, während nicht schwerwiegende Fehler möglicherweise wiederhergestellt werden können.
Analysedaten für die Wiedergabe einzelner Videos
Diese Daten werden automatisch erhoben, wenn Sie PlaybackStatsListener
verwenden, auch wenn Sie keepHistory=false
verwenden. Die endgültigen Werte sind die öffentlichen Felder, die du im PlaybackStats
-Javadoc findest, und die von getPlaybackStateDurationMs
zurückgegebene Dauer des Wiedergabestatus. Für den schnellen Zugriff gibt es auch Methoden wie getTotalPlayTimeMs
und getTotalWaitTimeMs
, mit denen die Dauer bestimmter Kombinationen von Wiedergabestatus zurückgegeben wird.
Kotlin
Log.d( "DEBUG", "Playback summary: " + "play time = " + playbackStats.totalPlayTimeMs + ", rebuffers = " + playbackStats.totalRebufferCount )
Java
Log.d( "DEBUG", "Playback summary: " + "play time = " + playbackStats.getTotalPlayTimeMs() + ", rebuffers = " + playbackStats.totalRebufferCount);
Analysedaten mehrerer Wiedergaben aggregieren
Sie können mehrere PlaybackStats
kombinieren, indem Sie PlaybackStats.merge
aufrufen. Die resultierende PlaybackStats
enthält die aggregierten Daten aller zusammengeführten Wiedergaben. Der Verlauf enthält jedoch nicht die einzelnen Wiedergabeereignisse, da diese nicht zusammengefasst werden können.
Mit PlaybackStatsListener.getCombinedPlaybackStats
können Sie eine aggregierte Ansicht aller Analysedaten abrufen, die während der Lebensdauer einer PlaybackStatsListener
erfasst wurden.
Berechnete zusammenfassende Messwerte
Neben den grundlegenden Analysedaten bietet PlaybackStats
viele Methoden zum Berechnen von Zusammenfassungsmesswerten.
Kotlin
Log.d( "DEBUG", "Additional calculated summary metrics: " + "average video bitrate = " + playbackStats.meanVideoFormatBitrate + ", mean time between rebuffers = " + playbackStats.meanTimeBetweenRebuffers )
Java
Log.d( "DEBUG", "Additional calculated summary metrics: " + "average video bitrate = " + playbackStats.getMeanVideoFormatBitrate() + ", mean time between rebuffers = " + playbackStats.getMeanTimeBetweenRebuffers());
Erweiterte Themen
Analysedaten mit Wiedergabemetadaten verknüpfen
Wenn du Analysedaten für einzelne Wiedergaben erhebst, kannst du die Analysedaten für die Wiedergabe mit Metadaten zu den wiedergegebenen Medien verknüpfen.
Wir empfehlen, medienspezifische Metadaten mit MediaItem.Builder.setTag
festzulegen.
Das Media-Tag ist Teil der EventTime
, die für Rohereignisse und für abgeschlossene PlaybackStats
erfasst werden. Es kann daher beim Umgang mit den entsprechenden Analysedaten ganz einfach abgerufen werden:
Kotlin
PlaybackStatsListener(/* keepHistory= */ false) { eventTime: EventTime, playbackStats: PlaybackStats -> val mediaTag = eventTime.timeline .getWindow(eventTime.windowIndex, Timeline.Window()) .mediaItem .localConfiguration ?.tag // Report playbackStats with mediaTag metadata. }
Java
new PlaybackStatsListener( /* keepHistory= */ false, (eventTime, playbackStats) -> { Object mediaTag = eventTime.timeline.getWindow(eventTime.windowIndex, new Timeline.Window()) .mediaItem .localConfiguration .tag; // Report playbackStats with mediaTag metadata. });
Berichte zu benutzerdefinierten Analytics-Ereignissen
Falls Sie den Analysedaten benutzerdefinierte Ereignisse hinzufügen müssen, müssen Sie diese Ereignisse in Ihrer eigenen Datenstruktur speichern und später mit dem gemeldeten PlaybackStats
kombinieren. Sie können DefaultAnalyticsCollector
erweitern, um EventTime
-Instanzen für Ihre benutzerdefinierten Ereignisse zu generieren und an die bereits registrierten Listener zu senden, wie im folgenden Beispiel gezeigt.
Kotlin
private interface ExtendedListener : AnalyticsListener { fun onCustomEvent(eventTime: EventTime) } private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) { fun customEvent() { val eventTime = generateCurrentPlayerMediaPeriodEventTime() sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener -> if (listener is ExtendedListener) { listener.onCustomEvent(eventTime) } } } } // Usage - Setup and listener registration. val player = ExoPlayer.Builder(context).setAnalyticsCollector(ExtendedCollector()).build() player.addAnalyticsListener( object : ExtendedListener { override fun onCustomEvent(eventTime: EventTime?) { // Save custom event for analytics data. } } ) // Usage - Triggering the custom event. (player.analyticsCollector as ExtendedCollector).customEvent()
Java
private interface ExtendedListener extends AnalyticsListener { void onCustomEvent(EventTime eventTime); } private static class ExtendedCollector extends DefaultAnalyticsCollector { public ExtendedCollector() { super(Clock.DEFAULT); } public void customEvent() { AnalyticsListener.EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime(); sendEvent( eventTime, CUSTOM_EVENT_ID, listener -> { if (listener instanceof ExtendedListener) { ((ExtendedListener) listener).onCustomEvent(eventTime); } }); } } // Usage - Setup and listener registration. ExoPlayer player = new ExoPlayer.Builder(context).setAnalyticsCollector(new ExtendedCollector()).build(); player.addAnalyticsListener( (ExtendedListener) eventTime -> { // Save custom event for analytics data. }); // Usage - Triggering the custom event. ((ExtendedCollector) player.getAnalyticsCollector()).customEvent();