미디어 앱에는 종종 계층 구조로 정리된 미디어 항목 모음이 포함됩니다. 예를 들어 앨범의 노래 또는 재생목록의 TV 에피소드입니다. 이러한 미디어 항목 계층 구조를 미디어 라이브러리라고 합니다.
MediaLibraryService는 미디어 라이브러리를 제공하고 액세스하기 위한 표준화된 API를 제공합니다. 예를 들어 미디어 라이브러리에 자체 드라이버 안전 UI를 제공하는 미디어 앱에
Android Auto 지원을 추가할 때 유용할 수 있습니다.
MediaLibraryService 빌드
MediaLibraryService 구현은 MediaSessionService 구현과 비슷하지만, onGetSession() 메서드에서 MediaSession 대신 MediaLibrarySession을 반환해야 합니다.
Kotlin
class PlaybackService : MediaLibraryService() { private var mediaLibrarySession: MediaLibrarySession? = null private val callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback { /* ... */ } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? { // If desired, validate the controller before returning the media library session return mediaLibrarySession } // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Java
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() { /* ... */ }; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
Service 및 필수 권한도 선언해야 합니다.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
서비스를 플랫폼 및 Media3 서비스 인터페이스로 등록하는 것이 좋습니다.
플랫폼 미디어 세션 API를 사용하는 클라이언트와의 호환성을 위해
<action android:name="android.media.browse.MediaBrowserService"/>를intent-filter요소에 포함하는 것이 좋습니다. Media3은 이 서비스 인터페이스에 이전 버전과의 호환성을 자동으로 제공합니다.향후에도 사용할 수 있는 설정으로 Media3을 사용하는 앱이 Media3 API를 사용하여 서비스와 통신할 수 있도록 서비스와 함께
<action android:name="androidx.media3.session.MediaLibraryService"/>를 제공해야 합니다.
이렇게 하면 앱이 PackageManager를 통해 서비스를 찾고 이러한 인터페이스 중 하나를 통해 MediaBrowser와 연결할 수 있습니다.
MediaLibrarySession 사용
MediaLibraryService API는 미디어 라이브러리가 단일 루트 노드와 재생 가능하거나 추가로 탐색할 수 있는 하위 노드가 있는
트리 형식으로 구성될 것으로 예상합니다.
MediaLibrarySession은 MediaSession API를 확장하여 콘텐츠
탐색 API를 추가합니다. MediaSession 콜백과 비교하여
MediaLibrarySession 콜백은 다음과 같은 메서드를 추가합니다.
onGetLibraryRoot()클라이언트가 콘텐츠 트리의 루트MediaItem를 요청할 때의onGetChildren()클라이언트가 콘텐츠 트리의MediaItem하위 요소를 요청할 때onGetSearchResult()클라이언트가 지정된 쿼리에 대해 콘텐츠 트리에서 검색 결과를 요청할 때
관련 콜백 메서드에는 LibraryParams 객체와
클라이언트 앱이
관심을 갖는 콘텐츠 트리 유형에 관한 추가 신호가 포함됩니다.
미디어 항목의 명령어 버튼
세션 앱은 MediaMetadata에서 MediaItem이 지원하는 명령어 버튼을 선언할 수 있습니다. 이렇게 하면 컨트롤러가 표시하고 편리한 방법으로 항목의 맞춤 명령어를 세션으로 전송하는 데 사용할 수 있는 미디어 항목에 하나 이상의 CommandButton 항목을 할당할 수 있습니다.
세션 측에서 명령어 버튼 설정
세션을 빌드할 때 세션 앱은 세션이 맞춤 명령어로 처리할 수 있는 명령어 버튼 집합을 선언합니다.
Kotlin
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Java
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
미디어 항목을 빌드할 때 세션 앱은 세션을 빌드할 때 설정된 명령어 버튼의 세션 명령어를 참조하는 지원되는 명령어 ID 집합을 추가할 수 있습니다.
Kotlin
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build() ) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
컨트롤러 또는 브라우저가 세션 Callback의 다른 메서드를 연결하거나 호출하면 세션 앱은 콜백에 전달된 ControllerInfo를 검사하여 컨트롤러 또는 브라우저가 표시할 수 있는 최대 명령어 버튼 수를 가져올 수 있습니다. 콜백 메서드에 전달된 ControllerInfo는 이 값에 편리하게 액세스할 수 있는 getter를 제공합니다. 기본적으로 값은 0으로 설정되며 이는 브라우저 또는 컨트롤러가 이 기능을 지원하지 않음을 나타냅니다.
Kotlin
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems) return settableFuture }
Java
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
미디어 항목에 전송된 맞춤 작업을 처리할 때 세션 앱은 onCustomCommand에 전달된 인수 Bundle에서 미디어 항목 ID를 가져올 수 있습니다.
Kotlin
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Java
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
명령어 버튼을 브라우저 또는 컨트롤러로 사용
MediaController 측에서 앱은 MediaController 또는 MediaBrowser를 빌드할 때 미디어 항목에 지원하는 최대 명령어 버튼 수를 선언할 수 있습니다.
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync()
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();
세션에 연결되면 컨트롤러 앱은 미디어 항목에서 지원되고 컨트롤러에 세션 앱에서 부여한 사용 가능한 명령어가 있는 명령어 버튼을 수신할 수 있습니다.
Kotlin
val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)
Java
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Kotlin
val future = controller.sendCustomCommand( requireNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY, )
자바
ListenableFuture<SessionResult> future = controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);