ExoPlayer est compatible avec un large éventail de besoins en termes d'analyse de la lecture. En fin de compte, l'analyse concerne la collecte, l'interprétation, l'agrégation et la synthèse des données à partir des lectures. Ces données peuvent être utilisées sur l'appareil (par exemple, pour la journalisation, le débogage ou pour éclairer les futures décisions de lecture), ou transmises à un serveur pour surveiller les lectures sur tous les appareils.
Un système d'analyse doit généralement commencer par collecter des événements, puis les traiter plus en détail pour les rendre significatifs:
- Collecte des événements : pour ce faire, enregistrez un élément
AnalyticsListener
sur une instanceExoPlayer
. Les écouteurs d'analyse enregistrés reçoivent des événements au fur et à mesure qu'ils se produisent lors de l'utilisation du lecteur. Chaque événement est associé à l'élément multimédia correspondant dans la playlist, ainsi qu'aux métadonnées de position de lecture et d'horodatage. - Traitement des événements : certains systèmes d'analyse importent des événements bruts sur un serveur et l'intégralité du traitement des événements est effectuée côté serveur. Il est également possible de traiter des événements sur l'appareil, ce qui peut être plus simple ou réduire la quantité d'informations à importer. ExoPlayer fournit
PlaybackStatsListener
, qui vous permet d'effectuer les étapes de traitement suivantes :- Interprétation des événements: pour être utile à des fins d'analyse, les événements doivent être interprétés dans le contexte d'une seule lecture. Par exemple, l'événement brut du passage de l'état du lecteur à
STATE_BUFFERING
peut correspondre à une mise en mémoire tampon initiale, une remise en mémoire tampon ou une mise en mémoire tampon qui se produit après une recherche. - Suivi de l'état: cette étape convertit les événements en compteurs. Par exemple, les événements de changement d'état peuvent être convertis en compteurs pour suivre le temps passé dans chaque état de lecture. Le résultat est un ensemble de base de valeurs de données analytiques pour une seule lecture.
- Agrégation: cette étape combine les données d'analyse de plusieurs lectures, généralement en additionnant des compteurs.
- Calcul des métriques récapitulatives: la plupart des métriques les plus utiles sont celles qui calculent des moyennes ou combinent les valeurs des données d'analyse de base d'autres manières. Les métriques récapitulatives peuvent être calculées pour une ou plusieurs lectures.
- Interprétation des événements: pour être utile à des fins d'analyse, les événements doivent être interprétés dans le contexte d'une seule lecture. Par exemple, l'événement brut du passage de l'état du lecteur à
Collecte d'événements avec AnalyticsListener
Les événements de lecture brute du lecteur sont signalés aux implémentations AnalyticsListener
. Vous pouvez facilement ajouter votre propre écouteur et ne remplacer que les méthodes qui vous intéressent:
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) {} });
Le EventTime
transmis à chaque rappel associe l'événement à un élément multimédia de la playlist, ainsi qu'aux métadonnées de position de lecture et d'horodatage:
realtimeMs
: durée d'exécution de l'événement.timeline
,windowIndex
etmediaPeriodId
: définissent la playlist et l'élément de la playlist à laquelle l'événement appartient. L'élémentmediaPeriodId
contient des informations supplémentaires facultatives, indiquant par exemple si l'événement appartient à une annonce dans l'élément.eventPlaybackPositionMs
: position de lecture dans l'élément lorsque l'événement s'est produit.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
etcurrentPlaybackPositionMs
: comme ci-dessus, mais pour l'élément en cours de lecture. L'élément en cours de lecture peut être différent de l'élément auquel l'événement appartient, par exemple si l'événement correspond à la mise en mémoire tampon préalable de l'élément suivant à lire.
Traitement des événements avec PlaybackStatsListener
PlaybackStatsListener
est un AnalyticsListener
qui implémente le traitement des événements sur l'appareil. Il calcule PlaybackStats
à l'aide de compteurs et de métriques dérivées, y compris:
- Métriques récapitulatives, par exemple la durée de lecture totale.
- Métriques de qualité de lecture adaptatives, par exemple la résolution vidéo moyenne.
- Métriques de qualité d'affichage, par exemple le taux d'abandon d'images.
- Métriques d'utilisation des ressources, par exemple le nombre d'octets lus sur le réseau.
Vous trouverez la liste complète des nombres disponibles et des métriques dérivées dans le Javadoc PlaybackStats
.
PlaybackStatsListener
calcule des PlaybackStats
distincts pour chaque élément multimédia de la playlist, ainsi que pour chaque annonce côté client insérée dans ces éléments. Vous pouvez fournir un rappel à PlaybackStatsListener
pour être informé des lectures terminées, et utiliser le EventTime
transmis au rappel pour identifier la lecture terminée. Il est possible d'agréger les données d'analyse pour plusieurs lectures. Vous pouvez également interroger l'PlaybackStats
pour la session de lecture en cours à tout moment à l'aide de PlaybackStatsListener.getPlaybackStats()
.
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. }));
Le constructeur de PlaybackStatsListener
permet de conserver l'historique complet des événements traités. Notez que cela peut entraîner une surcharge de mémoire inconnue en fonction de la durée de la lecture et du nombre d'événements. Par conséquent, vous ne devez l'activer que si vous avez besoin d'accéder à l'historique complet des événements traités, plutôt qu'aux données d'analyse finales.
Notez que PlaybackStats
utilise un vaste ensemble d'états pour indiquer non seulement l'état du contenu multimédia, mais aussi l'intention de lecture de l'utilisateur, ainsi que des informations plus détaillées, comme la raison pour laquelle la lecture a été interrompue ou terminée:
État de la lecture | Intention de jeu de l'utilisateur | Je n'ai pas l'intention de jouer |
---|---|---|
Avant la lecture | JOINING_FOREGROUND |
NOT_STARTED , JOINING_BACKGROUND |
Lecture active | PLAYING |
|
Lecture interrompue | BUFFERING , SEEKING |
PAUSED , PAUSED_BUFFERING , SUPPRESSED , SUPPRESSED_BUFFERING , INTERRUPTED_BY_AD |
États finaux | ENDED , STOPPED , FAILED , ABANDONED |
L'intention de l'utilisateur de jouer est importante pour faire la distinction entre les temps d'attente passives et l'attente active de la lecture. Par exemple, PlaybackStats.getTotalWaitTimeMs
renvoie le temps total passé dans les états JOINING_FOREGROUND
, BUFFERING
et SEEKING
, mais pas l'heure de mise en pause de la lecture. De même, PlaybackStats.getTotalPlayAndWaitTimeMs
renvoie le temps total dans lequel l'utilisateur a l'intention de jouer, c'est-à-dire le temps d'attente actif total et le temps total passé à l'état PLAYING
.
Événements traités et interprétés
Vous pouvez enregistrer des événements traités et interprétés en utilisant PlaybackStatsListener
avec keepHistory=true
. Le PlaybackStats
obtenu contiendra les listes d'événements suivantes:
playbackStateHistory
: liste numérotée des états de lecture étendues avec l'élémentEventTime
auquel ils ont commencé à s'appliquer. Vous pouvez également utiliserPlaybackStats.getPlaybackStateAtTime
pour rechercher l'état à une heure donnée.mediaTimeHistory
: historique de l'horloge murale et des paires heure du média, vous permettant de reconstituer quelles parties du contenu multimédia ont été lues à quel moment. Vous pouvez également utiliserPlaybackStats.getMediaTimeMsAtRealtimeMs
pour rechercher la position de lecture à une heure donnée.videoFormatHistory
etaudioFormatHistory
: listes ordonnées de formats vidéo et audio utilisés lors de la lecture avec l'élémentEventTime
à partir duquel ils ont commencé à être utilisés.fatalErrorHistory
etnonFatalErrorHistory
: listes classées d'erreurs fatales et non fatales avec l'EventTime
où elles se sont produites. Les erreurs fatales sont celles qui ont mis fin à la lecture, tandis que les erreurs non fatales peuvent avoir été récupérables.
Données analytiques pour la lecture unique
Ces données sont collectées automatiquement si vous utilisez PlaybackStatsListener
, même avec keepHistory=false
. Les valeurs finales sont les champs publics que vous pouvez trouver dans le Javadoc PlaybackStats
et les durées d'état de lecture renvoyées par getPlaybackStateDurationMs
. Pour plus de commodité, vous trouverez également des méthodes telles que getTotalPlayTimeMs
et getTotalWaitTimeMs
, qui renvoient la durée de combinaisons d'états de lecture spécifiques.
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);
Données d'analyse agrégées pour plusieurs lectures
Vous pouvez combiner plusieurs PlaybackStats
en appelant PlaybackStats.merge
. Le PlaybackStats
obtenu contiendra les données agrégées de toutes les lectures fusionnées. Notez qu'il ne contiendra pas l'historique des événements de lecture individuels, car ils ne peuvent pas être agrégés.
PlaybackStatsListener.getCombinedPlaybackStats
permet d'obtenir une vue agrégée de toutes les données d'analyse collectées au cours de la durée de vie d'un PlaybackStatsListener
.
Métriques récapitulatives calculées
En plus des données d'analyse de base, PlaybackStats
fournit de nombreuses méthodes pour calculer des métriques récapitulatives.
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());
Rubriques avancées
Associer des données d'analyse aux métadonnées de lecture
Lors de la collecte de données d'analyse pour des lectures individuelles, vous pouvez associer les données d'analyse de lecture à des métadonnées sur le contenu multimédia en cours de lecture.
Nous vous recommandons de définir des métadonnées spécifiques au contenu multimédia avec MediaItem.Builder.setTag
.
La balise multimédia fait partie du EventTime
signalé pour les événements bruts et lorsque la PlaybackStats
est terminée. Elle peut donc être facilement récupérée lors du traitement des données d'analyse correspondantes:
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. });
Créer des rapports sur des événements d'analyse personnalisés
Si vous devez ajouter des événements personnalisés aux données d'analyse, vous devez enregistrer ces événements dans votre propre structure de données et les combiner ultérieurement avec le PlaybackStats
indiqué. Si cela peut vous aider, vous pouvez étendre DefaultAnalyticsCollector
afin de générer des instances EventTime
pour vos événements personnalisés et de les envoyer aux écouteurs déjà enregistrés, comme illustré dans l'exemple suivant.
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();