แอปสื่อมักจะมีคอลเล็กชันรายการสื่อที่จัดระเบียบตามลำดับชั้น เช่น เพลงในอัลบั้มหรือตอนของรายการทีวีในเพลย์ลิสต์ ลำดับชั้นของรายการสื่อนี้เรียกว่าคลังสื่อ
MediaLibraryService มี API ที่ได้มาตรฐานเพื่อแสดงและเข้าถึงคลังสื่อของคุณ ซึ่งจะเป็นประโยชน์ เช่น เมื่อเพิ่มการรองรับ Android Auto ลงในแอปสื่อ ซึ่งมี UI ที่ปลอดภัยสำหรับผู้ขับขี่สำหรับคลังสื่อของคุณเอง
สร้าง MediaLibraryService
การติดตั้งใช้งาน MediaLibraryService คล้ายกับการติดตั้งใช้งาน MediaSessionService ยกเว้นว่าในเมธอด onGetSession() คุณควรส่งคืน MediaLibrarySession แทน MediaSession
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 และสิทธิ์ที่จำเป็นในไฟล์ Manifest ด้วย ดังนี้
<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-filterMedia3 จะให้ความเข้ากันได้แบบย้อนหลังกับอินเทอร์เฟซบริการนี้โดยอัตโนมัติคุณควรระบุ
<action android:name="androidx.media3.session.MediaLibraryService"/>ควบคู่ไปกับตัวเลือกแพลตฟอร์มเพื่อเป็นการตั้งค่าที่รองรับอนาคตและเพื่อให้มั่นใจว่าแอปที่ใช้ Media3 จะสื่อสารกับบริการของคุณได้โดยใช้ Media3 API
ซึ่งจะช่วยให้แอปค้นพบบริการของคุณผ่าน PackageManager และเชื่อมต่อกับ MediaBrowser ผ่านอินเทอร์เฟซใดอินเทอร์เฟซหนึ่งเหล่านี้ได้
ใช้ MediaLibrarySession
MediaLibraryService API คาดหวังให้คลังสื่อของคุณมีโครงสร้างในรูปแบบโครงสร้างต้นไม้ โดยมีโหนดรูทเดียวและโหนดลูกที่อาจเล่นได้หรือเรียกดูได้เพิ่มเติม
MediaLibrarySession ขยาย MediaSession API เพื่อเพิ่ม API การเรียกดูเนื้อหา เมื่อเทียบกับ MediaSession Callback แล้ว MediaLibrarySession Callback จะเพิ่มเมธอดต่างๆ เช่น
onGetLibraryRoot()เมื่อไคลเอ็นต์ขอรูทMediaItemของโครงสร้างเนื้อหาonGetChildren()เมื่อไคลเอ็นต์ขอรายการย่อยของMediaItemในโครงสร้างเนื้อหาonGetSearchResult()เมื่อไคลเอ็นต์ขอผลการค้นหาจากโครงสร้างเนื้อหาสำหรับคำค้นหาที่กำหนด
เมธอด Callback ที่เกี่ยวข้องจะมีออบเจ็กต์ LibraryParams พร้อมสัญญาณเพิ่มเติมเกี่ยวกับประเภทของโครงสร้างเนื้อหาที่แอปไคลเอ็นต์สนใจ
ปุ่มคำสั่งสำหรับรายการสื่อ
แอปเซสชันสามารถประกาศปุ่มคำสั่งที่ MediaItem รองรับใน MediaMetadata ได้ ซึ่งช่วยให้สามารถกำหนดรายการ CommandButton อย่างน้อย 1 รายการให้กับรายการสื่อที่ตัวควบคุมสามารถแสดงและใช้เพื่อส่งคำสั่งที่กำหนดเองสำหรับรายการไปยังเซสชันได้อย่างสะดวก
ตั้งค่าปุ่มคำสั่งในฝั่งเซสชัน
เมื่อสร้างเซสชัน แอปเซสชันจะประกาศชุดปุ่มคำสั่งที่เซสชันสามารถจัดการเป็นคำสั่งที่กำหนดเองได้ ดังนี้
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();
เมื่อสร้างรายการสื่อ แอปเซสชันจะเพิ่มชุดรหัสคำสั่งที่รองรับซึ่งอ้างอิงคำสั่งเซสชันของปุ่มคำสั่งที่ตั้งค่าไว้เมื่อสร้างเซสชันได้ ดังนี้
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 ที่ส่งไปยัง Callback เพื่อรับจำนวนปุ่มคำสั่งสูงสุดที่ตัวควบคุมหรือเบราว์เซอร์สามารถแสดงได้ ControllerInfo ที่ส่งไปยังเมธอด Callback จะมี 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; }
เมื่อจัดการการดำเนินการที่กำหนดเองซึ่งส่งมาสำหรับรายการสื่อ แอปเซสชันจะรับรหัสรายการสื่อจากอาร์กิวเมนต์ Bundle ที่ส่งไปยัง onCustomCommand ได้
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, )
Java
ListenableFuture<SessionResult> future = controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);