Eventos del jugador

Cómo escuchar eventos de reproducción

Los eventos, como cambios de estado y errores de reproducción, se informan a los Player.Listener de instancias. Para registrar un objeto de escucha de modo que reciba dicho eventos:

Kotlin

// Add a listener to receive events from the player.
player.addListener(listener)

Java

// Add a listener to receive events from the player.
player.addListener(listener);

Player.Listener tiene métodos predeterminados vacíos, por lo que solo debes implementar y los métodos que te interesan. Consulta Javadoc para obtener una descripción completa de los métodos y cuándo se los llama. Algunos de los métodos más importantes son se describen con más detalle a continuación.

Los objetos de escucha tienen la opción de implementar devoluciones de llamada de eventos individuales o una Es la devolución de llamada onEvents genérica que se llama después de que ocurren uno o más eventos. entre sí. Consulta Individual callbacks vs onEvents para obtener una explicación. se prefiere para distintos casos de uso.

Cambios en el estado de reproducción

Los cambios en el estado del reproductor se pueden recibir implementando onPlaybackStateChanged(@State int state) en un Player.Listener El reproductor puede estar en uno de los siguientes cuatro estados de reproducción:

  • Player.STATE_IDLE: Es el estado inicial, el estado en el que el reproductor se encuentra y cuando falló la reproducción. El reproductor solo contendrá recursos limitados en este estado.
  • Player.STATE_BUFFERING: El reproductor no puede reproducir inmediatamente desde su la posición actual. Esto sucede principalmente porque se deben cargar más datos.
  • Player.STATE_READY: El reproductor puede reproducir de inmediato el contenido actual. posición.
  • Player.STATE_ENDED: El reproductor terminó de reproducir todo el contenido multimedia.

Además de estos estados, el jugador tiene una marca playWhenReady para indicar la intención de jugar del usuario. Los cambios en esta marca se pueden recibir implementando onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)

Se está reproduciendo un reproductor (es decir, su posición avanza y se reproduce contenido multimedia) presentarse al usuario) cuando se cumplen las tres condiciones siguientes:

  • El reproductor está en el estado Player.STATE_READY
  • playWhenReady es true.
  • La reproducción no se suprimió por algún motivo devuelto por Player.getPlaybackSuppressionReason

En lugar de tener que verificar estas propiedades de forma individual, Player.isPlaying un modelo de AA. Los cambios en este estado se pueden recibir implementando onIsPlayingChanged(boolean isPlaying):

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
      if (isPlaying) {
        // Active playback.
      } else {
        // Not playing because playback is paused, ended, suppressed, or the player
        // is buffering, stopped or failed. Check player.playWhenReady,
        // player.playbackState, player.playbackSuppressionReason and
        // player.playerError for details.
      }
    }
  }
)

Java

player.addListener(
    new Player.Listener() {
      @Override
      public void onIsPlayingChanged(boolean isPlaying) {
        if (isPlaying) {
          // Active playback.
        } else {
          // Not playing because playback is paused, ended, suppressed, or the player
          // is buffering, stopped or failed. Check player.getPlayWhenReady,
          // player.getPlaybackState, player.getPlaybackSuppressionReason and
          // player.getPlaybackError for details.
        }
      }
    });

Errores de reproducción

Los errores que causan fallas en la reproducción se pueden recibir implementando onPlayerError(PlaybackException error) en un Player.Listener Cuando se produce un error, se llamará a este método inmediatamente antes de que el estado de reproducción pase a Player.STATE_IDLE. Si deseas reintentar las reproducciones con errores o detenidas, llama a ExoPlayer.prepare.

Ten en cuenta que algunas implementaciones de Player pasan instancias de subclases de PlaybackException para proporcionar información adicional sobre la falla. Para Por ejemplo, ExoPlayer pasa ExoPlaybackException, que tiene type, rendererIndex y otros campos específicos de ExoPlayer.

En el siguiente ejemplo se muestra cómo detectar un error en la reproducción debido a una Problema de red HTTP:

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onPlayerError(error: PlaybackException) {
      val cause = error.cause
      if (cause is HttpDataSourceException) {
        // An HTTP error occurred.
        val httpError = cause
        // It's possible to find out more about the error both by casting and by querying
        // the cause.
        if (httpError is InvalidResponseCodeException) {
          // Cast to InvalidResponseCodeException and retrieve the response code, message
          // and headers.
        } else {
          // Try calling httpError.getCause() to retrieve the underlying cause, although
          // note that it may be null.
        }
      }
    }
  }
)

Java

player.addListener(
    new Player.Listener() {
      @Override
      public void onPlayerError(PlaybackException error) {
        @Nullable Throwable cause = error.getCause();
        if (cause instanceof HttpDataSourceException) {
          // An HTTP error occurred.
          HttpDataSourceException httpError = (HttpDataSourceException) cause;
          // It's possible to find out more about the error both by casting and by querying
          // the cause.
          if (httpError instanceof HttpDataSource.InvalidResponseCodeException) {
            // Cast to InvalidResponseCodeException and retrieve the response code, message
            // and headers.
          } else {
            // Try calling httpError.getCause() to retrieve the underlying cause, although
            // note that it may be null.
          }
        }
      }
    });

Transiciones de la playlist

Cada vez que el reproductor cambia a un nuevo elemento multimedia de la playlist Se llama a onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) en registros Player.Listener. El motivo indica si se trata de una implementación una transición, un salto (por ejemplo, después de llamar a player.next()), una repetición de mismo elemento o debido a un cambio en la playlist (por ejemplo, si el el elemento que se está reproduciendo).

Metadatos

