ارائه محتوا با MediaLibraryService

برنامه‌های رسانه‌ای اغلب شامل مجموعه‌ای از آیتم‌های رسانه‌ای هستند که به صورت سلسله مراتبی سازماندهی شده‌اند. به عنوان مثال، آهنگ‌های یک آلبوم یا قسمت‌های تلویزیونی در یک لیست پخش. این سلسله مراتب از آیتم‌های رسانه‌ای به عنوان کتابخانه رسانه شناخته می‌شود.

نمونه‌هایی از محتوای رسانه‌ای که به صورت سلسله مراتبی مرتب شده‌اند
شکل ۱ : نمونه‌هایی از سلسله مراتب آیتم‌های رسانه‌ای که یک کتابخانه رسانه‌ای را تشکیل می‌دهند.

یک MediaLibraryService یک API استاندارد برای سرویس‌دهی و دسترسی به کتابخانه رسانه شما ارائه می‌دهد. این می‌تواند مفید باشد، برای مثال، هنگام افزودن پشتیبانی از Android Auto به برنامه رسانه‌ای شما، که رابط کاربری امن راننده خود را برای کتابخانه رسانه شما فراهم می‌کند.

ساخت یک MediaLibraryService

پیاده‌سازی MediaLibraryService مشابه پیاده‌سازی MediaSessionService است، با این تفاوت که در متد onGetSession() ، باید به جای MediaSession یک MediaLibrarySession برگردانید.

کاتلین

class PlaybackService : MediaLibraryService() {
  var mediaLibrarySession: MediaLibrarySession? = null
  var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...}

  // If desired, validate the controller before returning the media library session
  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? =
    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.MediaSessionService"/>
        <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" />

از یک MediaLibrarySession استفاده کنید

رابط برنامه‌نویسی کاربردی MediaLibraryService انتظار دارد که کتابخانه رسانه شما به صورت درختی ساختار یافته باشد، با یک گره ریشه واحد و گره‌های فرزند که ممکن است قابل پخش یا مرور بیشتر باشند.

یک MediaLibrarySession API MediaSession را برای افزودن APIهای مرور محتوا، توسعه می‌دهد. در مقایسه با فراخوانی MediaSession ، فراخوانی MediaLibrarySession متدهایی مانند موارد زیر را اضافه می‌کند:

  • onGetLibraryRoot() برای زمانی است که یک کلاینت MediaItem اصلی یک درخت محتوا را درخواست می‌کند.
  • onGetChildren() ‎ برای زمانی که یک کلاینت، فرزندان یک MediaItem را در درخت محتوا درخواست می‌کند.
  • onGetSearchResult() برای زمانی که یک کلاینت نتایج جستجو را از درخت محتوا برای یک پرس‌وجوی مشخص درخواست می‌کند.

متدهای فراخوانی مرتبط شامل یک شیء LibraryParams با سیگنال‌های اضافی در مورد نوع درخت محتوایی که برنامه کلاینت به آن علاقه‌مند است، خواهند بود.

دکمه‌های فرمان برای آیتم‌های رسانه‌ای

یک برنامه‌ی session می‌تواند دکمه‌های فرمانی را که توسط یک MediaItem در MediaMetadata پشتیبانی می‌شوند، تعریف کند. این امر امکان اختصاص یک یا چند ورودی CommandButton به یک آیتم رسانه‌ای فراهم می‌کند که یک کنترلر می‌تواند آن را نمایش داده و برای ارسال دستور سفارشی برای آیتم به session به روشی مناسب استفاده کند.

دکمه‌های فرمان را در سمت جلسه تنظیم کنید

هنگام ساخت جلسه، یک برنامه جلسه، مجموعه‌ای از دکمه‌های فرمان را که یک جلسه می‌تواند به عنوان دستورات سفارشی مدیریت کند، اعلام می‌کند:

کاتلین

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(),
    // possibly more here
  )

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

وقتی یک کنترلر یا مرورگر به متد دیگری از session Callback متصل می‌شود یا آن را فراخوانی می‌کند، برنامه session می‌تواند ControllerInfo ارسال شده به callback را بررسی کند تا حداکثر تعداد دکمه‌های فرمانی را که یک کنترلر یا مرورگر می‌تواند نمایش دهد، بدست آورد. ControllerInfo ارسال شده به یک متد callback، یک getter برای دسترسی راحت به این مقدار فراهم می‌کند. به طور پیش‌فرض، مقدار روی 0 تنظیم شده است که نشان می‌دهد مرورگر یا کنترلر از این ویژگی پشتیبانی نمی‌کند:

کاتلین

override fun onGetItem(
  session: MediaLibrarySession,
  browser: MediaSession.ControllerInfo,
  mediaId: String,
): ListenableFuture<LibraryResult<MediaItem>> {

  val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>()

  val maxCommandsForMediaItems = browser.maxCommandsForMediaItems
  scope.launch {
    loadMediaItem(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: List<CommandButton> =
  controller.getCommandButtonsForMediaItem(mediaItem)

جاوا

ImmutableList<CommandButton> commandButtonsForMediaItem =
    controller.getCommandButtonsForMediaItem(mediaItem);

برای راحتی، یک MediaController می‌تواند دستورات سفارشی مخصوص آیتم رسانه را با MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle) ارسال کند:

کاتلین

controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)

جاوا

controller.sendCustomCommand(
    checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);