Playlists

A API Playlist é definida pela interface Player, que é implementada por todas as implementações de ExoPlayer. As playlists permitem a reprodução sequencial de vários itens de mídia. O exemplo a seguir mostra como iniciar a reprodução de uma playlist com dois vídeos:

Kotlin

// Build the media items.
val firstItem = MediaItem.fromUri(firstVideoUri)
val secondItem = MediaItem.fromUri(secondVideoUri)
// Add the media items to be played.
player.addMediaItem(firstItem)
player.addMediaItem(secondItem)
// Prepare the player.
player.prepare()
// Start the playback.
player.play()

Java

// Build the media items.
MediaItem firstItem = MediaItem.fromUri(firstVideoUri);
MediaItem secondItem = MediaItem.fromUri(secondVideoUri);
// Add the media items to be played.
player.addMediaItem(firstItem);
player.addMediaItem(secondItem);
// Prepare the player.
player.prepare();
// Start the playback.
player.play();

As transições entre os itens de uma playlist são perfeitas. Não há exigência de que eles sejam do mesmo formato. Por exemplo, uma playlist pode ter vídeos em H264 e VP9. Eles podem até ser de tipos diferentes (ou seja, não há problema em uma playlist ter vídeos, imagens e streams de áudio). É possível usar o mesmo MediaItem várias vezes em uma playlist.

Como modificar a playlist

Você pode modificar uma playlist de forma dinâmica adicionando, movendo, removendo ou substituindo itens de mídia. Isso pode ser feito antes e durante a reprodução chamando os métodos correspondentes da API Playlist:

Kotlin

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri))
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0)
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0)
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri))

Java

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri));
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0);
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0);
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri));

Também é possível substituir e limpar a playlist inteira:

Kotlin

// Replaces the playlist with a new one.
val newItems: List<MediaItem> = listOf(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri))
player.setMediaItems(newItems, /* resetPosition= */ true)
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems()

Java

// Replaces the playlist with a new one.
ImmutableList<MediaItem> newItems =
    ImmutableList.of(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri));
player.setMediaItems(newItems, /* resetPosition= */ true);
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems();

O player processa automaticamente as modificações durante a reprodução da maneira correta:

  • Se o MediaItem em reprodução for movido, a reprodução não será interrompida, e o novo sucessor será reproduzido após a conclusão.
  • Se o MediaItem em reprodução for removido, o player vai tocar automaticamente o primeiro sucessor restante ou fazer a transição para o estado finalizado se não houver um sucessor.
  • Se o MediaItem em reprodução for substituído, a reprodução não será interrompida se nenhuma das propriedades no MediaItem relevante para a reprodução for alterada. Por exemplo, é possível atualizar os campos MediaItem.MediaMetadata na maioria dos casos sem afetar a reprodução.

Consultar a playlist

A playlist pode ser consultada usando Player.getMediaItemCount e Player.getMediaItemAt. O item de mídia em reprodução no momento pode ser consultado chamando Player.getCurrentMediaItem. Há também outros métodos convenientes, como Player.hasNextMediaItem ou Player.getNextMediaItemIndex, para simplificar a navegação na playlist.

Modos de repetição

O player é compatível com três modos de repetição que podem ser definidos a qualquer momento com Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: a playlist não é repetida, e o player faz a transição para Player.STATE_ENDED depois que o último item da playlist é reproduzido.
  • Player.REPEAT_MODE_ONE: o item atual é repetido em um loop sem fim. Métodos como Player.seekToNextMediaItem ignoram isso e buscam o próximo item na lista, que é repetido em um loop infinito.
  • Player.REPEAT_MODE_ALL: toda a playlist é repetida em um loop infinito.

Modo aleatório

O modo aleatório pode ser ativado ou desativado a qualquer momento com Player.setShuffleModeEnabled. No modo aleatório, o player toca a playlist em uma ordem aleatória pré-calculada. Todos os itens serão tocados uma vez, e o modo aleatório também pode ser combinado com Player.REPEAT_MODE_ALL para repetir a mesma ordem aleatória em um loop infinito. Quando o modo aleatório é desativado, a reprodução continua do item atual na posição original dele na playlist.

