Analytics

ExoPlayer répond à de nombreux besoins d'analyse de lecture. En fin de compte, l’analytique consiste à collecter, à interpréter, à agréger et à résumer des données des lectures. Ces données peuvent être utilisées sur l'appareil, par exemple pour la journalisation ou le débogage, ou d'éclairer les futures décisions de lecture, ou de signaler pour contrôler les lectures sur tous les appareils.

Un système d'analyse doit généralement collecter les événements, puis les traiter pour les rendre plus intéressantes:

  • Collecte de l'événement: Pour ce faire, enregistrez un AnalyticsListener sur un ExoPlayer. Compute Engine. Les écouteurs d'analyse enregistrés reçoivent les événements au fur et à mesure qu'ils se produisent du lecteur. Chaque événement est associé au média correspondant de la playlist, ainsi que les métadonnées de position et de code temporel de la lecture.
  • Traitement des événements: Certains systèmes d'analyse importent des événements bruts sur un serveur, et le traitement côté serveur. Il est également possible de traiter des événements d'un appareil, ce qui peut être plus simple ou réduire la quantité d'informations doit être importée. ExoPlayer fournit PlaybackStatsListener, qui vous permet d'effectuer les étapes de traitement suivantes: <ph type="x-smartling-placeholder">
      </ph>
    1. Interprétation des événements: pour être utiles à des fins d'analyse, les événements doivent à interpréter lors d'une seule lecture. Par exemple, les données brutes l'événement de changement d'état du lecteur sur STATE_BUFFERING peut correspondre à mise en mémoire tampon initiale, remise en mémoire tampon ou mise en mémoire tampon après une recherche.
    2. 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 qui suivent la durée dans chaque état de lecture. Vous obtenez ainsi un ensemble de données d'analyse de base pour une seule lecture.
    3. Agrégation: cette étape combine les données d'analyse de plusieurs généralement en ajoutant des compteurs.
    4. Calcul des métriques récapitulatives: la plupart des métriques les plus utiles sont ceux qui calculent les moyennes ou combinent les valeurs des données analytiques de base dans d'autres manières. Les métriques récapitulatives peuvent être calculées pour une ou plusieurs lectures.

Collecte d'événements avec AnalyticsListener

Les événements de lecture bruts du lecteur sont signalés à AnalyticsListener mises en œuvre. Vous pouvez facilement ajouter votre propre écouteur et remplacer uniquement 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) {}
    });

L'élément EventTime transmis à chaque rappel associe l'événement à un élément multimédia de la playlist, ainsi que les métadonnées relatives à la position de lecture et au code temporel:

  • realtimeMs: heure de l'événement
  • timeline, windowIndex et mediaPeriodId: définit la playlist et les éléments de la playlist à laquelle l'événement appartient. mediaPeriodId contient des informations supplémentaires facultatives, indiquant par exemple si le appartient à une annonce dans l'élément.
  • eventPlaybackPositionMs: position de lecture de l'élément lorsque l'événement s'est produit.
  • currentTimeline, currentWindowIndex, currentMediaPeriodId et currentPlaybackPositionMs: comme indiqué ci-dessus, mais pour l'élément en cours de lecture. La l'élément en cours de lecture peut être différent de celui auquel l'événement si l'événement correspond à la mise en mémoire tampon préalable du prochain à lire.

Traitement des événements avec PlaybackStatsListener

PlaybackStatsListener est un AnalyticsListener qui implémente sur l'appareil. lors du traitement des événements. Elle calcule PlaybackStats, avec des compteurs et des valeurs dérivées y compris:

  • Métriques récapitulatives, par exemple la durée de lecture totale.
  • Métriques adaptatives sur la qualité de la lecture, par exemple la résolution vidéo moyenne.
  • Métriques de qualité de rendu, telles que le taux d'images perdues.
  • Métriques d'utilisation des ressources, par exemple le nombre d'octets lus sur le réseau.

Vous trouverez une liste complète des décomptes disponibles et des métriques dérivées dans la Javadoc PlaybackStats.

