Un controlador multimedia interactúa con una sesión multimedia para consultar y controlar la reproducción de una app de este tipo. En Media3, la API de MediaController
implementa la interfaz Player
. Estos son algunos ejemplos de apps cliente que usan un controlador de contenido multimedia:
- Controles multimedia del sistema Android
- App complementaria de Android Wear OS
- Android Auto y el SO Automotive
- Asistentes de voz, como Asistente de Google
- La app de prueba del controlador multimedia
Un controlador multimedia también puede ser útil dentro de una app de música, 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 una MediaController
, primero crea un SessionToken
para la MediaSession
correspondiente. El método onStart()
de tu Activity
o Fragment
puede ser un buen lugar para esto.
val sessionToken =
SessionToken(context, ComponentName(context, PlaybackService::class.java))
SessionToken sessionToken =
new SessionToken(context, new ComponentName(context, PlaybackService.class));
El uso de este SessionToken
para compilar un MediaController
conecta el controlador a la sesión determinada. Esto se realiza de forma asíncrona, por lo que debes detectar el resultado y usarlo cuando esté disponible.
val controllerFuture =
MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener({
// MediaController is available here with controllerFuture.get()
}, MoreExecutors.directExecutor())
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.
Es decir, 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 Player
. Consulta la guía Eventos del reproductor 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 desde el MediaSession
conectado. Algunos ejemplos son onCustomCommand()
cuando la sesión envía un comando personalizado, onAvailableSessionCommandsChanged()
cuando la sesión cambia los comandos disponibles o onDisconnected()
cuando el controlador se desconecta de la sesión.
Se puede configurar un MediaController.Listener
cuando se compila el controlador con un Builder
:
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()
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
.
MediaController.releaseFuture(controllerFuture)
MediaController.releaseFuture(controllerFuture);
Si liberas el controlador, se seguirán enviando todos los comandos pendientes 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.
Crea y usa un MediaBrowser
Un MediaBrowser
se basa en las capacidades que ofrece un MediaController
para habilitar también la navegación por la biblioteca multimedia que ofrece el MediaLibraryService
de una app multimedia.
val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
browserFuture.addListener({
// MediaBrowser is available here with browserFuture.get()
}, MoreExecutors.directExecutor())
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 música, primero recupera el nodo raíz con getLibraryRoot()
:
// 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())
// 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:
// 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())
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());
Cómo mostrar los controles de reproducción de otra app de música
Cuando se muestran controles de IU con botones para otra app de música, es importante seguir las preferencias de botones de música declaradas de esa app.
La mejor manera de resolver las preferencias de la app y las restricciones y 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
metodo resolve
proporciona una lista definida de botones para
mostrar con su ícono, posición y acción prevista.