เชื่อมต่อกับแอปสื่อ

การเชื่อมต่อกับแอปสื่อทำได้ 2 วิธีดังนี้

  1. MediaController
  2. MediaBrowser

MediaController

ตัวควบคุมสื่อจะโต้ตอบกับเซสชันสื่อเพื่อค้นหาและควบคุมการเล่นของแอปสื่อ ใน Media3, API MediaController จะใช้Player อินเทอร์เฟซ ตัวอย่างแอปไคลเอ็นต์ที่ใช้ตัวควบคุมสื่อ ได้แก่

ตัวควบคุมสื่อยังมีประโยชน์ภายในแอปสื่อด้วย เช่น หากเพลเยอร์และเซสชันสื่ออยู่ใน Service แยกจาก Activity หรือ Fragment ที่มี UI

สร้าง MediaController

หากต้องการสร้าง MediaController ให้เริ่มด้วยการสร้าง SessionToken สำหรับ MediaSession ที่เกี่ยวข้อง เมธอด onStart() ของ Activity หรือ Fragment เป็นตำแหน่งที่เหมาะสมสำหรับการดำเนินการนี้

Kotlin

val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))

Java

SessionToken sessionToken =
    new SessionToken(context, new ComponentName(context, PlaybackService.class));

การใช้ SessionToken นี้เพื่อสร้าง MediaController จะเชื่อมต่อตัวควบคุมกับเซสชันที่ระบุ การดำเนินการนี้จะเกิดขึ้นแบบไม่พร้อมกัน ดังนั้นคุณควรฟังผลลัพธ์และใช้เมื่อพร้อมใช้งาน

Kotlin

