En esta sección, se explica cómo separar una app de reproducción multimedia en un controlador multimedia (para la IU) y una sesión multimedia (para el reproductor). Se describen dos arquitecturas de apps multimedia: un diseño cliente-servidor que funciona bien con apps de audio y un diseño de actividad única para reproductores de video. También se muestra cómo hacer que las apps de música respondan a los controles de hardware y cooperen con otras apps que usan la transmisión de salida de audio.
IU y reproductor
Una aplicación de contenido multimedia que reproduce audio o video suele tener dos partes:
- Un reproductor que recibe contenido multimedia digital y lo renderiza como video o audio
- Una IU con controles de transporte para ejecutar el reproductor y, opcionalmente, mostrar su estado
En Android, puedes compilar tu propio reproductor desde cero o elegir una de estas opciones:
- La clase MediaPlayer proporciona la funcionalidad básica para un reproductor básico compatible con los formatos de audio y video y las fuentes de datos más comunes.
- ExoPlayer es una biblioteca de código abierto que se compila sobre componentes de framework multimedia de nivel inferior, como
MediaCodec
yAudioTrack
. ExoPlayer admite funciones de alto rendimiento, como DASH, que no están disponibles enMediaPlayer
. Puedes personalizar el código de ExoPlayer para agregar componentes nuevos fácilmente. ExoPlayer solo se puede usar con Android 4.1 y versiones posteriores.
Controlador multimedia y sesión multimedia
Si bien las APIs de la IU y el reproductor pueden ser arbitrarias, la naturaleza de la interacción entre las dos partes es básicamente la misma para todas las apps de reproducción multimedia. El framework de Android define dos clases (una sesión multimedia y un controlador multimedia) que imponen una estructura bien definida para compilar una app de reproducción multimedia.
La sesión multimedia y el controlador multimedia se comunican entre sí mediante devoluciones de llamada predefinidas que corresponden a acciones estándar del reproductor (reproducir, pausar, detener, etc.), así como llamadas personalizadas extensibles que usas para definir comportamientos especiales exclusivos de tu app.
Sesión multimedia
Una sesión multimedia se encarga de toda la comunicación con el reproductor. Oculta la API del reproductor al resto de tu app. Solo se llama al reproductor desde la sesión multimedia que lo controla.
La sesión mantiene una representación del estado del reproductor (reproducción/pausa) y la información sobre lo que se está reproduciendo. Una sesión puede recibir devoluciones de llamada desde uno o más controladores multimedia. De esta manera, es posible que la IU de tu app y los dispositivos complementarios que ejecutan Wear OS y Android Auto controlen el reproductor. La lógica que responde a las devoluciones de llamada debe ser coherente. La respuesta a una devolución de llamada MediaSession
debe ser la misma sin importar qué app cliente inició la devolución de llamada.
Controlador multimedia
Un controlador multimedia aísla tu IU. El código de la IU solo se comunica con el controlador multimedia, no con el reproductor en sí. El controlador multimedia traduce las acciones de control de transporte en devoluciones de llamada a la sesión multimedia. También recibe devoluciones de llamada de la sesión multimedia cada vez que cambia el estado de la sesión. Esto proporciona un mecanismo para actualizar automáticamente la IU asociada. Un controlador multimedia solo puede conectarse a una sesión multimedia a la vez.
Cuando usas un controlador multimedia y una sesión multimedia, puedes implementar diferentes interfaces o reproductores en el entorno de ejecución. Puedes cambiar la apariencia o el rendimiento de tu app de forma independiente, según las capacidades del dispositivo en el que se ejecuta.
Diferencias entre apps de video y apps de audio
Cuando reproduces un video, usas la vista y el oído. Cuando reproduces audio, escuchas, pero también puedes trabajar con una app diferente al mismo tiempo. Hay un diseño distinto para cada caso práctico.
App de video
Una app de video necesita una ventana para ver el contenido. Por este motivo, las apps de video suelen implementarse como una sola actividad de Android. La pantalla en la que aparece el video es parte de la actividad.
App de audio
Un reproductor de audio no siempre necesita que su IU esté visible. Una vez que comienza a reproducir audio, el reproductor puede ejecutarse como una tarea en segundo plano. El usuario puede cambiar a otra app y trabajar mientras sigue escuchando.
Para implementar este diseño en Android, puedes compilar una app de audio usando dos componentes: una actividad para la IU y un servicio para el reproductor. Si el usuario cambia a otra app, el servicio puede ejecutarse en segundo plano. Si se incluyen las dos partes de una app de audio en componentes separados, cada una puede ejecutarse de manera más eficiente por sí sola. Por lo general, una IU es de corta duración en comparación con un reproductor, que puede ejecutarse durante mucho tiempo sin una IU.
La biblioteca de compatibilidad proporciona dos clases para implementar este enfoque de cliente-servidor: MediaBrowserService
y MediaBrowser
. El componente de servicio se implementa como una subclase de MediaBrowserService
que contiene la sesión multimedia y su reproductor. La actividad con la IU y el controlador multimedia debe incluir un MediaBrowser
, que se comunique con el MediaBrowserService
.
Usar MediaBrowserService
permite que los dispositivos complementarios (como Android Auto y Wear) descubran tu app, se conecten a ella, exploren contenido y controlen la reproducción sin acceder a la actividad de la IU de tu app. De hecho, puede haber varias apps conectadas al mismo MediaBrowserService
al mismo tiempo, cada una con su propio MediaController
. Una app que ofrece un MediaBrowserService
debería poder manejar varias conexiones simultáneas.
Aplicaciones de contenido multimedia y la infraestructura de audio de Android
Una app de música bien diseñada debe "combinarse bien" con otras apps que reproducen audio. Debe estar preparada para compartir el teléfono y cooperar con otras apps de tu dispositivo que usan audio. También debe responder a los controles de hardware en el dispositivo.
Todo este comportamiento se describe en Cómo controlar la salida de audio.
La biblioteca media-compat
La biblioteca media-compat contiene clases que son útiles para compilar apps que reproducen audio y video. Estas clases son compatibles con dispositivos que ejecutan Android 2.3 (nivel de API 9) y versiones posteriores. También se pueden usar con otras funciones de Android para crear una experiencia cómoda y familiar.
La implementación recomendada de sesiones multimedia y controladores multimedia son las clases MediaSessionCompat
y MediaControllerCompat
, que se definen en la biblioteca de compatibilidad de compatibilidad con contenido multimedia. Reemplazan las versiones anteriores de las clases MediaSession
y MediaController
que se introdujeron en Android 5.0 (nivel de API 21). Las clases de compatibilidad ofrecen
las mismas funciones, pero facilitan el desarrollo de tu app, ya que solo
necesitas escribir en una API. La biblioteca se encarga de la retrocompatibilidad, ya que traduce los métodos de sesión multimedia a los métodos equivalentes en versiones anteriores de la plataforma cuando están disponibles.
Si ya tienes una app funcional que usa las clases anteriores, te recomendamos que
la actualices a las clases compatibles. Cuando usas las versiones de compatibilidad, puedes quitar
todas las llamadas a registerMediaButtonReceiver()
y cualquier método de RemoteControlClient
.
Cómo medir el rendimiento
En Android 8.0 (nivel de API 26) y versiones posteriores, el método getMetrics()
está disponible para algunas clases de contenido multimedia. Muestra un objeto PersistableBundle
que contiene información de configuración y rendimiento, expresada como un mapa de atributos y valores.
El método getMetrics()
se define para estas clases de contenido multimedia:
MediaPlayer.getMetrics()
MediaRecorder.getMetrics()
MediaCodec.getMetrics()
MediaExtractor.getMetrics()
Las métricas se recopilan por separado para cada instancia y se conservan durante toda la vida útil de la instancia. Si no hay métricas disponibles, el método muestra un valor nulo. Las métricas reales que se muestran dependen de la clase.