Analytics

ExoPlayer es compatible con una amplia gama de necesidades de análisis de reproducción. En última instancia, el análisis consiste en recopilar, interpretar, agregar y resumir datos de las reproducciones. Estos datos se pueden usar en el dispositivo, por ejemplo, para registros o depuraciones, o para informar decisiones de reproducción futuras, o se informa a un para supervisar las reproducciones en todos los dispositivos.

Por lo general, un sistema de análisis debe recopilar eventos primero y, luego, procesarlos. aún más para que sean significativos:

  • Colección de eventos: Para ello, registra un AnalyticsListener en un ExoPlayer instancia. Los objetos de escucha de análisis registrados reciben eventos a medida que ocurren durante uso del reproductor. Cada evento se asocia con el contenido multimedia correspondiente. elemento de la playlist, así como la posición de reproducción y los metadatos de marca de tiempo.
  • Procesamiento de eventos: Algunos sistemas de análisis suben eventos sin procesar a un servidor, con todos los eventos el procesamiento realizado en el servidor. También es posible procesar eventos en la dispositivo y hacerlo puede ser más simple o reducir la cantidad de información que debe subirse. ExoPlayer proporciona PlaybackStatsListener, que te permite realizar los siguientes pasos de procesamiento:
    1. Interpretación de eventos: Para que sean útiles con fines estadísticos, los eventos necesitan se debe interpretar en el contexto de una reproducción única. Por ejemplo, los datos sin procesar evento de un cambio de estado del reproductor a STATE_BUFFERING puede corresponder un búfer inicial, un realmacenamiento o almacenamiento en búfer que se producen después de una búsqueda.
    2. Seguimiento de estado: Este paso convierte los eventos en contadores. Por ejemplo: los eventos de cambio de estado pueden convertirse en contadores que hacen un seguimiento del tiempo en cada estado de reproducción. El resultado es un conjunto básico de datos de análisis para una sola reproducción.
    3. Agregación: En este paso, se combinan los datos de estadísticas de varias reproducciones, normalmente sumando contadores.
    4. Cálculo de métricas de resumen: Muchas de las métricas más útiles son los que calculan promedios o combinan los valores de datos de análisis básicos en de otras formas. Las métricas de resumen se pueden calcular para una o varias reproducciones.

Recopilación de eventos con AnalyticsListener

Los eventos de reproducción sin procesar del reproductor se informan a AnalyticsListener. de Google Cloud. Puedes agregar fácilmente tu propio objeto de escucha y anular solo el métodos que te interesan:

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) {}
    });

La EventTime que se pasa a cada devolución de llamada asocia el evento a un elemento multimedia. elemento de la playlist, así como la posición de reproducción y los metadatos de marca de tiempo:

  • realtimeMs: Es la hora real del evento.
  • timeline, windowIndex y mediaPeriodId: Definen la playlist y el elemento dentro de la playlist a la que pertenece el evento. El mediaPeriodId contiene información adicional opcional, por ejemplo, que indica si el evento pertenece a un anuncio dentro del elemento.
  • eventPlaybackPositionMs: Es la posición de reproducción en el elemento cuando el evento para determinar si se produjo un error.
  • currentTimeline, currentWindowIndex, currentMediaPeriodId y currentPlaybackPositionMs: Igual al anterior, pero para el elemento que se está reproduciendo. El El elemento que se está reproduciendo puede ser diferente del elemento con el que se está reproduciendo el evento. pertenece, por ejemplo, si el evento corresponde al almacenamiento en búfer previo de la siguiente elemento que se va a reproducir.

Procesamiento de eventos con PlaybackStatsListener

PlaybackStatsListener es un AnalyticsListener que implementa implementación el procesamiento de eventos. Calcula PlaybackStats, con contadores y derivados como las siguientes:

  • Métricas de resumen, por ejemplo, el tiempo total de reproducción
  • Métricas de calidad de reproducción adaptable, por ejemplo, la resolución de video promedio
  • Métricas de calidad de renderización, por ejemplo, la tasa de fotogramas disminuidos.
  • Las métricas de uso de los recursos, por ejemplo, la cantidad de bytes leídos en la red.

Encontrarás una lista completa de los recuentos disponibles y las métricas derivadas en la Javadoc de PlaybackStats.

PlaybackStatsListener calcula PlaybackStats independientes para cada elemento multimedia. de la playlist y cada anuncio del cliente insertado dentro de estos elementos. Tú Puedes proporcionar una devolución de llamada a PlaybackStatsListener para informar que el proceso finalizó reproducciones y usa el EventTime que se pasa a la devolución de llamada para identificar qué terminó la reproducción. Es posible agregar los datos de estadísticas para varias reproducciones. También es posible consultar PlaybackStats para el sesión de reproducción actual en cualquier momento mediante 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.
        }));

