Existen dos maneras de conectarse a una app de contenido multimedia:
MediaControllerMediaBrowser
MediaController
Un controlador multimedia interactúa con una sesión multimedia para consultar y controlar la reproducción de una app de contenido multimedia. En Media3, la API de MediaController implementa la interfaz Player. Estos son algunos ejemplos de apps cliente que usan un controlador multimedia:
- Controles multimedia del sistema Android
- App complementaria de Wear OS de Android
- Android Auto y Automotive OS
- Asistentes por voz, como el Asistente de Google
- La app de prueba del controlador multimedia
Un controlador multimedia también puede ser útil dentro de una app multimedia, por ejemplo, si el reproductor y la sesión multimedia se encuentran en un Service independiente de la Activity o el 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));
Si usas este SessionToken para compilar un MediaController, se conecta el controlador a la sesión determinada. Esto se realiza 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 de la MediaSession conectada.
Esto significa que llamar a play() en un MediaController enviará el comando al MediaSession conectado, que, posteriormente, 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 reproductor para obtener más detalles sobre cómo usar un Player.Listener.
La interfaz MediaController.Listener define devoluciones de llamada adicionales para eventos y comandos personalizados de la MediaSession conectada. Algunos ejemplos son
onCustomCommand() cuando el controlador envía un comando personalizado,
onAvailableSessionCommandsChanged() cuando el controlador 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
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();
Al igual que con otros componentes, recuerda liberar el MediaController cuando ya no sea necesario, como en el método onStop() de un Activity o Fragment.
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
Si liberas 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 tiempo de espera, lo que ocurra primero.
MediaBrowser
Un MediaBrowser se basa en las funciones que ofrece un MediaController para habilitar también la exploración de la biblioteca de contenido multimedia que ofrece el MediaLibraryService de una app multimedia.
Cómo crear un 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());
Usa un MediaBrowser
Para comenzar a explorar la biblioteca de contenido de la app multimedia, 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 de contenido 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());
Muestra 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 multimedia declaradas de esa app.
Para resolver las preferencias de la app con las restricciones y los requisitos de tu IU, usa 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 definitiva de botones para mostrar con su ícono, posición y acción prevista. Si un usuario hace clic en uno de estos botones, puedes usar CommandButton.executeAction para activar la acción asociada en la app de contenido multimedia.
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)); }