플레이어 인터페이스

플레이어는 미디어 항목의 재생을 용이하게 하는 앱의 구성요소입니다. Media3 Player 인터페이스는 일반적으로 플레이어에서 처리하는 기능의 개요를 설정합니다. 여기에는 다음이 포함됩니다.

  • 재생, 일시중지, 탐색 등 재생 컨트롤에 영향을 줌
  • 재생 위치와 같은 현재 재생 중인 미디어의 속성 쿼리
  • 미디어 항목의 재생목록/대기열 관리
  • 무작위 섞기, 반복, 속도, 볼륨과 같은 재생 속성 구성
  • 화면에 동영상 렌더링

Media3은 ExoPlayer라는 Player 인터페이스 구현도 제공합니다.

구성요소 간의 공통 인터페이스

Media3의 여러 구성요소는 플레이어 인터페이스를 구현합니다. 예를 들면 다음과 같습니다.

구성요소 설명 및 행동 참고사항
ExoPlayer 미디어 플레이어 API 및 Player 인터페이스의 기본 구현
MediaController MediaSession와 상호작용하여 재생 명령어를 전송합니다. PlayerMediaSession가 플레이어의 UI가 있는 Activity 또는 Fragment와 별개인 Service에 있는 경우 MediaControllerPlayerView UI 플레이어로 할당할 수 있습니다. 재생 및 재생목록 메서드 호출은 MediaSession를 통해 Player로 전송됩니다.
MediaBrowser MediaController에서 제공하는 기능 외에도 MediaLibrarySession와 상호작용하여 사용 가능한 미디어 콘텐츠를 탐색합니다.
ForwardingPlayer 메서드 호출을 다른 Player로 전달하는 Player 구현입니다. 이 클래스를 사용하면 각 메서드를 재정의하여 특정 작업을 억제하거나 수정할 수 있습니다.
SimpleBasePlayer 구현할 메서드 수를 최소한으로 줄이는 Player 구현입니다. MediaSession에 연결하려는 맞춤 플레이어를 사용할 때 유용합니다.
CastPlayer Cast 수신기 앱과 통신하는 Player 구현. 동작은 기본 전송 세션에 따라 다릅니다.

MediaSessionPlayer 인터페이스를 구현하지 않지만 인터페이스를 만들 때 Player가 필요합니다. 목적은 다른 프로세스나 스레드에서 Player에 액세스할 수 있도록 하는 것입니다.

Media3 재생 아키텍처

Player에 액세스할 수 있다면 메서드를 직접 호출하여 재생 명령어를 실행해야 합니다. MediaSession를 구현하여 재생을 알리고 외부 소스 재생 제어 권한을 부여할 수 있습니다. 이러한 외부 소스는 미디어 세션에 연결하고 재생 명령어 요청을 실행하는 데 도움이 되는 MediaController를 구현합니다.

백그라운드에서 미디어를 재생할 때 포그라운드 서비스로 실행되는 MediaSessionService 또는 MediaLibraryService 내에 미디어 세션과 플레이어를 보관해야 합니다. 이렇게 하면 재생 컨트롤 UI가 포함된 앱의 활동과 플레이어를 분리할 수 있습니다. 이 경우 미디어 컨트롤러를 사용해야 할 수도 있습니다.

Media3 재생 구성요소가 미디어 앱 아키텍처에 어떻게 적용되는지 보여주는 다이어그램
그림 1: Player 인터페이스는 Media3 아키텍처에서 핵심 역할을 합니다.

플레이어 상태

Player 인터페이스를 구현하는 미디어 플레이어의 상태는 주로 4가지 정보 카테고리로 구성됩니다.

  1. 재생 상태
  2. 미디어 항목 재생목록
    • 재생을 위한 MediaItem 인스턴스의 시퀀스입니다.
    • getCurrentTimeline()로 검색
    • Player 인스턴스는 MediaItem 추가 또는 삭제와 같은 재생목록 작업 메서드 및 getCurrentMediaItem()와 같은 편의 메서드를 제공할 수 있습니다.
  3. 다음과 같은 재생/일시중지 속성:
    • playWhenReady: 사용자가 미디어를 재생할 수 있을 때 재생하기를 원하는지 아니면 일시중지 상태를 유지하기를 원하는지 표시합니다.
    • 재생 제거 이유: 해당하는 경우 playWhenReadytrue인 경우에도 재생이 억제된 이유 표시
    • isPlaying: 플레이어가 현재 재생 중인지에 관한 표시로, 재생 상태가 STATE_READY이고 playWhenReadytrue이며 재생이 억제되지 않은 경우에만 true입니다.
  4. 다음을 포함한 재생 위치:

또한 Player 인터페이스를 사용하면 사용 가능한 트랙, 미디어 메타데이터, 재생 속도, 볼륨 및 재생의 기타 보조 속성에 액세스할 수 있습니다.

변경사항 수신 대기

Player.Listener를 사용하여 Player의 변경사항을 수신 대기합니다. 리스너를 만들고 사용하는 방법에 관한 자세한 내용은 플레이어 이벤트에 관한 ExoPlayer 문서를 참고하세요.

리스너 인터페이스에는 정상적인 재생 진행을 추적하는 콜백이 포함되어 있지 않습니다. 재생 진행률을 지속적으로 모니터링하려면(예: 진행률 표시줄 UI 설정) 적절한 간격으로 현재 위치를 쿼리해야 합니다.

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

재생 제어

Player 인터페이스는 상태를 조작하고 재생을 제어하는 다양한 방법을 제공합니다.

맞춤 Player 구현

맞춤 플레이어를 만들려면 Media3에 포함된 SimpleBasePlayer를 확장하면 됩니다. 이 클래스는 Player 인터페이스의 기본 구현을 제공하여 구현해야 하는 메서드의 수를 최소한으로 줄입니다.

먼저 getState() 메서드를 재정의합니다. 이 메서드는 호출 시 다음을 포함하여 현재 플레이어 상태를 채워야 합니다.

  • 사용 가능한 명령어 집합
  • 재생 속성(예: 재생 상태가 STATE_READY일 때 플레이어의 재생 시작 여부, 현재 재생 중인 미디어 항목의 색인, 현재 항목 내 재생 위치)

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer는 유효한 상태 값 조합으로 State가 생성되도록 합니다. 또한 리스너를 처리하고 리스너에 상태 변경사항을 알립니다. 상태 업데이트를 수동으로 트리거해야 하는 경우 invalidateState()를 호출합니다.

getState() 메서드 외에는 플레이어가 사용 가능하다고 선언한 명령어에 사용되는 메서드만 구현하면 됩니다. 구현하려는 기능에 해당하는 재정의 가능한 핸들러 메서드를 찾습니다. 예를 들어 COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM과 같은 작업을 지원하도록 handleSeek() 메서드를 재정의합니다.