재생목록

재생목록 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()

자바

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

자바

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

자바

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

자바

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

자바

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

자바

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

자바

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

자바

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

자바

@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를 사용하여 호출됩니다. 타임라인 업데이트의 다른 원인에는 다음이 포함됩니다.

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