Las apps de contenido multimedia suelen contener colecciones de elementos multimedia organizados en una jerarquía. Por ejemplo, las canciones de un álbum o los episodios de una serie de TV en una playlist. Esta jerarquía de elementos multimedia se conoce como biblioteca multimedia.
Un MediaLibraryService
proporciona una API estandarizada para publicar y acceder a tu biblioteca de medios. Esto puede ser útil, por ejemplo, cuando agregas compatibilidad con Android Auto a tu app de música, que proporciona su propia IU segura para el conductor para tu biblioteca de música.
Compila un MediaLibraryService
Implementar un MediaLibraryService
es similar a implementar un MediaSessionService
, excepto que, en el método onGetSession()
, debes devolver un MediaLibrarySession
en lugar de un MediaSession
.
Kotlin
class PlaybackService : MediaLibraryService() { var mediaLibrarySession: MediaLibrarySession? = null var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...} // If desired, validate the controller before returning the media library session override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? = mediaLibrarySession // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Java
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() {...}; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
Recuerda declarar tu Service
y los permisos requeridos en el archivo de manifiesto también:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Usa un MediaLibrarySession
La API de MediaLibraryService
espera que tu biblioteca multimedia esté estructurada en formato de árbol, con un solo nodo raíz y nodos secundarios que pueden ser reproducibles o explorables.
Un MediaLibrarySession
extiende la API de MediaSession
para agregar APIs de navegación de contenido. En comparación con la devolución de llamada MediaSession
, la devolución de llamada MediaLibrarySession
agrega métodos como los siguientes:
onGetLibraryRoot()
para cuando un cliente solicita la raízMediaItem
de un árbol de contenidoonGetChildren()
para cuando un cliente solicita los elementos secundarios de unMediaItem
en el árbol de contenidoonGetSearchResult()
para cuando un cliente solicita resultados de la búsqueda del árbol de contenido para una búsqueda determinada
Los métodos de devolución de llamada pertinentes incluirán un objeto LibraryParams
con indicadores adicionales sobre el tipo de árbol de contenido que le interesa a una app cliente.
Botones de comando para elementos multimedia
Una app de sesión puede declarar botones de comando compatibles con un MediaItem
en el MediaMetadata
. Esto permite asignar una o más entradas de CommandButton
a un elemento multimedia que un controlador puede mostrar y usar para enviar el comando personalizado del elemento a la sesión de una manera conveniente.
Configura los botones de comando en el lado de la sesión
Cuando se compila la sesión, una app de sesión declara el conjunto de botones de comando que una sesión puede controlar como comandos personalizados:
Kotlin
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), // possibly more here ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Java
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
Cuando se compila un elemento multimedia, una app de sesión puede agregar un conjunto de IDs de comandos admitidos que hacen referencia a los comandos de sesión de los botones de comando que se configuraron cuando se compiló la sesión:
Kotlin
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
Cuando un controlador o navegador se conecta o llama a otro método de la sesión Callback
, la app de la sesión puede inspeccionar el ControllerInfo
que se pasó a la devolución de llamada para obtener la cantidad máxima de botones de comando que puede mostrar un controlador o navegador. El ControllerInfo
que se pasa a un método de devolución de llamada proporciona un getter para acceder a este valor de forma conveniente. De forma predeterminada, el valor se establece en 0, lo que indica que el navegador o el controlador no admiten esta función:
Kotlin
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems scope.launch { loadMediaItem(settableFuture, mediaId, maxCommandsForMediaItems) } return settableFuture }
Java
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
Cuando se controla una acción personalizada que se envió para un elemento multimedia, la app de sesión puede obtener el ID del elemento multimedia de los argumentos Bundle
que se pasan a onCustomCommand
:
Kotlin
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Java
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
Usar los botones de comando como navegador o control
En el lado de MediaController
, una app puede declarar la cantidad máxima de botones de comando que admite para un elemento multimedia cuando compila el objeto MediaController
o MediaBrowser
:
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync()
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync();
Cuando se conecta a la sesión, la app del controlador puede recibir los botones de comando que admite el elemento multimedia y para los que el controlador tiene el comando disponible otorgado por la app de la sesión:
Kotlin
val commandButtonsForMediaItem: List<CommandButton> = controller.getCommandButtonsForMediaItem(mediaItem)
Java
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Para mayor comodidad, un MediaController
puede enviar comandos personalizados específicos del elemento multimedia con MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle)
:
Kotlin
controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)
Java
controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);