Cómo controlar contenido multimedia mediante MediaSession

Última actualización: 09/09/2020

¿Cuáles son los beneficios de agregar una MediaSession a la reproducción de video?

Las sesiones multimedia son un vínculo integral entre la plataforma de Android y las apps multimedia. Esto no solo informa a Android que se está reproduciendo contenido multimedia, de modo que pueda reenviar acciones de ese tipo a la sesión correcta, sino que también informa a la plataforma qué se está reproduciendo y cómo se puede controlar.

Exponer una MediaSession a través de tu app tiene varios beneficios que disfrutarán los usuarios. A continuación, incluimos algunos excelentes ejemplos.

Asistente de Google

Los usuarios pueden interactuar fácilmente con el contenido multimedia de tu app a través de comandos por voz como "Pausar", "Reanudar" y "Siguiente". Los metadatos del contenido multimedia también se pueden usar para obtener respuestas sobre lo que se está reproduciendo.

Android TV

En pantallas grandes, tu app de Android TV puede usar controles remotos convencionales para usuarios de TVs compatibles con HDMI-CEC. Los comandos emitidos por los botones Reproducir, Pausar, Detener, Siguiente y Anterior se transmiten a tu app.

Controles multimedia en pantalla

A partir de Android 4.0 (nivel de API 14), el sistema puede acceder a los metadatos y al estado de reproducción de una sesión multimedia. Esta funcionalidad permite que la pantalla de bloqueo muestre controles de contenido multimedia y material gráfico. Este comportamiento varía según la versión de Android.

Contenido multimedia en segundo plano

El contenido multimedia se puede controlar en cualquiera de estas situaciones, incluso si la app que lo reproduce se está ejecutando en segundo plano.

Computación ambiental

Exponer tu contenido multimedia con datos sobre lo que se está reproduciendo y cómo se lo puede controlar entre diferentes dispositivos hará que los usuarios interactúen con él de una variedad de formas que realmente disfrutarán.

Qué compilarás

En este codelab, extenderás la muestra de ExoPlayer existente para agregar compatibilidad con sesiones multimedia. Tu app hará lo siguiente:

  • Reflejará correctamente el estado activo de la sesión multimedia.
  • Retransmitirá controles multimedia a ExoPlayer.
  • Pasará metadatos de los elementos en fila a la sesión multimedia.

Qué aprenderás

  • Por qué las sesiones multimedia ofrecen a los usuarios una experiencia más enriquecedora
  • Cómo crear una sesión multimedia y administrar su estado
  • Cómo conectar una sesión multimedia con ExoPlayer
  • Cómo incluir metadatos de elementos en la fila de reproducción de la sesión multimedia
  • Cómo agregar acciones adicionales (personalizadas)

Este codelab se enfoca en el SDK de MediaSession. Los conceptos y los bloques de código no relevantes, incluidos los detalles sobre la implementación de ExoPlayer, no se analizan, pero se proporcionan para que simplemente los copies y los pegues.

Qué necesitarás

  • Una versión reciente de Android Studio (3.5 o posterior)
  • Conocimientos básicos sobre el desarrollo de aplicaciones para Android

¿Cuál es nuestro punto de partida?

Es la demostración principal de ExoPlayer, que contiene videos con controles de reproducción en pantalla, pero no utiliza sesiones multimedia listas para usar. Es ideal para que la exploremos a fondo y agregamos esas sesiones.

Descarga la muestra de ExoPlayer

Para comenzar, ejecutemos la muestra de ExoPlayer. Clona el repositorio de GitHub desde el vínculo que aparece a continuación.

Clonar la muestra de ExoPlayer

Abre la demostración

En Android Studio, abre el proyecto principal de demostración ubicado en demos/main.

Android Studio te pedirá que establezcas la ruta de acceso del SDK. Si tienes algún problema, te sugerimos que sigas las recomendaciones para actualizar las herramientas del IDE y el SDK.

10e3b5c652186d57.png

Si se te pide que uses la versión más reciente de Gradle, actualízala.

Dedica unos minutos a comprender cómo está diseñada la app. Ten en cuenta que hay dos actividades: SampleChooserActivity y PlayerActivity. Dedicaremos el resto del codelab a PlayerActivity, donde se reproduce el contenido multimedia, así que abre esa clase y continúa con la siguiente sección.

Crea la sesión multimedia

Abre la clase PlayerActivity.java, que crea el ExoPlayer y administra sus funciones, como renderizar el video en la pantalla. En esta actividad, conectaremos ExoPlayer a una sesión multimedia.