Os índices retornados por métodos como Player.getCurrentMediaItemIndex sempre se referem à ordem original e não aleatória. Da mesma forma, Player.seekToNextMediaItem não vai tocar o item em player.getCurrentMediaItemIndex() + 1, mas o próximo item de acordo com a ordem aleatória. Inserir ou remover itens da playlist mantém a ordem aleatória atual inalterada na medida do possível.

Definir uma ordem aleatória personalizada

Por padrão, o player oferece suporte à reprodução aleatória usando o DefaultShuffleOrder. Isso pode ser personalizado fornecendo uma implementação de ordem aleatória personalizada ou definindo uma ordem personalizada no construtor DefaultShuffleOrder:

Kotlin

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(DefaultShuffleOrder(intArrayOf(3, 1, 0, 4, 2), randomSeed))
// Enable shuffle mode.
exoPlayer.shuffleModeEnabled = true

Java

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(new DefaultShuffleOrder(new int[] {3, 1, 0, 4, 2}, randomSeed));
// Enable shuffle mode.
exoPlayer.setShuffleModeEnabled(/* shuffleModeEnabled= */ true);

Identificar itens da playlist

Para identificar itens de playlist, MediaItem.mediaId pode ser definido ao criar o item:

Kotlin

// Build a media item with a media ID.
val mediaItem = MediaItem.Builder().setUri(uri).setMediaId(mediaId).build()

Java

// Build a media item with a media ID.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setMediaId(mediaId).build();

Se um app não definir explicitamente um ID de mídia para um item de mídia, a representação de string do URI será usada.

Como associar dados de apps a itens de playlists

Além de um ID, cada item de mídia também pode ser configurado com uma tag personalizada, que pode ser qualquer objeto fornecido pelo app. Um uso de tags personalizadas é anexar metadados a cada item de mídia:

Kotlin

// Build a media item with a custom tag.
val mediaItem = MediaItem.Builder().setUri(uri).setTag(metadata).build()

Java

// Build a media item with a custom tag.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setTag(metadata).build();

Detectar quando a reprodução muda para outro item de mídia

Quando a reprodução passa para outro item de mídia ou começa a repetir o mesmo item, Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) é chamado. Esse callback recebe o novo item de mídia, além de um @MediaItemTransitionReason que indica o motivo da transição. Um caso de uso comum de onMediaItemTransition é atualizar a interface do app para o novo item de mídia:

Kotlin

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  updateUiForPlayingMediaItem(mediaItem)
}

Java

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  updateUiForPlayingMediaItem(mediaItem);
}

Se os metadados necessários para atualizar a interface estiverem anexados a cada item de mídia usando tags personalizadas, uma implementação poderá ser assim:

Kotlin

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  var metadata: CustomMetadata? = null
  mediaItem?.localConfiguration?.let { localConfiguration ->
    metadata = localConfiguration.tag as? CustomMetadata
  }
  updateUiForPlayingMediaItem(metadata)
}

Java

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  @Nullable CustomMetadata metadata = null;
  if (mediaItem != null && mediaItem.localConfiguration != null) {
    metadata = (CustomMetadata) mediaItem.localConfiguration.tag;
  }
  updateUiForPlayingMediaItem(metadata);
}

Detectar quando a playlist muda

Quando um item de mídia é adicionado, removido ou movido, Listener.onTimelineChanged(Timeline, @TimelineChangeReason) é chamado imediatamente com TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Esse callback é chamado mesmo quando o player ainda não foi preparado.

Kotlin

override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
  if (reason == Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline)
  }
}

Java

@Override
public void onTimelineChanged(Timeline timeline, @TimelineChangeReason int reason) {
  if (reason == TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline);
  }
}

Quando informações como a duração de um item de mídia na playlist ficam disponíveis, o Timeline é atualizado e o onTimelineChanged é chamado com TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Outros motivos que podem causar uma atualização da linha do tempo incluem:

  • Um manifesto fica disponível depois de preparar um item de mídia adaptável.
  • Um manifesto atualizado periodicamente durante a reprodução de uma transmissão ao vivo.