Cómo conectarse a una app de música

Un controlador multimedia interactúa con una sesión multimedia para consultar y controlar la reproducción de una app de música. En Media3, la API de MediaController implementa la interfaz Player. Estos son algunos ejemplos de apps cliente que usan un controlador de medios:

Un controlador multimedia también puede ser útil dentro de una app de medios, por ejemplo, si el reproductor y la sesión multimedia se encuentran en un Service separado del Activity o Fragment con la IU.

Cómo crear un MediaController

Para crear un MediaController, primero crea un SessionToken para el MediaSession correspondiente. El método onStart() de tu Activity o Fragment puede ser un buen lugar para esto.

Kotlin

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

Java

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

Usar este SessionToken para compilar un MediaController conecta el controlador a la sesión determinada. Esto se lleva a cabo de forma asíncrona, por lo que debes escuchar el resultado y usarlo cuando esté disponible.

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

Usa un MediaController

MediaController implementa la interfaz Player, por lo que puedes usar los comandos definidos en la interfaz para controlar la reproducción del MediaSession conectado. Esto significa que llamar a play() en un MediaController enviará el comando al MediaSession conectado, que luego delegará el comando a su Player subyacente.

Puedes agregar un Player.Listener al controlador para detectar cambios en el estado de Player. Consulta la guía de Eventos del jugador para obtener más detalles sobre el uso de un Player.Listener.

La interfaz MediaController.Listener define devoluciones de llamada adicionales para eventos y comandos personalizados del objeto MediaSession conectado. Algunos ejemplos son onCustomCommand() cuando la sesión envía un comando personalizado, onAvailableSessionCommandsChanged() cuando la sesión cambia los comandos de sesión disponibles o onDisconnected() cuando el controlador se desconecta de la sesión.

Se puede establecer un MediaController.Listener cuando se compila el controlador con un Builder:

Kotlin

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

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

Al igual que con otros componentes, recuerda liberar el MediaController cuando ya no se necesite, como en el método onStop() de un Activity o Fragment.

Kotlin

MediaController.releaseFuture(controllerFuture)

Java

MediaController.releaseFuture(controllerFuture);

Si sueltas el controlador, se seguirán entregando todos los comandos pendientes que se enviaron a la sesión y solo se desvinculará del servicio de sesión una vez que se hayan controlado estos comandos o después de un período de espera, lo que ocurra primero.

Crea y usa un MediaBrowser

Un MediaBrowser se basa en las capacidades que ofrece un MediaController para también permitir la navegación por la biblioteca multimedia que ofrece el MediaLibraryService de una app de música.

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

Para comenzar a explorar la biblioteca de contenido de la app de medios, primero recupera el nodo raíz con 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());

Luego, puedes navegar por la biblioteca multimedia recuperando los elementos secundarios de un MediaItem en la biblioteca con getChildren(). Por ejemplo, para recuperar los elementos secundarios del nodo raíz MediaItem, haz lo siguiente:

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

Mostrar los controles de reproducción de otra app de contenido multimedia

Cuando se muestran controles de la IU con botones para otra app de contenido multimedia, es importante seguir las preferencias de botones de contenido multimedia declaradas de esa app.

La mejor manera de resolver las preferencias de la app y las restricciones y los requisitos de tu IU es usar CommandButton.DisplayConstraints. Puedes definir los límites y las restricciones de lo que puede hacer tu IU, y el método resolve proporciona una lista definida de botones para mostrar con su ícono, posición y acción prevista.