Jetpack Media3 define una interfaz Player que describe la funcionalidad básica
para la reproducción de archivos de audio y video. ExoPlayer es la implementación predeterminada
de esta interfaz en Media3. Te recomendamos que uses ExoPlayer, ya que proporciona un
conjunto completo de funciones que abarcan la mayoría de los casos de uso de reproducción y se
puede personalizar para controlar cualquier caso de uso adicional que puedas tener. ExoPlayer también
abstrae la fragmentación del dispositivo y del SO para que tu código funcione de manera coherente
en todo el ecosistema de Android. ExoPlayer incluye lo siguiente:
- Compatibilidad con playlists
- Compatibilidad con una variedad de formatos de transmisión progresiva y adaptable formats
- Compatibilidad con la inserción de anuncios del cliente y del servidor ad insertion
- Compatibilidad con la reproducción protegida por DRM
En esta página, se explican algunos de los pasos clave para compilar una app de reproducción . Para obtener más detalles, puedes consultar nuestras guías completas sobre ExoPlayer de Media3.
Cómo comenzar
Para comenzar, agrega una dependencia en los módulos ExoPlayer, UI y Common de Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.9.2" implementation "androidx.media3:media3-ui:1.9.2" implementation "androidx.media3:media3-common:1.9.2"
Según tu caso de uso, es posible que también necesites módulos adicionales de Media3,
como exoplayer-dash para reproducir transmisiones en formato DASH.
Asegúrate de reemplazar 1.9.2 por la versión preferida de la
biblioteca. Puedes consultar las notas de la versión
para ver la versión más reciente.
Cómo crear un reproductor multimedia
Con Media3, puedes usar la implementación incluida de la Player
interfaz, ExoPlayer, o bien puedes compilar tu propia implementación personalizada.
Cómo crear un ExoPlayer
La forma más sencilla de crear una instancia de ExoPlayer es la siguiente:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Puedes crear tu reproductor multimedia en el método de ciclo de vida onCreate() de la
Activity, Fragment o el Service en el que reside.
El Builder incluye
una variedad de opciones de personalización que te pueden interesar, como las siguientes:
setAudioAttributes()para configurar el control del enfoque de audiosetHandleAudioBecomingNoisy()para configurar el comportamiento de reproducción cuando se desconecta un dispositivo de salida de audiosetTrackSelector()para configurar la selección de pistas
Media3 proporciona un componente de IU PlayerView que puedes incluir en el archivo de diseño de tu app's. Este componente encapsula un PlayerControlView para los controles de reproducción, un SubtitleView para mostrar subtítulos y un Surface para renderizar video.
Cómo preparar el reproductor
Agrega elementos multimedia a una playlist para la
reproducción con métodos como
setMediaItem()
y addMediaItem().
Luego, llama a prepare() para
comenzar a cargar contenido multimedia y adquirir los recursos necesarios.
No debes realizar estos pasos antes de que la app esté en primer plano. Si tu
reproductor está en una Activity o un Fragment, esto significa preparar el reproductor en el
onStart() método de ciclo de vida en el nivel de API 24 y versiones posteriores, o en el onResume()
método de ciclo de vida en el nivel de API 23 y versiones anteriores. Para un reproductor que está en un Service,
puedes prepararlo en onCreate(). Consulta el codelab de Exoplayer para ver un
ejemplo de cómo implementar métodos de ciclo de vida.
Cómo controlar el reproductor
Una vez que se haya preparado el reproductor, puedes controlar la reproducción llamando a métodos en el reproductor, como los siguientes:
play()ypause()para iniciar y pausar la reproducciónseekTo()para buscar una posición dentro del elemento multimedia actualseekToNextMediaItem()yseekToPreviousMediaItem()para navegar por la playlist
Los componentes de la IU, como PlayerView o PlayerControlView, se actualizarán
según corresponda cuando estén vinculados a un reproductor.
Cómo liberar el reproductor
La reproducción puede requerir recursos que tienen una oferta limitada, como decodificadores de video, por lo que es importante llamar a release()en tu reproductor para liberar recursos cuando ya no se necesite.
Si tu reproductor está en un Activity o un Fragment, libera el reproductor en el
onStop() método de ciclo de vida en el nivel de API 24 y versiones posteriores, o el onPause()
método en el nivel de API 23 y versiones anteriores. Para un reproductor que está en un Service, puedes
liberarlo en onDestroy(). Consulta el codelab de Exoplayer para ver un
ejemplo de cómo implementar métodos de ciclo de vida.
Cómo administrar la reproducción con una sesión multimedia
En Android, las sesiones multimedia proporcionan una forma estandarizada de interactuar con un reproductor multimedia a través de los límites del proceso. Conectar una sesión multimedia a tu reproductor te permite anunciar la reproducción de contenido multimedia de forma externa y recibir comandos de reproducción de fuentes externas, por ejemplo, para integrarlos con los controles multimedia del sistema en dispositivos móviles y de pantalla grande.
Para usar sesiones multimedia, agrega una dependencia en el módulo de sesión de Media3:
implementation "androidx.media3:media3-session:1.9.2"
Cómo crear una sesión multimedia
Puedes crear un MediaSession después de inicializar un reproductor de la siguiente manera:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 sincroniza automáticamente el estado del Player con el estado del
MediaSession. Esto funciona con cualquier Player implementación, incluidos
ExoPlayer, CastPlayer o una
implementación personalizada.
Cómo otorgar control a otros clientes
Las apps cliente pueden implementar un controlador multimedia
para controlar la reproducción de tu sesión multimedia. Para recibir estas solicitudes, configura un
objeto de devolución de llamada cuando
compiles tu MediaSession.
Cuando un controlador está a punto de conectarse a tu sesión multimedia, se llama al
onConnect()
método. Puedes usar el ControllerInfo
para decidir si aceptas
o rechazas
la solicitud. Consulta un ejemplo de esto en la app de demostración de la sesión de Media3.
Una vez conectado, un controlador puede enviar comandos de reproducción a la sesión. Luego, la
sesión delega esos comandos al reproductor. La sesión controla automáticamente los comandos de reproducción y de playlist
definidos en la Player interfaz.
Otros métodos de devolución de llamada te permiten controlar, por ejemplo, solicitudes de
comandos de reproducción personalizados
y modificar la playlist. Estas devoluciones de llamada también incluyen un objeto ControllerInfo para que puedas
determinar el control de acceso según cada solicitud.
Cómo reproducir contenido multimedia en segundo plano
Para seguir reproduciendo contenido multimedia cuando tu app no está en primer plano, por ejemplo
para reproducir música, audiolibros o podcasts, incluso cuando el usuario no tiene abierta tu app, tu Player y MediaSession deben estar encapsulados en un
servicio en primer plano. Media3 provides
la interfaz MediaSessionService para este propósito.
Cómo implementar un MediaSessionService
Crea una clase que extienda MediaSessionService y crea una instancia de tu
MediaSession en el método de ciclo de vida onCreate().
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
En tu manifiesto, agrega tu clase Service con un filtro de intents MediaSessionService y solicita el permiso FOREGROUND_SERVICE para ejecutar un servicio en primer plano:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Por último, en la clase que creaste, anula el método onGetSession() para controlar
el acceso del cliente a tu sesión multimedia. Muestra un MediaSession para aceptar la
solicitud de conexión o muestra null para rechazarla.
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
Cómo conectarse a tu IU
Ahora que tu sesión multimedia está en un Service independiente de la Activity o
Fragment en el que reside la IU del reproductor, puedes usar un MediaController para vincular
los. En el método onStart() de la Activity o el Fragment con tu
IU, crea un SessionToken para tu MediaSession y, luego, usa el SessionToken
para compilar un MediaController. La compilación de un MediaController se realiza
de forma asíncrona.
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController implementa la interfaz Player, por lo que puedes usar los mismos
métodos, como play() y pause(), para controlar la reproducción. Al igual que con otros
componentes, recuerda liberar el MediaController cuando ya no sea
necesario, como el método de ciclo de vida onStop() de una Activity, llamando
MediaController.releaseFuture().
Cómo publicar una notificación
Los servicios en primer plano deben publicar una notificación mientras están activos. Un
MediaSessionService creará automáticamente una
MediaStyle notificación para
ti en forma de MediaNotification.
Para proporcionar una notificación personalizada, crea un
MediaNotification.Provider
con DefaultMediaNotificationProvider.Builder
o crea una implementación personalizada de la interfaz del proveedor. Agrega tu
proveedor a tu MediaSession con
setMediaNotificationProvider.
Cómo anunciar tu biblioteca de contenido
Un MediaLibraryService se basa en un MediaSessionService y permite que las apps cliente exploren el contenido multimedia que proporciona tu app. Las apps cliente implementan un
MediaBrowser para interactuar
con tu MediaLibraryService.
La implementación de un MediaLibraryService es similar a la implementación de un
MediaSessionService, excepto que en onGetSession(), debes mostrar un
MediaLibrarySession en lugar de un MediaSession. En comparación con un
MediaSession.Callback, el MediaLibrarySession.Callback incluye
métodos adicionales que permiten que un cliente del navegador navegue por el contenido que ofrece tu
servicio de biblioteca.
Al igual que con el MediaSessionService, declara el MediaLibraryService en tu
manifiesto y solicita el permiso FOREGROUND_SERVICE para ejecutar un servicio en primer plano:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
En el ejemplo anterior, se incluye un filtro de intents para el MediaLibraryService
y, para la compatibilidad con versiones anteriores, el MediaBrowserService heredado. El
filtro de intents adicional permite que las apps cliente que usan la MediaBrowserCompat API
reconozcan tu Service.
Un MediaLibrarySession te permite entregar tu biblioteca de contenido en una estructura de árbol, con una sola raíz MediaItem. Cada MediaItem del árbol puede tener
cualquier cantidad de nodos MediaItem secundarios. Puedes entregar una raíz diferente o un
árbol diferente según la solicitud de la app cliente. Por ejemplo, el árbol que
muestras a un cliente que busca una lista de elementos multimedia recomendados solo
puede contener la raíz MediaItem y un solo nivel de nodos MediaItem secundarios,
mientras que el árbol que muestras a una app cliente diferente puede representar una biblioteca de contenido más
completa.
Cómo crear un MediaLibrarySession
Un MediaLibrarySession
extiende la API de MediaSession para agregar APIs de exploración de contenido. En comparación con la
MediaSession devolución de llamada,
la MediaLibrarySession devolución de llamada
agrega métodos como los siguientes:
onGetLibraryRoot()para cuando un cliente solicita la raízMediaItemde un árbol de contenidoonGetChildren()para cuando un cliente solicita los elementos secundarios de unMediaItemen el árbol de contenidoonGetSearchResult()para cuando un cliente solicita resultados de la búsqueda del árbol de contenido para una consulta determinada
Los métodos de devolución de llamada relevantes incluirán un LibraryParams
objeto con indicadores adicionales sobre el tipo de árbol de contenido en el que está interesada una app cliente.