Playlist

L'API playlist è definita dall'interfaccia Player, che viene implementata da tutte le implementazioni ExoPlayer. Le playlist consentono la riproduzione sequenziale di più elementi multimediali. L'esempio seguente mostra come avviare la riproduzione di una playlist contenente due video:

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

Le transizioni tra gli elementi di una playlist sono fluide. Non è necessario che abbiano lo stesso formato (ad esempio, le playlist possono contenere sia video H264 sia video VP9). Possono anche essere di tipi diversi (in altre parole, una playlist deve contenere sia stream video sia stream solo audio). Puoi usare lo stesso MediaItem più volte all'interno di una playlist.

Modifica della playlist

Puoi modificare una playlist in modo dinamico aggiungendo, spostando, rimuovendo o sostituendo gli elementi multimediali. Questa operazione può essere eseguita sia prima che durante la riproduzione chiamando i metodi dell'API playlist corrispondenti:

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

Sono supportate anche la sostituzione e la cancellazione dell'intera playlist:

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

Il player gestisce automaticamente le modifiche durante la riproduzione nel modo corretto:

  • Se viene spostato l'oggetto MediaItem attualmente in riproduzione, la riproduzione non viene interrotta e il nuovo successore verrà riprodotto al termine.
  • Se l'elemento MediaItem attualmente in riproduzione viene rimosso, il giocatore giocherà automaticamente il primo successore rimanente o passerà allo stato "Terminato" se non esiste.
  • Se il valore MediaItem attualmente in riproduzione viene sostituito, la riproduzione non viene interrotta se nessuna delle proprietà in MediaItem pertinente alla riproduzione è cambiata. Ad esempio, nella maggior parte dei casi è possibile aggiornare i campi MediaItem.MediaMetadata senza influire sulla riproduzione.

Esecuzione di query sulla playlist

È possibile eseguire query sulla playlist utilizzando Player.getMediaItemCount e Player.getMediaItemAt. È possibile eseguire query sull'elemento multimediale attualmente in riproduzione chiamando Player.getCurrentMediaItem. Esistono anche altri metodi come Player.hasNextMediaItem o Player.getNextMediaItemIndex per semplificare la navigazione nella playlist.

Modalità di ripetizione

Il player supporta tre modalità di ripetizione che possono essere impostate in qualsiasi momento con Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: la playlist non viene ripetuta e il player passerà a Player.STATE_ENDED una volta riprodotto l'ultimo elemento della playlist.
  • Player.REPEAT_MODE_ONE: l'elemento corrente viene ripetuto in un ciclo infinito. Metodi come Player.seekToNextMediaItem lo ignorano e cercano l'elemento successivo nell'elenco, che verrà poi ripetuto in un ciclo infinito.
  • Player.REPEAT_MODE_ALL: l'intera playlist viene ripetuta in un loop infinito.

Modalità casuale

La modalità casuale può essere attivata o disattivata in qualsiasi momento con Player.setShuffleModeEnabled. In modalità di riproduzione casuale, il player riprodurrà la playlist in ordine casuale precalcolato. Tutti gli elementi verranno riprodotti una volta e la modalità di riproduzione casuale può essere anche combinata con Player.REPEAT_MODE_ALL per ripetere lo stesso ordine casuale in un loop infinito. Quando la modalità di riproduzione casuale non è attiva, la riproduzione continua dall'elemento corrente nella posizione originale nella playlist.

Tieni presente che gli indici restituiti da metodi come Player.getCurrentMediaItemIndex fanno sempre riferimento all'ordine originale non casuale. Allo stesso modo, Player.seekToNextMediaItem non riprodurrà l'elemento al minuto player.getCurrentMediaItemIndex() + 1, ma l'elemento successivo in base all'ordine casuale. L'inserimento di nuovi elementi nella playlist o la loro rimozione manterrà invariato l'ordine casuale esistente.

Impostazione di un ordine casuale personalizzato

Per impostazione predefinita, il player supporta la riproduzione casuale tramite DefaultShuffleOrder. Questa opzione può essere personalizzata fornendo un'implementazione personalizzata di ordine casuale o impostando un ordine personalizzato nel costruttore 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);

Identificazione degli elementi della playlist

Per identificare gli elementi della playlist, puoi impostare MediaItem.mediaId durante la creazione dell'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();

Se un'app non definisce esplicitamente un ID multimediale per un elemento multimediale, viene utilizzata la rappresentazione stringa dell'URI.

Associazione dei dati dell'app a elementi della playlist

Oltre a un ID, ogni elemento multimediale può essere configurato anche con un tag personalizzato, che può essere qualsiasi oggetto fornito dall'app. I tag personalizzati possono essere utilizzati per collegare i metadati a ciascun elemento multimediale:

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

Rilevamento delle transizioni della riproduzione a un altro elemento multimediale

Quando la riproduzione passa a un altro elemento multimediale o inizia a ripetere lo stesso elemento multimediale, viene richiamato Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason). Questo callback riceve il nuovo elemento multimediale, insieme a un @MediaItemTransitionReason che indica il motivo della transizione. Un caso d'uso comune per onMediaItemTransition è aggiornare l'interfaccia utente dell'app per il nuovo elemento multimediale:

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 i metadati necessari per aggiornare l'interfaccia utente sono allegati a ogni elemento multimediale utilizzando tag personalizzati, l'implementazione potrebbe essere simile a:

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

Rilevamento del cambio di playlist

Quando un elemento multimediale viene aggiunto, rimosso o spostato, Listener.onTimelineChanged(Timeline, @TimelineChangeReason) viene chiamato immediatamente con TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Questo callback viene richiamato anche quando il player non è ancora pronto.

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 informazioni come la durata di un elemento multimediale nella playlist diventano disponibili, Timeline viene aggiornato e onTimelineChanged viene chiamato con TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Altri motivi che possono causare un aggiornamento della cronologia sono:

  • Un file manifest che diventa disponibile dopo la preparazione di un elemento multimediale adattivo.
  • Un file manifest che viene aggiornato periodicamente durante la riproduzione di un live streaming.