El constructor de PlaybackStatsListener ofrece la opción de mantener la configuración de eventos procesados. Ten en cuenta que esto puede generar una sobrecarga de memoria desconocida. según la duración de la reproducción y la cantidad de eventos. Por lo tanto, solo debes activarlo si necesitas acceso al historial completo eventos, en lugar de solo a los datos finales de estadísticas.

Ten en cuenta que PlaybackStats usa un conjunto extendido de estados para indicar no solo el estado de los medios, pero también la intención del usuario de jugar información como el motivo por el que se interrumpió o finalizó la reproducción:

Estado de reproducción Intención de jugar del usuario No tengo intención de jugar
Antes de reproducir JOINING_FOREGROUND NOT_STARTED, JOINING_BACKGROUND
Reproducción activa PLAYING
Reproducción interrumpida BUFFERING, SEEKING PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD
Estados de finalización ENDED, STOPPED, FAILED, ABANDONED

La intención de jugar del usuario es importante para distinguir los momentos en que el usuario estuvo que esperan activamente que la reproducción continúe desde los tiempos de espera pasivos. Por ejemplo: PlaybackStats.getTotalWaitTimeMs devuelve el tiempo total empleado en el Estados JOINING_FOREGROUND, BUFFERING y SEEKING, pero no la hora en la que se pausó la reproducción. Del mismo modo, PlaybackStats.getTotalPlayAndWaitTimeMs Devuelve el tiempo total con la intención de jugar del usuario, que es el total de actividades el tiempo de espera y el tiempo total empleado en el estado PLAYING.

Eventos interpretados y procesados

Puedes registrar eventos interpretados y procesados con PlaybackStatsListener con keepHistory=true. La PlaybackStats resultante contendrá lo siguiente: las siguientes listas de eventos:

  • playbackStateHistory: Es una lista ordenada de estados de reproducción extendidos con el EventTime en el que comenzaron a postularse. También puedes usar PlaybackStats.getPlaybackStateAtTime para buscar el estado en un muro determinado y la hora del reloj.
  • mediaTimeHistory: Es un historial de los relojes de pared y los pares de horarios multimedia que permiten te permite reconstruir qué partes de los medios se reprodujeron en ese momento. Puedes también puedes usar PlaybackStats.getMediaTimeMsAtRealtimeMs para buscar la reproducción a una hora determinada.
  • videoFormatHistory y audioFormatHistory: listas ordenadas de videos y Formatos de audio que se usaron durante la reproducción con el EventTime en el que comenzaron que se usará.
  • fatalErrorHistory y nonFatalErrorHistory: listas ordenadas de errores recuperables y errores recuperables con el EventTime en el que ocurrieron. Los errores no recuperables son aquellos que finalizaron la reproducción, mientras que los errores recuperables podrían haberse recuperado.

Datos de estadísticas de reproducción única

Estos datos se recopilan automáticamente si usas PlaybackStatsListener, incluso con keepHistory=false. Los valores finales son los campos públicos que puedes que encontrarás en PlaybackStats Javadoc y las duraciones del estado de reproducción que devuelve getPlaybackStateDurationMs. Para mayor comodidad, también encontrarás métodos como getTotalPlayTimeMs y getTotalWaitTimeMs que devuelven el la duración de combinaciones específicas de estados de reproducción.

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);

Datos de estadísticas agregados de varias reproducciones

Puedes combinar varios PlaybackStats llamando PlaybackStats.merge La PlaybackStats resultante contendrá la datos de todas las reproducciones combinadas. Ten en cuenta que no contendrá el historial de eventos de reproducción individuales, ya que no se pueden agregar.

Puedes usar PlaybackStatsListener.getCombinedPlaybackStats para obtener un vista agregada de todos los datos de estadísticas recopilados durante el ciclo de vida de una PlaybackStatsListener

Métricas de resumen calculadas

Además de los datos básicos de estadísticas, PlaybackStats ofrece muchos métodos para calcular las métricas de resumen.

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());

Temas avanzados

Asociación de datos de estadísticas con metadatos de reproducción

Cuando recopiles datos de estadísticas para reproducciones individuales, te recomendamos asociar los datos de análisis de reproducción con metadatos sobre el contenido multimedia jugó.

Se recomienda establecer metadatos específicos de contenido multimedia con MediaItem.Builder.setTag. La etiqueta multimedia es parte del elemento EventTime que se informa para eventos sin procesar y cuándo Las PlaybackStats finalizaron, por lo que se pueden recuperar fácilmente cuando se manejan el datos de Analytics correspondientes:

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.
    });

Cómo informar eventos de estadísticas personalizadas

En caso de que necesites agregar eventos personalizados a los datos de Analytics, debes guardar estos eventos en tu propia estructura de datos y combinarlos con la información PlaybackStats después. Si te sirve, puedes extender DefaultAnalyticsCollector para poder generar EventTime instancias para tus eventos personalizados y enviar a objetos de escucha ya registrados, como se muestra en el siguiente ejemplo.

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();