Eventos de player

Como detectar eventos de reprodução

Eventos como mudanças de estado e erros de reprodução são informados aos usuários registrados Instâncias de Player.Listener. Registrar um listener para receber esses 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);

A Player.Listener tem métodos padrão vazios, então você só precisa implementar os métodos em que você tem interesse. Consulte o Javadoc para ver uma descrição completa dos os métodos e quando eles são chamados. Alguns dos métodos mais importantes são descritos em mais detalhes abaixo.

As escutas têm a opção de implementar callbacks de eventos individuais ou callback genérico onEvents que é chamado após a ocorrência de um ou mais eventos. juntas. Consulte Individual callbacks vs onEvents para uma explicação sobre qual em diferentes casos de uso.

Mudanças no estado de reprodução

As alterações no estado do player podem ser recebidas implementando onPlaybackStateChanged(@State int state) em um registro Player.Listener. O player pode estar em um dos quatro estados de reprodução:

  • Player.STATE_IDLE: este é o estado inicial, quando o player é parou e quando a reprodução falhou. O jogador terá apenas recursos limitados nesse estado.
  • Player.STATE_BUFFERING: o player não pode começar imediatamente a partir do próprio posição atual. Isso acontece principalmente porque é preciso carregar mais dados.
  • Player.STATE_READY: o player pode reproduzir imediatamente a partir do posição
  • Player.STATE_ENDED: o player terminou de reproduzir todas as mídias.

Além desses estados, o jogador tem uma flag playWhenReady para indicar a intenção do usuário de jogar. As mudanças nessa flag podem ser recebidas implementando onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason):

Um player está tocando (ou seja, sua posição está avançando e a mídia está sendo apresentadas ao usuário) quando todas as três condições a seguir forem atendidas:

  • O player está no estado Player.STATE_READY.
  • playWhenReady é true
  • A reprodução não é suprimida pelo motivo retornado pelo Player.getPlaybackSuppressionReason

Em vez de ter que verificar essas propriedades individualmente, Player.isPlaying pode ser chamado. Alterações nesse estado podem ser recebidas 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.
        }
      }
    });

Erros de reprodução

Os erros que causam falha na reprodução podem ser recebidos implementando onPlayerError(PlaybackException error) em um registro Player.Listener. Em caso de falha, este método será chamado imediatamente antes da transição do estado de reprodução para Player.STATE_IDLE. Para tentar novamente as reproduções com falha ou interrompidas, chame ExoPlayer.prepare.

Algumas implementações de Player transmitem instâncias de subclasses de PlaybackException para fornecer mais informações sobre a falha. Para exemplo, ExoPlayer passa ExoPlaybackException, que tem type, rendererIndex e outros campos específicos do ExoPlayer.

O exemplo a seguir mostra como detectar quando uma reprodução falhou devido a um Problema de rede 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.
          }
        }
      }
    });

Transições de playlists

sempre que o player mudar para um novo item de mídia na playlist. onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) é chamado no estado registrado objetos Player.Listener. O motivo indica se este foi um processo transição, uma busca (por exemplo, depois de chamar player.next()), uma repetição de o mesmo item ou por uma mudança na playlist (por exemplo, se o evento o item em reprodução é removido).

Metadados

Os metadados retornados de player.getCurrentMediaMetadata() podem mudar devido a muitos motivos: transições de listas de reprodução, atualizações de metadados in-stream ou atualização do MediaItem no meio da reprodução atual.

Se você estiver interessado em alterações de metadados, por exemplo, para atualizar uma interface que mostra o título atual, você pode ouvir onMediaMetadataChanged.

Procurando

Chamar métodos Player.seekTo resulta em uma série de callbacks para registros Player.Listener instâncias:

  1. onPositionDiscontinuity com reason=DISCONTINUITY_REASON_SEEK. Isso é o resultado direto da chamada de Player.seekTo. O callback tem PositionInfo para a posição antes e depois da busca.
  2. onPlaybackStateChanged por qualquer mudança imediata de estado relacionada à busca. Talvez não haja essa mudança.

Callbacks individuais x onEvents

Os listeners podem escolher entre implementar callbacks individuais, como onIsPlayingChanged(boolean isPlaying), e a abordagem genérica onEvents(Player player, Events events). A chamada de retorno genérica fornece acesso ao objeto Player e especifica o conjunto de events que ocorreu juntas. Esse retorno de chamada é sempre chamado após os callbacks que correspondem ao os eventos individuais.

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

É recomendável dar preferência a eventos individuais nos seguintes casos:

  • O listener está interessado nos motivos das alterações. Por exemplo, o motivos fornecidos para onPlayWhenReadyChanged ou onMediaItemTransition.
  • O listener só atua sobre os novos valores fornecidos pelos parâmetros de callback ou aciona outra coisa que não dependa dos parâmetros de callback.
  • A implementação do listener prefere uma indicação clara e legível do que acionou o evento no nome do método.
  • O ouvinte se reporta a um sistema analítico que precisa saber tudo eventos individuais e alterações de estado.

O onEvents(Player player, Events events) genérico tem preferência na seguintes casos:

  • O listener quer acionar a mesma lógica para vários eventos. Para exemplo, atualizar uma IU para onPlaybackStateChanged e onPlayWhenReadyChanged.
  • O listener precisa acessar o objeto Player para acionar outros eventos. por exemplo, busca após uma transição de item de mídia.
  • O listener pretende usar vários valores de estado que são relatados usando callbacks separados ou em combinação com o getter Player. métodos. Por exemplo, usar Player.getCurrentWindowIndex() com o O Timeline informado no onTimelineChanged só é seguro no onEvents.
  • O listener está interessado em saber se os eventos ocorreram logicamente juntos. Para exemplo, de onPlaybackStateChanged a STATE_BUFFERING devido a um item de mídia a transição.

Em alguns casos, os listeners podem precisar combinar os callbacks individuais com o callback onEvents genérico, por exemplo, para registrar os motivos de mudança do item de mídia. com onMediaItemTransition, mas só atuam quando todas as mudanças de estado podem ser usadas em onEvents.

Como usar o AnalyticsListener

Ao usar ExoPlayer, um AnalyticsListener pode ser registrado com o jogador chame addAnalyticsListener. AnalyticsListener implementações podem para detectar eventos detalhados que podem ser úteis para análises e registros propósitos. Consulte a página de análises para mais detalhes.

Como usar o EventLogger

EventLogger é um AnalyticsListener fornecido diretamente pela biblioteca para para fins de geração de registros. Adicionar EventLogger a um ExoPlayer para ativar métricas geração de registros adicional com uma única linha:

Kotlin

player.addAnalyticsListener(EventLogger())

Java

player.addAnalyticsListener(new EventLogger());

Consulte a página de geração de registros de depuração para saber mais.

Disparar eventos em posições de reprodução específicas

Alguns casos de uso exigem o disparo de eventos em posições de reprodução especificadas. Isso é compatível com o uso de PlayerMessage. Um PlayerMessage pode ser criado usando ExoPlayer.createMessage. A posição de reprodução em que ele deve ser executado podem ser definidas usando PlayerMessage.setPosition. As mensagens são executadas sequência de reprodução por padrão, mas isso pode ser personalizado usando PlayerMessage.setLooper: PlayerMessage.setDeleteAfterDelivery pode ser usado para controlar se a mensagem será executada sempre que a mensagem posição de reprodução for encontrada (isso pode acontecer várias vezes devido à busca e repetir) ou apenas na primeira vez. Quando o PlayerMessage for configurado, ele pode ser programado usando 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();