ExoPlayer unterstützt eine Vielzahl von Anforderungen an Wiedergabeanalysen. Letztendlich geht es bei Analysen um das Erfassen, 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 für zukünftige Wiedergabeentscheidungen – oder an einen Server gemeldet werden, um Wiedergaben auf allen Geräten zu überwachen.
Ein Analysesystem muss normalerweise zuerst Ereignisse erfassen und diese dann weiter verarbeiten, um sie aussagekräftig zu machen:
- Ereigniserfassung: Dazu können Sie ein
AnalyticsListener
in einerExoPlayer
-Instanz registrieren. Registrierte Analyse-Listener empfangen Ereignisse, wenn sie während der Nutzung des Players auftreten. Jedes Ereignis ist mit dem entsprechenden Medienelement in der Playlist sowie mit den Metadaten der Wiedergabeposition und des Zeitstempels verknüpft. - Ereignisverarbeitung: Einige Analysesysteme laden Rohereignisse auf einen Server hoch, wobei die gesamte Ereignisverarbeitung serverseitig erfolgt. Es ist auch möglich, Ereignisse auf dem Gerät zu verarbeiten, was einfacher ist oder die Menge der Informationen, die hochgeladen werden muss, reduziert. ExoPlayer stellt
PlaybackStatsListener
bereit, mit dem Sie die folgenden Verarbeitungsschritte ausführen können:- Ereignisinterpretation: Ereignisse müssen für Analysezwecke im Kontext einer einzelnen Wiedergabe interpretiert werden. Beispielsweise kann das Rohereignis einer Player-Statusänderung in
STATE_BUFFERING
einer anfänglichen Pufferung, einer erneuten Zwischenspeicherung oder einer Zwischenspeicherung nach einer Suche entsprechen. - Status-Tracking: In diesem Schritt werden Ereignisse in Zähler umgewandelt. Beispielsweise können Statusänderungsereignisse in Zähler umgewandelt werden, die erfassen, 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 aus mehreren Wiedergaben kombiniert. In der Regel werden dabei Zähler addiert.
- Berechnung der zusammenfassenden Messwerte: Zu den nützlichsten Messwerten zählen die, mit denen Durchschnittswerte berechnet oder die grundlegenden Analysedatenwerte auf andere Weise kombiniert werden. Zusammenfassende Messwerte können für einzelne oder mehrere Wiedergaben berechnet werden.
- Ereignisinterpretation: Ereignisse müssen für Analysezwecke im Kontext einer einzelnen Wiedergabe interpretiert werden. Beispielsweise kann das Rohereignis einer Player-Statusänderung in
Ereigniserfassung mit AnalyticsListener
Unformatierte Wiedergabeereignisse aus dem Player werden an AnalyticsListener
-Implementierungen gemeldet. Sie können einfach Ihren eigenen Listener hinzufügen und nur die für Sie relevanten Methoden überschreiben:
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) {} });
Die EventTime
, die an jeden Callback übergeben wird, verknüpft das Ereignis mit einem Medienelement in der Playlist sowie mit den Metadaten der Wiedergabeposition und des Zeitstempels:
realtimeMs
: Die tatsächlich verstrichene Zeit der Veranstaltung.timeline
,windowIndex
undmediaPeriodId
: Definiert die Playlist und das Element in der Playlist, zu der das Ereignis gehört.mediaPeriodId
enthält optionale zusätzliche Informationen, z. B. gibt an, ob das Ereignis zu einer Anzeige im Element gehört.eventPlaybackPositionMs
: Die Wiedergabeposition im Element, an der das Ereignis aufgetreten ist.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
undcurrentPlaybackPositionMs
: wie oben, aber für das aktuell wiedergegebene Element. Das aktuell wiedergegebene Element kann sich von dem Element unterscheiden, zu dem das Ereignis gehört, z. B. wenn das Ereignis der Vorpufferung des nächsten abzuspielenden Elements entspricht.
Ereignisverarbeitung mit WiedergabeStatsListener
PlaybackStatsListener
ist ein AnalyticsListener
, der die On-Device-Ereignisverarbeitung implementiert. Dabei wird PlaybackStats
mit Zählern und abgeleiteten Messwerten berechnet, darunter:
- Zusammengefasste Messwerte, z. B. die gesamte Wiedergabezeit
- Messwerte zur adaptiven Wiedergabequalität, z. B. die durchschnittliche Videoauflösung.
- Qualitätsmesswerte rendern, z. B. die Rate der abgebrochenen Frames
- Messwerte zur Ressourcennutzung, z. B. die Anzahl der im Netzwerk gelesenen Byte.
Eine vollständige Liste der verfügbaren Anzahlen und abgeleiteten Messwerte finden Sie im PlaybackStats
-Javadoc.
PlaybackStatsListener
berechnet separate PlaybackStats
für jedes Medienelement in der Playlist sowie für jede clientseitige Anzeige, die innerhalb dieser Elemente eingefügt wird. Du kannst einen Callback für PlaybackStatsListener
bereitstellen, um über abgeschlossene Wiedergaben informiert zu werden, und die an den Callback übergebene EventTime
verwenden, um anzugeben, welche Wiedergabe beendet wurde. Es ist möglich, die Analysedaten für mehrere Wiedergaben zusammenfassen. Du kannst auch jederzeit mit PlaybackStatsListener.getPlaybackStats()
den PlaybackStats
nach der aktuellen Wiedergabesitzung abfragen.
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 gesamten Verlauf der verarbeiteten Ereignisse beizubehalten. Hinweis: Je nach Länge der Wiedergabe und Anzahl der Ereignisse kann dadurch ein unbekannter Arbeitsspeicher-Overhead entstehen. Daher sollten Sie sie nur aktivieren, wenn Sie Zugriff auf den gesamten Verlauf der verarbeiteten Ereignisse und nicht nur auf die endgültigen Analysedaten benötigen.
Beachten Sie, dass PlaybackStats
einen erweiterten Satz von Status verwendet, um nicht nur den Status der Medien, sondern auch die Absicht des Nutzers zum Abspielen und detailliertere Informationen anzugeben, z. B. warum die Wiedergabe unterbrochen oder beendet wurde:
Wiedergabestatus | Spielabsicht des Nutzers | Keine Spielabsicht |
---|---|---|
Vor der Wiedergabe | JOINING_FOREGROUND |
NOT_STARTED , JOINING_BACKGROUND |
Aktive Wiedergabe | PLAYING |
|
Wiedergabe unterbrochen | BUFFERING , SEEKING |
PAUSED , PAUSED_BUFFERING , SUPPRESSED , SUPPRESSED_BUFFERING , INTERRUPTED_BY_AD |
Endzustände | ENDED , STOPPED , FAILED , ABANDONED |
Die Spielabsicht 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 in den 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 Absicht des Nutzers zurück, d. h. die gesamte aktive Wartezeit und die Gesamtzeit, die im Status PLAYING
verbracht wurde.
Verarbeitete und interpretierte Ereignisse
Sie können verarbeitete und interpretierte Ereignisse aufzeichnen, indem Sie PlaybackStatsListener
mit keepHistory=true
verwenden. Die resultierende PlaybackStats
enthält die folgenden Ereignislisten:
playbackStateHistory
: Eine sortierte Liste erweiterter Wiedergabestatus mit demEventTime
, ab dem sie angewendet wurden. Sie können auchPlaybackStats.getPlaybackStateAtTime
verwenden, um den Status zu einer bestimmten tatsächlichen Uhrzeit abzurufen.mediaTimeHistory
: Ein Verlauf der Echtzeit- und Medienzeitpaare, mit denen Sie rekonstruieren können, welche Teile der Medien zu welchem Zeitpunkt abgespielt wurden. Du kannst auchPlaybackStats.getMediaTimeMsAtRealtimeMs
verwenden, um die Wiedergabeposition zu einer bestimmten tatsächlich verstrichenen Zeit zu ermitteln.videoFormatHistory
undaudioFormatHistory
: geordnete Listen der Video- und Audioformate, die während der Wiedergabe mit demEventTime
verwendet wurden, ab dem sie zu verwenden begannen.fatalErrorHistory
undnonFatalErrorHistory
: geordnete Listen von schwerwiegenden und nicht schwerwiegenden Fehlern mit derEventTime
, an der sie aufgetreten sind. Schwerwiegende Fehler sind Fehler, die die Wiedergabe beendet haben, während nicht schwerwiegende Fehler möglicherweise behoben werden konnten.
Analysedaten für eine einzelne Wiedergabe
Diese Daten werden automatisch erhoben, wenn Sie PlaybackStatsListener
verwenden, auch mit keepHistory=false
. Die endgültigen Werte sind die öffentlichen Felder, die du im PlaybackStats
-Javadoc findest, und die Dauer der Wiedergabestatus, die von getPlaybackStateDurationMs
zurückgegeben wird. Der Einfachheit halber findest du hier auch Methoden wie getTotalPlayTimeMs
und getTotalWaitTimeMs
, die die Dauer bestimmter Wiedergabestatuskombinationen zurückgeben.
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
durch Aufrufen von PlaybackStats.merge
kombinieren. Das resultierende PlaybackStats
enthält die aggregierten Daten aller zusammengeführten Wiedergaben. Beachte, dass sie nicht den Verlauf einzelner Wiedergabeereignisse enthalten, da diese nicht zusammengefasst werden können.
Mit PlaybackStatsListener.getCombinedPlaybackStats
können Sie eine zusammengefasste Ansicht aller Analysedaten abrufen, die während der Laufzeit eines PlaybackStatsListener
erfasst wurden.
Berechnete zusammenfassende Messwerte
Zusätzlich zu den grundlegenden Analysedaten bietet PlaybackStats
viele Methoden zum Berechnen zusammenfassender Messwerte.
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
Beim Erfassen von Analysedaten für einzelne Wiedergaben empfiehlt es sich, die Wiedergabeanalysedaten mit Metadaten über die wiedergegebenen Medien zu verknüpfen.
Es empfiehlt sich, medienspezifische Metadaten mit MediaItem.Builder.setTag
festzulegen.
Das Medien-Tag ist Teil des EventTime
, der für Rohereignisse gemeldet wird und wenn PlaybackStats
abgeschlossen ist, sodass es bei der Verarbeitung der entsprechenden Analysedaten einfach abgerufen werden kann:
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 Analyseereignissen
Falls Sie den Analysedaten benutzerdefinierte Ereignisse hinzufügen möchten, 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();