Плейлисты

API списка воспроизведения определяется интерфейсом Player , который реализован во всех реализациях ExoPlayer . Списки воспроизведения позволяют последовательно воспроизводить несколько элементов мультимедиа. В следующем примере показано, как начать воспроизведение списка воспроизведения, содержащего два видео:

Котлин

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

Джава

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

Переходы между элементами плейлиста плавные. Не требуется, чтобы они были одного формата (например, плейлист может содержать видео H264 и VP9). Они могут даже быть разных типов (то есть список воспроизведения может содержать видео, изображения и только аудиопотоки). Вы можете использовать один и тот же MediaItem несколько раз в списке воспроизведения.

Изменение списка воспроизведения

Вы можете динамически изменять список воспроизведения, добавляя, перемещая, удаляя или заменяя элементы мультимедиа. Это можно сделать как до, так и во время воспроизведения, вызвав соответствующие методы API плейлиста:

Котлин

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

Джава

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

Также поддерживается замена и очистка всего плейлиста:

Котлин

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

Джава

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

Плеер автоматически корректно обрабатывает изменения во время воспроизведения:

  • Если текущий воспроизводимый MediaItem перемещается, воспроизведение не прерывается, а его новый преемник будет воспроизведен после завершения.
  • Если воспроизводимый в данный момент MediaItem удален, проигрыватель автоматически воспроизведет первого оставшегося преемника или перейдет в завершенное состояние, если такого преемника не существует.
  • Если текущий воспроизводимый MediaItem заменяется, воспроизведение не прерывается, если ни одно из свойств MediaItem , релевантных для воспроизведения, не изменилось. Например, в большинстве случаев можно обновить поля MediaItem.MediaMetadata , не влияя на воспроизведение.

Запрос плейлиста

Список воспроизведения можно запросить с помощью Player.getMediaItemCount и Player.getMediaItemAt . Воспроизводимый в данный момент элемент мультимедиа можно запросить, вызвав Player.getCurrentMediaItem . Существуют также другие удобные методы, такие как Player.hasNextMediaItem или Player.getNextMediaItemIndex для упрощения навигации по списку воспроизведения.

Режимы повтора

Плеер поддерживает 3 режима повтора, которые можно установить в любое время с помощью Player.setRepeatMode :

  • Player.REPEAT_MODE_OFF : список воспроизведения не повторяется, и проигрыватель перейдет в Player.STATE_ENDED после воспроизведения последнего элемента в списке воспроизведения.
  • Player.REPEAT_MODE_ONE : текущий элемент повторяется в бесконечном цикле. Такие методы, как Player.seekToNextMediaItem проигнорируют это и перейдут к следующему элементу в списке, который затем будет повторяться в бесконечном цикле.
  • Player.REPEAT_MODE_ALL : весь список воспроизведения повторяется в бесконечном цикле.

Режим перемешивания

Режим перемешивания можно включить или отключить в любое время с помощью Player.setShuffleModeEnabled . В случайном порядке проигрыватель будет воспроизводить список воспроизведения в заранее рассчитанном случайном порядке. Все элементы будут воспроизводиться один раз, а режим перемешивания также можно комбинировать с Player.REPEAT_MODE_ALL для повторения одного и того же случайного порядка в бесконечном цикле. Если режим случайного воспроизведения выключен, воспроизведение продолжается с текущего элемента в его исходном положении в списке воспроизведения.

Обратите внимание, что индексы, возвращаемые такими методами, как Player.getCurrentMediaItemIndex всегда относятся к исходному, неперетасованному порядку. Аналогично, Player.seekToNextMediaItem будет воспроизводить не элемент player.getCurrentMediaItemIndex() + 1 , а следующий элемент в случайном порядке. Вставка новых элементов в список воспроизведения или удаление элементов сохранит существующий порядок в случайном порядке, насколько это возможно.

Установка пользовательского порядка перемешивания

По умолчанию проигрыватель поддерживает перетасовку с помощью DefaultShuffleOrder . Это можно настроить, предоставив собственную реализацию порядка перемешивания или установив собственный порядок в конструкторе DefaultShuffleOrder :

Котлин

// 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

Джава

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

Определение элементов плейлиста

Чтобы идентифицировать элементы списка воспроизведения, MediaItem.mediaId можно установить при создании элемента:

Котлин

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

Джава

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

Если приложение явно не определяет идентификатор мультимедиа для элемента мультимедиа, используется строковое представление URI.

Связывание данных приложения с элементами списка воспроизведения

Помимо идентификатора, каждый элемент мультимедиа также можно настроить с помощью пользовательского тега, который может быть любым объектом, предоставленным приложением. Одним из вариантов использования пользовательских тегов является прикрепление метаданных к каждому элементу мультимедиа:

Котлин

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

Джава

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

Обнаружение перехода воспроизведения к другому элементу мультимедиа

Когда воспроизведение переходит к другому элементу мультимедиа или начинает повторять один и тот же элемент мультимедиа, вызывается Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) . Этот обратный вызов получает новый элемент мультимедиа вместе с @MediaItemTransitionReason , указывающим, почему произошел переход. Распространенным вариантом использования onMediaItemTransition является обновление пользовательского интерфейса приложения для нового элемента мультимедиа:

Котлин

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

Джава

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

Если метаданные, необходимые для обновления пользовательского интерфейса, прикреплены к каждому элементу мультимедиа с помощью пользовательских тегов, то реализация может выглядеть так:

Котлин

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

Джава

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

Обнаружение изменения списка воспроизведения

Когда элемент мультимедиа добавляется, удаляется или перемещается, Listener.onTimelineChanged(Timeline, @TimelineChangeReason) вызывается немедленно с TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED . Этот обратный вызов вызывается, даже если игрок еще не подготовлен.

Котлин

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

Джава

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

Когда такая информация, как продолжительность медиа-элемента в списке воспроизведения, становится доступной, Timeline будет обновлена, и onTimelineChanged будет вызван с TIMELINE_CHANGE_REASON_SOURCE_UPDATE . Другие причины, которые могут вызвать обновление временной шкалы, включают:

  • Манифест становится доступным после подготовки адаптивного медиа-элемента.
  • Манифест периодически обновляется во время воспроизведения прямой трансляции.