En la parte superior de la clase, declara los siguientes dos campos que usaremos en toda la sección.

private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;

Deberás agregar la dependencia del proyecto "extension-mediasession" al nivel de módulo build.gradle para "Module: demo":

implementation project(path: ':extension-mediasession')

Ten en cuenta que Android Studio puede ayudarte a agregar automáticamente esta dependencia si desplazas el mouse sobre el error para resolver MediaSessionConnector:

60055e4ad54fbb97.png

Por último, resuelve las importaciones de clase agregando lo siguiente:

import android.support.v4.media.session.MediaSessionCompat;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;

Cuando se genere la actividad, crearemos una sesión multimedia y un conector de sesión multimedia que actúe como intermediario entre la sesión y ExoPlayer.

El lugar ideal para insertar esto es donde también se crea ExoPlayer. En nuestra app de demostración, podemos adjuntar nuestro código al final de initializePlayer(). Asegúrate de agregar esta lógica después de que se cree una instancia del reproductor.

private void initializePlayer() {
  if (player == null) {
    ...
    player = ...
    ...
    mediaSession = new MediaSessionCompat(this, "sample");
    mediaSessionConnector = new MediaSessionConnector(mediaSession);
    mediaSessionConnector.setPlayer(player);
  }
  ...
}

Libera la sesión multimedia

Libera la sesión multimedia cuando ya no sea necesaria. Cuando liberamos ExoPlayer en releasePlayer(), también podemos incluir el siguiente código para hacerlo:

private void releasePlayer() {
  if (mediaSession != null) {
    mediaSession.release();
  }
  ...
}

Administra el estado de la sesión multimedia

Ahora que creamos instancias de la sesión multimedia, debemos asegurarnos de que su estado se refleje correctamente a medida que el usuario interactúe con la actividad.

Cuando el usuario inicia la actividad, se debe activar la sesión multimedia:

@Override
public void onStart() {
  ...
  if (mediaSession != null) {
    mediaSession.setActive(true);
  }
}

Debido a que nuestra aplicación no reproduce contenido multimedia en segundo plano, es fundamental garantizar que la sesión se encuentre inactiva cuando el usuario deje la actividad:

@Override
public void onStop() {
  super.onStop();
  if (mediaSession != null) {
    mediaSession.setActive(false);
  }
  ...
}

Ejecutemos la demostración

  1. Conecta un dispositivo Android o inicia un emulador.
  2. Asegúrate de que la opción "demo" esté seleccionada para ejecutarse en la barra de herramientas de Android Studio. cb1ec4e50886874f.png
  3. En la barra de herramientas de Android Studio, haz clic en 9d8fb3a9ddf12827.png.
  4. Una vez que se inicie la app en el dispositivo, selecciona una transmisión de video por Internet para reproducir.
  5. Cuando comience la reproducción, explora con los siguientes comandos adb para controlar la sesión multimedia: adb shell media dispatch pauseadb shell media dispatch playadb shell media dispatch play-pauseadb shell media dispatch fast-forwardadb shell media dispatch rewind
  1. Además, ejecuta el comando adb shell dumpsys media_session para explorar cómo ve Android tu sesión multimedia.
  2. Si estás usando un dispositivo físico con un micrófono, intenta invocar al Asistente de Google y emitir comandos por voz, como: "Pausar", "Reanudar" y "Adelantar 1 minuto".

b8dda02a6fb0f6a4.pngMuestra de ExoPlayer que se ejecuta en Android TV

Ahora, podemos expandir las funciones compatibles de la sesión multimedia donde creamos anteriormente nuestro MediaSessionConnector en initializePlayer().

Cómo agregar un TimelineQueueNavigator

ExoPlayer representa la estructura de elementos multimedia como un cronograma. Para obtener información detallada sobre cómo funciona esto, dedica unos minutos a leer acerca del objeto Timeline de ExoPlayer. Aprovechar esta estructura nos permite recibir notificaciones cuando cambie el contenido y exponer los metadatos de lo que se esté reproduciendo cuando se lo solicite.

Para ello, definimos un TimelineQueueNavigator. Ubica la creación de instancias de MediaSessionConnector en initializePlayer() y agrega una implementación de TimelineQueueNavigator después de que se inicialice mediaSession.

mediaSessionConnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) {
  @Override
  public MediaDescriptionCompat getMediaDescription(Player player, int windowIndex) {
    return new MediaDescriptionCompat.Builder()
            .setTitle("MediaDescription title")
            .setDescription("MediaDescription description for " + windowIndex)
            .setSubtitle("MediaDescription subtitle")
            .build();
  }
});

Para resolver las importaciones de clases, agrega lo siguiente:

import android.support.v4.media.MediaDescriptionCompat;
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator;

Observa que el parámetro windowIndex corresponde al elemento de ese índice en la fila de reproducción.

Ahora que agregaste algunos metadatos, puedes probar si el Asistente entiende qué se está reproduciendo. Mientras reproduces un video en Android TV, invoca al Asistente y di "¿Qué se está reproduciendo?".

6c7fc0cb853cbc38.png

Es posible que tu reproductor no sea compatible con algunas acciones o que quieras agregar compatibilidad con más. Ahora profundicemos un poco más en la sesión multimedia donde habíamos creado nuestro MediaSessionConnector en initializePlayer().

Cómo declarar acciones compatibles

Intenta usar mediaSessionConnector.setEnabledPlaybackActions() para personalizar las acciones que quieras que admita la sesión multimedia.

Ten en cuenta que el conjunto completo es el siguiente:

mediaSessionConnector.setEnabledPlaybackActions(
        PlaybackStateCompat.ACTION_PLAY_PAUSE
                | PlaybackStateCompat.ACTION_PLAY
                | PlaybackStateCompat.ACTION_PAUSE
                | PlaybackStateCompat.ACTION_SEEK_TO
                | PlaybackStateCompat.ACTION_FAST_FORWARD
                | PlaybackStateCompat.ACTION_REWIND
                | PlaybackStateCompat.ACTION_STOP
                | PlaybackStateCompat.ACTION_SET_REPEAT_MODE
                | PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
);

Veamos de nuevo cómo se exponen estos datos en la plataforma:

  1. Al igual que antes, inicia un video.
  2. Ejecuta el siguiente comando para explorar cómo Android ve los metadatos de tu sesión multimedia:adb shell dumpsys media_session
  3. Ubica la línea que contiene los metadatos y corrobora que el título y la descripción estén incluidos y asociados con com.google.android.exoplayer2.demo/sample.

Cómo agregar acciones adicionales

Podemos expandir nuestra sesión multimedia con algunas acciones adicionales. En esta sección, solo agregaremos compatibilidad con subtítulos.

Cómo agregar compatibilidad con subtítulos

Agregar compatibilidad con subtítulos a las sesiones multimedia permite que los usuarios los activen o desactiven utilizando la voz. Donde hayas inicializado el conector de sesiones multimedia, agrega lo siguiente:

mediaSessionConnector.setCaptionCallback(new MediaSessionConnector.CaptionCallback() {
      @Override
      public void onSetCaptioningEnabled(Player player, boolean enabled) {
        Log.d("MediaSession", "onSetCaptioningEnabled: enabled=" + enabled);
      }

      @Override
      public boolean hasCaptions(Player player) {
        return true;
      }

      @Override
      public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
        return false;
      }
    }
);

Por último, resuelve las importaciones que falten.

Para probar eso, invoca al Asistente de Google en Android TV y di "Habilitar subtítulos". Consulta Logcat para ver si hay mensajes en los que se indique cómo esto llama a tu código.

Felicitaciones. Agregaste correctamente sesiones multimedia a la muestra.

Obtuviste una gran cantidad de funcionalidades haciendo lo siguiente:

  • agregando una sesión multimedia
  • conectando sesiones multimedia con una instancia de ExoPlayer
  • agregando metadatos y acciones adicionales

Ahora ya conoces los pasos clave necesarios para hacer que una app multimedia sea más atractiva y ofrecer a los usuarios una experiencia más versátil.

Una última observación

Compilamos este codelab basándonos en una muestra del código fuente de ExoPlayer. No es necesario usar ExoPlayer desde el código fuente, y se recomienda que extraigas las dependencias de ExoPlayer y MediaSessionConnector para que sea más fácil mantenerse actualizado con las últimas versiones.

Para ello, solo debes reemplazar las dependencias del proyecto, como se muestra a continuación:

implementation project(modulePrefix + 'library-core')
implementation project(path: ':extension-mediasession')

Para extraer datos de repositorios de Maven, como los siguientes:

implementation 'com.google.android.exoplayer:exoplayer-core:2.+'
implementation 'com.google.android.exoplayer:extension-mediasession:2.+'

Documentos de referencia