برنامههای رسانهای اغلب حاوی مجموعههایی از موارد رسانهای هستند که بهصورت سلسلهمراتبی سازماندهی شدهاند. برای مثال، آهنگهای یک آلبوم یا قسمتهای تلویزیونی در فهرست پخش. این سلسلهمراتب فایلهای رسانهای بهعنوان کتابخانه رسانهای شناخته میشود.
MediaLibraryService میانای برنامهسازی کاربردی استانداردی برای ارائه و دسترسی به
کتابخانه رسانهای شما ارائه میدهد. این کار میتواند مفید باشد، برای مثال، هنگام افزودن پشتیبانی از
Android Auto به برنامه رسانه شما، که واسط کاربر ایمن برای راننده را برای
کتابخانه رسانه شما ارائه میدهد.
ساختن MediaLibraryService
پیادهسازی MediaLibraryService مشابه پیادهسازی
MediaSessionService است، با این تفاوت که در روش onGetSession()،
باید MediaLibrarySession را بهجای MediaSession برگردانید.
کاتلین
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() } }
جاوا
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 ثبت کنید:
برای سازگاری با کارخواههایی که از میاناهای برنامهسازی کاربردی جلسه رسانه پلاتفرم استفاده میکنند، توصیه میشود
<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 را گسترش میدهد تا میاناهای برنامهسازی کاربردی مرور محتوا را اضافه کند. درمقایسه با فراخوانی MediaSession،
فراخوانی MediaLibrarySession روشهایی مثل موارد زیر را اضافه میکند:
onGetLibraryRoot()برای زمانی که مشتری ریشهMediaItemدرخت محتوا را درخواست میکندonGetChildren()برای زمانی که مشتری فرزندان یکMediaItemرا در درخت محتوا درخواست میکندonGetSearchResult()برای زمانی که مشتری نتایج جستجو را از درخت محتوا برای پُرسمان دادهشده درخواست میکند
روشهای فراخوانی مربوطه شامل شیء LibraryParams با
نشانهای اضافی درباره نوع درخت محتوایی است که برنامه مشتری
به آن علاقه دارد.
دکمههای فرمان برای فایلهای رسانهای
برنامه جلسه میتواند دکمههای فرمانی را که توسط MediaItem در MediaMetadata پشتیبانی میشود اعلام کند. این کار امکان اختصاص دادن یک یا چند ورودی CommandButton
به فایل رسانهای را فراهم میکند که کنترلکننده میتواند آن را نمایش دهد و از آن برای ارسال فرمان سفارشی
برای آن مورد به جلسه بهشیوهای راحت استفاده کند.
دکمههای فرمان راهاندازی در طرف جلسه
هنگام ساختن جلسه، برنامه جلسه مجموعهای از دکمههای فرمان را اعلام میکند که جلسه میتواند بهعنوان فرمانهای سفارشی مدیریت کند:
کاتلین
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()
جاوا
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();
هنگام ساختن فایل رسانهای، برنامه جلسه میتواند مجموعهای از شناسههای فرمان پشتیبانیشده را اضافه کند که به فرمانهای جلسه دکمههای فرمان که هنگام ساختن جلسه راهاندازی شدهاند ارجاع میدهند:
کاتلین
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build() ) .build()
جاوا
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
وقتی کنترلکننده یا مرورگر به روش دیگری از جلسه متصل میشود یا آن را فراخوانی میکند
Callback، برنامه جلسه میتواند ControllerInfo ارسالشده به
برگشت فراخوانی را بررسی کند تا حداکثر تعداد دکمههای فرمانی را که کنترلکننده یا مرورگر
میتواند نمایش دهد دریافت کند. ControllerInfo که به روش callback منتقل شده است،
یک getter برای دسترسی راحت به این مقدار ارائه میدهد. بهطور پیشفرض، مقدار روی ۰ تنظیم شده است که
نشان میدهد مرورگر یا کنترلکننده از این ویژگی پشتیبانی نمیکند:
کاتلین
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 }
جاوا
@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 منتقل شده است دریافت کند:
کاتلین
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) }
جاوا
@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 اعلام کند:
کاتلین
val browserFuture = MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync()
جاوا
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();
وقتی برنامه کنترلکننده به جلسه متصل است، میتواند دکمههای فرمان را که توسط فایل رسانهای پشتیبانی میشوند و کنترلکننده برای آنها فرمان دردسترس اعطاشده توسط برنامه جلسه را دارد دریافت کند:
کاتلین
val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)
جاوا
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
کاتلین
val future = controller.sendCustomCommand( requireNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY, )
جاوا
ListenableFuture<SessionResult> future = controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);