PlaybackStatsListener calcule des PlaybackStats distincts pour chaque élément multimédia de la playlist, ainsi que chaque annonce côté client insérée à l'intérieur de ces éléments. Toi peut rappeler à PlaybackStatsListener pour être informé de l'avancement et utilise le EventTime transmis au rappel pour identifier les lecture terminée. Il est possible d'agréger les données d'analyse pour plusieurs lectures. Il est également possible d'interroger PlaybackStats pour obtenir la session de lecture en cours à tout moment en utilisant 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'intégralité l'historique 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 l'activez que si vous avez besoin d'accéder à l'historique complet les événements, et pas seulement aux données d'analyse finales.

Notez que PlaybackStats utilise un ensemble étendu d'états pour indiquer non seulement l'état des contenus multimédias, mais aussi l'intention de l'utilisateur de les lire, des informations telles que la raison pour laquelle la lecture a été interrompue ou terminée:

État de lecture Intention de l'utilisateur de jouer 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 de fin ENDED, STOPPED, FAILED, ABANDONED

L'intention de l'utilisateur de jouer est importante pour distinguer les moments où l'utilisateur dans l'attente active de la poursuite de la lecture à partir des temps d'attente passifs. Par exemple : PlaybackStats.getTotalWaitTimeMs renvoie le temps total passé dans la JOINING_FOREGROUND, BUFFERING et SEEKING, mais pas le moment où la lecture a été mise en pause. De même, PlaybackStats.getTotalPlayAndWaitTimeMs renvoie la durée totale de jeu dont l'utilisateur a l'intention de jouer, c'est-à-dire la durée totale le temps d'attente 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 à l'aide de PlaybackStatsListener avec keepHistory=true. Le PlaybackStats obtenu contient le les listes d'événements suivantes:

  • playbackStateHistory: liste numérotée des états de lecture étendue avec la EventTime à laquelle il a commencé à postuler. Vous pouvez également utiliser PlaybackStats.getPlaybackStateAtTime pour rechercher l'état sur un mur donné l'heure de l'horloge.
  • mediaTimeHistory: historique de l'heure de l'horloge murale et de l'heure du média permettant de reconstituer quelles parties du média ont été lues et à quel moment. Vous pouvez Utilisez aussi PlaybackStats.getMediaTimeMsAtRealtimeMs pour rechercher la lecture à une heure donnée.
  • videoFormatHistory et audioFormatHistory: listes ordonnées de vidéos et formats audio utilisés lors de la lecture avec le EventTime à partir duquel ils ont commencé à utiliser.
  • fatalErrorHistory et nonFatalErrorHistory: listes numérotées d'erreurs fatales et des erreurs non fatales avec le EventTime où elles se sont produites. Les erreurs fatales sont ceux qui ont mis fin à la lecture, alors que les erreurs non fatales auraient pu être récupérées.

Données d'analyse pour les lectures uniques

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 que vous trouverez dans le Javadoc PlaybackStats et les durées d'état de lecture renvoyé par getPlaybackStateDurationMs. Pour plus de commodité, vous trouverez également comme getTotalPlayTimeMs et getTotalWaitTimeMs, qui renvoient le 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);

Regrouper les données d'analyse de plusieurs lectures

Vous pouvez combiner plusieurs PlaybackStats en appelant PlaybackStats.merge Le PlaybackStats obtenu contient les données agrégées les donné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 une vue agrégée de toutes les données d'analyse collectées au cours de la durée de vie PlaybackStatsListener

Métriques récapitulatives calculées

En plus des données d'analyse de base, PlaybackStats propose 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

Si vous collectez des données d'analyse pour des lectures individuelles, vous pouvez associer les données d'analyse de lecture aux métadonnées concernant le contenu multimédia joué.

Nous vous recommandons de définir des métadonnées spécifiques aux contenus multimédias avec MediaItem.Builder.setTag. La balise média fait partie du EventTime rapporté pour les événements bruts et quand PlaybackStats sont terminés, et peuvent donc être facilement récupérés lors de la gestion données analytiques 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 avec les PlaybackStats plus tard. Si cela peut vous aider, vous pouvez prolonger DefaultAnalyticsCollector afin de pouvoir générer des instances EventTime pour vos événements personnalisés et 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();