একটি MediaLibraryService এর সাথে সামগ্রী পরিবেশন করুন

মিডিয়া অ্যাপগুলোতে প্রায়শই মিডিয়া আইটেমের সংগ্রহ থাকে, যা একটি স্তরবিন্যাস অনুসারে সাজানো থাকে। যেমন, একটি অ্যালবামের গান বা একটি প্লেলিস্টের টিভি পর্ব। মিডিয়া আইটেমের এই স্তরবিন্যাসটি মিডিয়া লাইব্রেরি নামে পরিচিত।

শ্রেণিবিন্যাস অনুসারে সাজানো মিডিয়া বিষয়বস্তুর উদাহরণ
চিত্র ১ : মিডিয়া লাইব্রেরি গঠনকারী মিডিয়া আইটেমের স্তরবিন্যাসের উদাহরণ।

একটি MediaLibraryService আপনার মিডিয়া লাইব্রেরি পরিবেশন ও অ্যাক্সেস করার জন্য একটি প্রমিত API প্রদান করে। এটি সহায়ক হতে পারে, উদাহরণস্বরূপ, আপনার মিডিয়া অ্যাপে Android Auto- এর জন্য সমর্থন যোগ করার সময়, যা আপনার মিডিয়া লাইব্রেরির জন্য নিজস্ব ড্রাইভার-নিরাপদ UI প্রদান করে।

একটি MediaLibraryService তৈরি করুন

MediaLibraryService ইমপ্লিমেন্ট করা MediaSessionService ইমপ্লিমেন্ট করার মতোই, তবে পার্থক্য হলো onGetSession() মেথডে MediaSession এর পরিবর্তে MediaLibrarySession রিটার্ন করতে হয়।

কোটলিন

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.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 API-এর জন্য প্রয়োজন যে আপনার মিডিয়া লাইব্রেরিটি একটি ট্রি ফরম্যাটে গঠিত হবে, যেখানে একটিমাত্র রুট নোড এবং চাইল্ড নোড থাকবে যা প্লে করা বা আরও ব্রাউজ করা যেতে পারে।

MediaLibrarySession কন্টেন্ট ব্রাউজিং এপিআই যোগ করার জন্য MediaSession এপিআই-কে প্রসারিত করে। MediaSession কলব্যাকের তুলনায়, MediaLibrarySession কলব্যাক নিম্নলিখিত মেথডগুলো যোগ করে:

  • যখন কোনো ক্লায়েন্ট একটি কন্টেন্ট ট্রি-এর রুট MediaItem জন্য অনুরোধ করে, তখন onGetLibraryRoot() ব্যবহৃত হয়।
  • যখন কোনো ক্লায়েন্ট কন্টেন্ট ট্রিতে থাকা কোনো MediaItem এর চাইল্ড আইটেমগুলো অনুরোধ করে, তখন onGetChildren() ব্যবহৃত হয়।
  • যখন কোনো ক্লায়েন্ট একটি নির্দিষ্ট কোয়েরির জন্য কন্টেন্ট ট্রি থেকে অনুসন্ধানের ফলাফল অনুরোধ করে, তখন onGetSearchResult() ব্যবহৃত হয়।

প্রাসঙ্গিক কলব্যাক মেথডগুলোতে একটি LibraryParams অবজেক্ট অন্তর্ভুক্ত থাকবে, যা ক্লায়েন্ট অ্যাপটি কোন ধরনের কন্টেন্ট ট্রি-তে আগ্রহী সে সম্পর্কে অতিরিক্ত সংকেত দেবে।

মিডিয়া আইটেমগুলির জন্য কমান্ড বাটন

একটি সেশন অ্যাপ তার MediaMetadata তে MediaItem দ্বারা সমর্থিত কমান্ড বাটন ঘোষণা করতে পারে। এর ফলে একটি মিডিয়া আইটেমে এক বা একাধিক 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 তে এই মানটি সহজে অ্যাক্সেস করার জন্য একটি গেটার থাকে। ডিফল্টরূপে এর মান 0 সেট করা থাকে, যা নির্দেশ করে যে ব্রাউজার বা কন্ট্রোলারটি এই ফিচারটি সাপোর্ট করে না।

কোটলিন

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;
}

কোনো মিডিয়া আইটেমের জন্য পাঠানো কাস্টম অ্যাকশন পরিচালনা করার সময়, সেশন অ্যাপটি onCustomCommand এ পাস করা আর্গুমেন্টস Bundle থেকে মিডিয়া আইটেম আইডিটি পেতে পারে:

কোটলিন

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