Los metadatos que devuelve player.getCurrentMediaMetadata() pueden cambiar debido a muchos razones: transiciones de playlists, actualizaciones de metadatos in-stream o actualización de actual MediaItem en medio de la reproducción.

Si te interesan los cambios en los metadatos, por ejemplo, para actualizar una IU que muestra el título actual, puedes escuchar onMediaMetadataChanged.

Buscando

Llamar a los métodos Player.seekTo da como resultado una serie de devoluciones de llamada a registros Instancias de Player.Listener:

  1. onPositionDiscontinuity con reason=DISCONTINUITY_REASON_SEEK. Este es el resultado directo de la llamada a Player.seekTo La devolución de llamada tiene PositionInfo. para la posición antes y después del salto.
  2. onPlaybackStateChanged con cualquier cambio de estado inmediato relacionado con la búsqueda. Ten en cuenta que es posible que no haya ese cambio.

Devoluciones de llamada individuales en comparación con onEvents

Los objetos de escucha pueden elegir entre implementar devoluciones de llamada individuales, como onIsPlayingChanged(boolean isPlaying) y el genérico Devolución de llamada onEvents(Player player, Events events). La devolución de llamada genérica brinda acceso al objeto Player y especifica el conjunto de events que se produjo entre sí. Esta devolución de llamada siempre se llama después de las devoluciones de llamada que corresponden a los eventos individuales.

Kotlin

override fun onEvents(player: Player, events: Player.Events) {
  if (
    events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) ||
      events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)
  ) {
    uiModule.updateUi(player)
  }
}

Java

@Override
public void onEvents(Player player, Events events) {
  if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)
      || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
    uiModule.updateUi(player);
  }
}

Se deben preferir eventos individuales en los siguientes casos:

  • El objeto de escucha está interesado en los motivos de los cambios. Por ejemplo, el motivos proporcionados para onPlayWhenReadyChanged o onMediaItemTransition.
  • El objeto de escucha solo actúa sobre los valores nuevos proporcionados a través de los parámetros de devolución de llamada o activa algo más que no depende de los parámetros de devolución de llamada.
  • La implementación del objeto de escucha prefiere una indicación clara y legible de lo que activó el evento en el nombre del método.
  • El oyente informa a un sistema de análisis que necesita saber acerca de todos eventos individuales y cambios de estado.

Se debe preferir el onEvents(Player player, Events events) genérico en las los siguientes casos:

  • El objeto de escucha quiere activar la misma lógica para varios eventos. Para Por ejemplo, actualizar una IU para onPlaybackStateChanged y onPlayWhenReadyChanged
  • El objeto de escucha necesita acceder al objeto Player para activar más eventos. como la búsqueda después de la transición de un elemento multimedia.
  • El objeto de escucha intenta usar múltiples valores de estado que se informan a través de devoluciones de llamada separadas o en combinación con el método get Player . Por ejemplo, si usas Player.getCurrentWindowIndex() con el Los Timeline proporcionados en onTimelineChanged solo están seguros en el onEvents.
  • El objeto de escucha está interesado en si los eventos ocurrieron juntos de forma lógica. Para ejemplo, onPlaybackStateChanged a STATE_BUFFERING debido a un elemento multimedia transición.

En algunos casos, es posible que los objetos de escucha necesiten combinar las devoluciones de llamada individuales con el Es la devolución de llamada genérica de onEvents, por ejemplo, para grabar motivos de cambio de elementos multimedia. con onMediaItemTransition, pero solo actuar una vez que se puedan usar todos los cambios de estado juntos en onEvents.

AnalyticsListener en uso

Cuando se usa ExoPlayer, se puede registrar un AnalyticsListener con el reproductor llamando a addAnalyticsListener. Las implementaciones de AnalyticsListener pueden para escuchar eventos detallados que podrían ser útiles para las estadísticas y los registros comerciales. Consulta la página de estadísticas para obtener más detalles.

EventLogger en uso

EventLogger es un objeto AnalyticsListener que proporciona directamente la biblioteca para de registro. Agrega EventLogger a una ExoPlayer para habilitar funciones útiles registros adicionales con una sola línea:

Kotlin

player.addAnalyticsListener(EventLogger())

Java

player.addAnalyticsListener(new EventLogger());

Consulta la página del registro de depuración para obtener más detalles.

Cómo activar eventos en posiciones de reproducción especificadas

Algunos casos de uso requieren que se activen eventos en posiciones de reproducción especificadas. Este es compatible con PlayerMessage. Se puede crear un PlayerMessage con ExoPlayer.createMessage La posición de reproducción en la que debe ejecutarse se pueden configurar con PlayerMessage.setPosition. Los mensajes se ejecutan en la subproceso de reproducción de forma predeterminada, pero se puede personalizar PlayerMessage.setLooper Se puede usar PlayerMessage.setDeleteAfterDelivery para controlar si el mensaje se ejecutará cada vez que se cumpla se encuentra la posición de reproducción (esto puede ocurrir varias veces debido a la y los modos de repetición), o solo la primera vez. Una vez que PlayerMessage esté se puede programar con PlayerMessage.send.

Kotlin

player
  .createMessage { messageType: Int, payload: Any? -> }
  .setLooper(Looper.getMainLooper())
  .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000)
  .setPayload(customPayloadData)
  .setDeleteAfterDelivery(false)
  .send()

Java

player
    .createMessage(
        (messageType, payload) -> {
          // Do something at the specified playback position.
        })
    .setLooper(Looper.getMainLooper())
    .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000)
    .setPayload(customPayloadData)
    .setDeleteAfterDelivery(false)
    .send();