val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener(
  {
    // MediaController is available here with controllerFuture.get()
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(context, sessionToken).buildAsync();
controllerFuture.addListener(
    () -> {
      // MediaController is available here with controllerFuture.get()
    },
    MoreExecutors.directExecutor());

ใช้ MediaController

MediaController ใช้อินเทอร์เฟซ Player คุณจึงสามารถใช้คำสั่งที่กำหนดไว้ในอินเทอร์เฟซเพื่อควบคุมการเล่นของ MediaSession ที่เชื่อมต่อได้ ซึ่งหมายความว่าการเรียกใช้ play() ใน MediaController จะส่งคำสั่งไปยัง MediaSession ที่เชื่อมต่ออยู่ ซึ่งจะมอบสิทธิ์คำสั่งไปยัง Player ที่เกี่ยวข้องในภายหลัง

คุณสามารถเพิ่ม Player.Listener ลงในตัวควบคุมเพื่อฟังการเปลี่ยนแปลงในสถานะ Player ได้ ดูรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ Player.Listener ได้ที่คู่มือเหตุการณ์ของโปรแกรมเล่น

อินเทอร์เฟซ MediaController.Listener จะกำหนด Callback เพิ่มเติมสำหรับเหตุการณ์และคำสั่งที่กำหนดเองจาก MediaSession ที่เชื่อมต่อ ตัวอย่างเช่น onCustomCommand() เมื่อเซสชันส่งคำสั่งที่กำหนดเอง onAvailableSessionCommandsChanged() เมื่อเซสชันเปลี่ยนคำสั่งเซสชันที่ใช้ได้ หรือ onDisconnected() เมื่อตัวควบคุมถูกยกเลิกการเชื่อมต่อ จากเซสชัน

คุณตั้งค่า MediaController.Listener ได้เมื่อสร้างตัวควบคุมด้วย Builder ดังนี้

Kotlin

val controllerFuture =
  MediaController.Builder(context, sessionToken)
    .setListener(
      object : MediaController.Listener {
        override fun onCustomCommand(
          controller: MediaController,
          command: SessionCommand,
          args: Bundle,
        ): ListenableFuture<SessionResult> {
          // Handle custom command.
          return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
        }

        override fun onDisconnected(controller: MediaController) {
          // Handle disconnection.
        }
      }
    )
    .buildAsync()

Java

ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(context, sessionToken)
        .setListener(
            new MediaController.Listener() {
              @Override
              public ListenableFuture<SessionResult> onCustomCommand(
                  MediaController controller, SessionCommand command, Bundle args) {
                // Handle custom command.
                return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
              }

              @Override
              public void onDisconnected(MediaController controller) {
                // Handle disconnection.
              }
            })
        .buildAsync();

เช่นเดียวกับคอมโพเนนต์อื่นๆ อย่าลืมปล่อย MediaController เมื่อไม่จำเป็นต้องใช้แล้ว เช่น ในเมธอด onStop() ของ Activity หรือ Fragment

Kotlin

MediaController.releaseFuture(controllerFuture)

Java

MediaController.releaseFuture(controllerFuture);

การปล่อยตัวควบคุมจะยังคงส่งคำสั่งที่รอดำเนินการทั้งหมดไปยังเซสชัน และจะยกเลิกการเชื่อมโยงจากบริการเซสชันเมื่อมีการจัดการคำสั่งเหล่านี้แล้วหรือหลังจากระยะหมดเวลา ขึ้นอยู่กับว่ากรณีใดจะเกิดขึ้นก่อน

MediaBrowser

MediaBrowser สร้างขึ้นจากความสามารถที่ MediaController มีให้เพื่อเปิดใช้การเรียกดูคลังสื่อที่ MediaLibraryService ของแอปสื่อมีให้ด้วย

สร้าง MediaBrowser

Kotlin

val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
browserFuture.addListener(
  {
    // MediaBrowser is available here with browserFuture.get()
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken).buildAsync();
browserFuture.addListener(
    () -> {
      // MediaBrowser is available here with browserFuture.get()
    },
    MoreExecutors.directExecutor());

ใช้ MediaBrowser

หากต้องการเริ่มเรียกดูคลังเนื้อหาของแอปสื่อ ให้ดึงข้อมูลโหนดรูทด้วย getLibraryRoot() ก่อน

Kotlin

// Get the library root to start browsing the library tree.
val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null)
rootFuture.addListener(
  {
    // Root node MediaItem is available here with rootFuture.get().value
  },
  MoreExecutors.directExecutor(),
)

Java

// Get the library root to start browsing the library tree.
ListenableFuture<LibraryResult<MediaItem>> rootFuture =
    mediaBrowser.getLibraryRoot(/* params= */ null);
rootFuture.addListener(
    () -> {
      // Root node MediaItem is available here with rootFuture.get().value
    },
    MoreExecutors.directExecutor());

จากนั้นคุณจะไปยังส่วนต่างๆ ของคลังสื่อได้โดยการดึงข้อมูลรายการย่อยของ MediaItem ในคลังด้วย getChildren() เช่น หากต้องการดึงข้อมูลโหนดย่อยของโหนดรูท MediaItem ให้ทำดังนี้

Kotlin

// Get the library root to start browsing the library tree.
val childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null)
childrenFuture.addListener(
  {
    // List of children MediaItem nodes is available here with
    // childrenFuture.get().value
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture =
    mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null);
childrenFuture.addListener(
    () -> {
      // List of children MediaItem nodes is available here with
      // childrenFuture.get().value
    },
    MoreExecutors.directExecutor());

แสดงตัวควบคุมการเล่นสำหรับแอปสื่ออื่น

เมื่อแสดงตัวควบคุม UI ที่มีปุ่มสำหรับแอปสื่ออื่น คุณต้องทำตามค่ากำหนดปุ่มสื่อที่ประกาศไว้ของแอปนั้น

หากต้องการแก้ไขค่ากำหนดของแอปด้วยข้อจำกัดและข้อกำหนดของ UI ให้ใช้ CommandButton.DisplayConstraints คุณสามารถกำหนดขีดจำกัดและข้อจำกัดของสิ่งที่ UI ทำได้ และเมธอด resolve() จะแสดงรายการปุ่มที่แน่นอนเพื่อแสดงพร้อมไอคอน ตำแหน่ง และการดำเนินการที่ต้องการ หากผู้ใช้คลิกปุ่มใดปุ่มหนึ่งเหล่านี้ คุณสามารถใช้ CommandButton.executeAction เพื่อทริกเกอร์การดำเนินการที่เกี่ยวข้องในแอปสื่อได้

Kotlin

// Get media button preferences from media app
val mediaButtonPreferences = controller.getMediaButtonPreferences()
// Declare constraints of UI (example: limit overflow button to one)
val displayConstraints =
  DisplayConstraints.Builder().setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1).build()
// Resolve media app preferences with constraints
val resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller)
// Display buttons in UI
for (button in resolvedButtons) {
  generateUiButton(
    uiPosition = button.slots[0],
    icon = getIconRes(button.icon),
    onClick = { button.executeAction(controller) },
  )
}

Java

// Get media button preferences from media app
List<CommandButton> mediaButtonPreferences = controller.getMediaButtonPreferences();
// Declare constraints of UI (example: limit overflow button to one)
DisplayConstraints displayConstraints =
    new DisplayConstraints.Builder()
        .setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1)
        .build();
// Resolve media app preferences with constraints
List<CommandButton> resolvedButtons =
    displayConstraints.resolve(mediaButtonPreferences, controller);
// Display buttons in UI
for (CommandButton button : resolvedButtons) {
  generateUiButton(
      /* uiPosition= */ button.slots.get(0),
      /* icon= */ getIconRes(button.icon),
      /* onClick= */ () -> button.executeAction(controller));
}