Playlists

La API de la playlist se define mediante la interfaz de Player, que se implementa en todas las implementaciones de ExoPlayer. Estas permiten la reproducción secuencial de varios elementos multimedia. El siguiente ejemplo muestra cómo iniciar la reproducción de una lista de reproducción que contiene dos videos:

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

Las transiciones entre elementos de una lista de reproducción son perfectas. No hay ningún requisito de que tengan el mismo formato (por ejemplo, está bien que una lista de reproducción contenga videos H264 y VP9). Incluso pueden ser de diferentes tipos (es decir, está bien que una playlist contenga tanto videos como transmisiones de solo audio). Puedes usar el mismo MediaItem varias veces dentro de una lista de reproducción.

Cómo modificar la playlist

Para modificar una playlist de forma dinámica, puedes agregar, mover, quitar o reemplazar elementos multimedia. Esto se puede hacer antes y durante la reproducción llamando a los métodos de la API de playlist correspondientes:

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

También puedes reemplazar y borrar la lista de reproducción completa de la siguiente manera:

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

El reproductor controla automáticamente las modificaciones durante la reproducción de la manera correcta:

  • Si se mueve el MediaItem que se está reproduciendo actualmente, la reproducción no se interrumpirá y se reproducirá su nuevo sucesor cuando finalice.
  • Si se quita la MediaItem que se está reproduciendo actualmente, el reproductor reproducirá automáticamente el primer sucesor restante o pasará al estado finalizado si no existe tal sucesor.
  • Si se reemplaza la MediaItem que se está reproduciendo actualmente, la reproducción no se interrumpe si no se cambia ninguna de las propiedades de la MediaItem relevantes para la reproducción. Por ejemplo, en la mayoría de los casos, es posible actualizar los campos MediaItem.MediaMetadata sin afectar la reproducción.

Consulta de la playlist

La lista de reproducción se puede consultar con Player.getMediaItemCount y Player.getMediaItemAt. Para consultar el elemento multimedia que se está reproduciendo actualmente, se puede llamar a Player.getCurrentMediaItem. También hay otros métodos prácticos, como Player.hasNextMediaItem o Player.getNextMediaItemIndex, para simplificar la navegación en la lista de reproducción.

Modos de repetición

El reproductor admite 3 modos de repetición que se pueden configurar en cualquier momento con Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: La lista de reproducción no se repite, y el reproductor pasará a Player.STATE_ENDED una vez que se haya reproducido el último elemento de la lista.
  • Player.REPEAT_MODE_ONE: El elemento actual se repite en un bucle infinito. Los métodos como Player.seekToNextMediaItem ignorarán esto y buscarán el siguiente elemento de la lista, que luego se repetirá en un bucle infinito.
  • Player.REPEAT_MODE_ALL: Toda la lista de reproducción se repite en un bucle infinito.

Modo aleatorio

El modo aleatorio se puede habilitar o inhabilitar en cualquier momento con Player.setShuffleModeEnabled. Cuando esté en el modo aleatorio, el reproductor reproducirá la lista de reproducción en un orden aleatorio calculado previamente. Todos los elementos se reproducirán una vez, y el modo aleatorio también se puede combinar con Player.REPEAT_MODE_ALL para repetir el mismo orden aleatorio en un bucle infinito. Cuando el modo de reproducción aleatoria está desactivado, la reproducción continúa desde el elemento actual en su posición original en la lista de reproducción.

Ten en cuenta que los índices que muestran métodos como Player.getCurrentMediaItemIndex siempre hacen referencia al orden original sin mezclar. De manera similar, Player.seekToNextMediaItem no reproducirá el elemento en player.getCurrentMediaItemIndex() + 1, sino el siguiente elemento según el orden aleatorio. Cuando insertas nuevos elementos en la lista de reproducción o quitas elementos, se mantiene el orden aleatorio existente sin modificar tanto como sea posible.

Configuración de un orden aleatorio personalizado

De forma predeterminada, el reproductor admite la redistribución mediante DefaultShuffleOrder. Para personalizarlo, proporciona una implementación personalizada de orden aleatorio o establece un orden personalizado en el constructor 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);

Cómo identificar los elementos de una playlist

Para identificar los elementos de la lista de reproducción, se puede configurar MediaItem.mediaId cuando se compila el elemento:

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

Si una app no define explícitamente un ID de contenido multimedia para un elemento multimedia, se usa la representación de string del URI.

Cómo asociar datos de app con elementos de una lista de reproducción

Además de un ID, cada elemento multimedia se puede configurar con una etiqueta personalizada, que puede ser cualquier objeto proporcionado por la app. Un uso de las etiquetas personalizadas es adjuntar metadatos a cada elemento multimedia:

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

Cómo detectar cuándo la reproducción pasa a otro elemento multimedia

Cuando la reproducción pasa a otro elemento multimedia o comienza a repetir el mismo elemento multimedia, se llama a Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason). Esta devolución de llamada recibe el nuevo elemento multimedia, junto con un @MediaItemTransitionReason que indica el motivo de la transición. Un caso de uso común para onMediaItemTransition es actualizar la IU de la app para el nuevo elemento multimedia:

Kotlin

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

Java

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

Si se adjuntan los metadatos necesarios para actualizar la IU a cada elemento multimedia mediante etiquetas personalizadas, la implementación podría tener el siguiente aspecto:

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

Cómo detectar cuándo cambia la playlist

Cuando se agrega, quita o mueve un elemento multimedia, se llama a Listener.onTimelineChanged(Timeline, @TimelineChangeReason) de inmediato con TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Se llama a esta devolución de llamada incluso cuando el reproductor aún no está 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);
  }
}

Cuando haya información disponible, como la duración de un elemento multimedia en la playlist, se actualizará Timeline y se llamará a onTimelineChanged con TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Entre otros motivos que pueden provocar una actualización del cronograma, se incluyen los siguientes:

  • Es un manifiesto que está disponible después de preparar un elemento multimedia adaptable.
  • Es un manifiesto que se actualiza periódicamente durante la reproducción de una transmisión en vivo.