Как подключиться к мультимедийному приложению

Подключиться к мультимедийному приложению можно двумя способами:

  1. MediaController
  2. MediaBrowser

MediaController

Контроллер мультимедиа взаимодействует с сеансом мультимедиа, чтобы запрашивать и контролировать воспроизведение мультимедийного приложения. В Media3 API MediaController реализует интерфейс Player. Примеры клиентских приложений, использующих контроллер мультимедиа:

Контроллер также может быть полезен в мультимедийном приложении, например если проигрыватель и сеанс мультимедиа находятся в Service отдельно от Activity или Fragment с пользовательским интерфейсом.

Создать 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 определяет дополнительные обратные вызовы для событий и специальных команд из подключенного 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());

Как показать элементы управления воспроизведением для другого мультимедийного приложения

При показе элементов управления пользовательского интерфейса с кнопками для другого мультимедийного приложения важно следовать объявленным настройкам кнопок мультимедиа этого приложения.

Чтобы согласовать настройки приложения с ограничениями и требованиями пользовательского интерфейса, используйте CommandButton.DisplayConstraints. Вы можете определить ограничения для своего интерфейса, а метод 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));
}