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

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

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