재생목록

재생목록 API는 모든 ExoPlayer 구현으로 구현되는 Player 인터페이스로 정의됩니다. 재생목록을 사용하면 여러 미디어 항목을 순차적으로 재생할 수 있습니다. 다음 예는 동영상 2개가 포함된 재생목록의 재생을 시작하는 방법을 보여줍니다.

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

재생목록 항목 간 전환이 원활하게 이루어집니다. 동일한 형식일 필요는 없습니다. 예를 들어 재생목록에 H264 동영상과 VP9 동영상을 모두 포함해도 괜찮습니다. 유형은 다양할 수도 있습니다. 즉, 재생목록에 동영상과 오디오 전용 스트림을 모두 포함해도 괜찮습니다. 재생목록 내에서 동일한 MediaItem를 여러 번 사용할 수 있습니다.

재생목록 수정

미디어 항목을 추가, 이동, 삭제 또는 교체하여 재생목록을 동적으로 수정할 수 있습니다. 상응하는 재생목록 API 메서드를 호출하면 재생 전과 재생 중에 모두 이 작업을 실행할 수 있습니다.

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

전체 재생목록 바꾸기 및 삭제도 지원됩니다.

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

플레이어는 재생 중에 올바른 방식으로 수정사항을 자동으로 처리합니다.

  • 현재 재생 중인 MediaItem를 이동하면 재생이 중단되지 않고 완료 시 새로운 후속 광고가 재생됩니다.
  • 현재 재생 중인 MediaItem가 삭제되면 플레이어는 자동으로 남은 첫 번째 후속 곡을 재생하거나 이러한 후속 후속 광고가 없으면 종료 상태로 전환됩니다.
  • 현재 재생 중인 MediaItem가 교체되는 경우 재생과 관련된 MediaItem의 속성이 변경되지 않아도 재생이 중단되지 않습니다. 예를 들어 대부분의 경우 재생에 영향을 주지 않고 MediaItem.MediaMetadata 필드를 업데이트할 수 있습니다.

재생목록 쿼리

재생목록은 Player.getMediaItemCountPlayer.getMediaItemAt를 사용하여 쿼리할 수 있습니다. 현재 재생 중인 미디어 항목은 Player.getCurrentMediaItem를 호출하여 쿼리할 수 있습니다. 재생목록 탐색을 간소화하는 Player.hasNextMediaItem 또는 Player.getNextMediaItemIndex와 같은 다른 편의 메서드도 있습니다.

반복 모드

플레이어는 Player.setRepeatMode로 언제든지 설정할 수 있는 3가지 반복 모드를 지원합니다.

  • 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.seekToNextMediaItemplayer.getCurrentMediaItemIndex() + 1에서 항목을 재생하지 않고 셔플 순서에 따라 다음 항목을 재생합니다. 재생목록에 새 항목을 삽입하거나 항목을 삭제하면 기존의 셔플된 순서가 변경되지 않고 최대한으로 유지됩니다.

맞춤 셔플 순서 설정

기본적으로 플레이어는 DefaultShuffleOrder를 사용하여 무작위 섞기를 지원합니다. 맞춤 셔플 순서 구현을 제공하거나 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);

재생목록 항목 확인

재생목록 항목을 식별하려면 항목을 빌드할 때 MediaItem.mediaId를 설정하면 됩니다.

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

앱이 미디어 항목의 미디어 ID를 명시적으로 정의하지 않으면 URI의 문자열 표현이 사용됩니다.

앱 데이터를 재생목록 항목과 연결

ID 외에도 각 미디어 항목은 맞춤 태그(앱에서 제공하는 객체일 수 있음)로 구성할 수도 있습니다. 맞춤 태그의 한 가지 용도는 각 미디어 항목에 메타데이터를 첨부하는 것입니다.

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

재생이 다른 미디어 항목으로 전환될 때 감지

재생이 다른 미디어 항목으로 전환되거나 동일한 미디어 항목을 반복하기 시작하면 Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason)가 호출됩니다. 이 콜백은 전환이 발생한 이유를 나타내는 @MediaItemTransitionReason와 함께 새 미디어 항목을 수신합니다. onMediaItemTransition의 일반적인 사용 사례는 새 미디어 항목에 관해 앱의 UI를 업데이트하는 것입니다.

Kotlin

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

Java

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

맞춤 태그를 사용하여 UI를 업데이트하는 데 필요한 메타데이터가 각 미디어 항목에 첨부되는 경우 구현은 다음과 같습니다.

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

재생목록 변경 시 감지

미디어 항목이 추가, 삭제 또는 이동하면 Listener.onTimelineChanged(Timeline, @TimelineChangeReason)TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED를 통해 즉시 호출됩니다. 이 콜백은 플레이어가 아직 준비되지 않은 경우에도 호출됩니다.

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

재생목록에 있는 미디어 항목의 재생 시간과 같은 정보를 사용할 수 있게 되면 Timeline가 업데이트되고 onTimelineChangedTIMELINE_CHANGE_REASON_SOURCE_UPDATE와 함께 호출됩니다. 타임라인 업데이트가 발생할 수 있는 다른 이유는 다음과 같습니다.

  • 적응형 미디어 항목을 준비한 후 사용할 수 있는 매니페스트
  • 라이브 스트림이 재생되는 동안 주기적으로 업데이트되는 매니페스트입니다.