MediaLibraryService-এর মাধ্যমে কন্টেন্ট পরিবেশন করা

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

ক্রম অনুযায়ী সাজানো মিডিয়া কন্টেন্টের উদাহরণ
ছবি ১: মিডিয়া আইটেম হায়ারার্কির উদাহরণ যা একটি মিডিয়া লাইব্রেরি তৈরি করে।

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

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()
  }
}

জাভা

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 ব্যবহার করা ক্লায়েন্টদের সাথে মানানসই হওয়ার জন্য, intent-filter এলিমেন্টে <action android:name="android.media.browse.MediaBrowserService"/> অন্তর্ভুক্ত করার সাজেশন দেওয়া হয়। Media3 অটোমেটিক এই পরিষেবা ইন্টারফেসে ব্যাকওয়ার্ড কম্প্যাটিবিলিটি প্রদান করে।

  • ভবিষ্যতে যাতে কোনও সমস্যা না হয় এবং Media3 ব্যবহার করে এমন অ্যাপ যাতে Media3 API ব্যবহার করে আপনার পরিষেবার সাথে যোগাযোগ করতে পারে তা নিশ্চিত করতে, প্ল্যাটফর্ম বিকল্পের পাশাপাশি <action android:name="androidx.media3.session.MediaLibraryService"/> প্রদান করা উচিত।

এটি অ্যাপকে PackageManager-এর মাধ্যমে আপনার পরিষেবা খুঁজে পেতে এবং এই ইন্টারফেসগুলির যেকোনও একটির মাধ্যমে MediaBrowser-এর সাথে কানেক্ট করতে দেয়।

MediaLibrarySession ব্যবহার করুন

MediaLibraryService API আশা করে যে আপনার মিডিয়া লাইব্রেরি ট্রি ফর্ম্যাটে স্ট্রাকচার করা থাকবে, যেখানে একটি রুট নোড এবং চাইল্ড নোড থাকবে যা প্লে করা যাবে বা আরও ব্রাউজ করা যাবে।

MediaLibrarySession, কন্টেন্ট ব্রাউজিং API যোগ করার জন্য MediaSession 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()

জাভা

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

জাভা

MediaItem mediaItem =
    new MediaItem.Builder()
        .setMediaMetadata(
            new MediaMetadata.Builder()
                .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO))
                .build())
        .build();

কোনও কন্ট্রোলার বা ব্রাউজার সেশনের অন্য কোনও পদ্ধতিকে কানেক্ট বা কল করলে Callback, সেশন অ্যাপটি কলব্যাকে পাস করা ControllerInfo পরীক্ষা করতে পারে যাতে কন্ট্রোলার বা ব্রাউজার সর্বাধিক কতগুলি কমান্ড বোতাম দেখাতে পারে তা জানা যায়। কলব্যাক পদ্ধতিতে পাস করা ControllerInfo এই ভ্যালু সুবিধাজনকভাবে অ্যাক্সেস করার জন্য একটি গেটার প্রদান করে। ডিফল্ট হিসেবে ভ্যালু ০-তে সেট করা থাকে, যার অর্থ হল ব্রাউজার বা কন্ট্রোলারে এই ফিচার কাজ করে না:

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
}

জাভা

@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 থেকে মিডিয়া আইটেম আইডি পেতে পারে:

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

জাভা

@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()

জাভা

ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();

সেশনের সাথে কানেক্ট করা থাকলে, কন্ট্রোলার অ্যাপ মিডিয়া আইটেমের মাধ্যমে কাজ করে এমন কমান্ড বোতাম রিসিভ করতে পারে এবং যার জন্য কন্ট্রোলারের কাছে সেশন অ্যাপের মাধ্যমে অনুমোদিত উপলভ্য কমান্ড থাকে:

Kotlin

val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)

জাভা

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