Cómo usar sesiones multimedia

Una sesión multimedia existe junto al reproductor que administra. Debes crear e inicializar una sesión multimedia en el método onCreate() de la actividad o servicio que posee la sesión multimedia y su reproductor asociado.

Cómo inicializar la sesión multimedia

Una sesión multimedia recién creada no tiene capacidades. Debes inicializar la sesión con estos pasos:

  • Establece marcas para que la sesión multimedia pueda recibir devoluciones de llamada desde controladores multimedia y botones de medios.
  • Crea e inicializa una instancia de PlaybackStateCompat y asígnala a la sesión. El estado de reproducción cambia a lo largo de la sesión, por lo que recomendamos almacenar en caché el objeto PlaybackStateCompat.Builder para su reutilización.
  • Crea una instancia de MediaSessionCompat.Callback y asígnala a la sesión (más abajo se brinda información sobre las devoluciones de llamada).

Debes crear e inicializar una sesión multimedia en el método onCreate() de la actividad o el servicio que posee la sesión.

Para que los botones de medios funcionen cuando tu app se haya inicializado (o detenido) recientemente, su PlaybackState debe contener una acción de reproducción que coincida con el intent que envía el botón de medios. Ese es el motivo por el cual ACTION_PLAY se asigna al estado de la sesión durante la inicialización. Para obtener más información, consulta Cómo responder a los botones de medios.

Cómo mantener el estado y los metadatos de la reproducción

Existen dos clases que representan el estado de una sesión multimedia.

La clase PlaybackStateCompat describe el estado operativo actual del reproductor. Esto incluye lo siguiente:

  • El estado del transporte (si el reproductor está reproduciendo contenido, detenido, almacenando contenido en el búfer, etc., consulta getState())
  • Un código de error y un mensaje de error opcional cuando corresponda (consulta getErrorCode() y lee la sección Estados y errores, que se incluye más abajo)
  • La posición del reproductor
  • Las acciones válidas del controlador que se pueden manejar en el estado actual

La clase MediaMetadataCompat describe el material que se está reproduciendo:

  • El nombre del artista, el álbum y la pista
  • La duración de la pista
  • La portada del álbum para mostrar en la pantalla de bloqueo (la imagen es un mapa de bits con un tamaño máximo de 320 x 320 dp; si es más grande, se reduce)
  • Una instancia de ContentUris que dirige a una versión más grande de la portada

El estado y los metadatos del reproductor pueden cambiar durante el ciclo de vida de una sesión multimedia. Cada vez que el estado o los metadatos cambian, debes usar el compilador correspondiente para cada clase, PlaybackStateCompat.Builder() o MediaMetadataCompat.Builder(), y luego pasar la nueva instancia a la sesión multimedia llamando a setPlaybackState() o a setMetaData(). Para reducir el consumo general de memoria de estas operaciones frecuentes, conviene crear los compiladores una vez y reutilizarlos durante el ciclo de vida de la sesión.

Estados y errores

Ten en cuenta que PlaybackState es un objeto que contiene valores separados para el estado de reproducción de la sesión (getState()) y, cuando es necesario, un código de error asociado (getErrorCode()). Los errores pueden ser irrecuperables o recuperables:

Cuando se interrumpe la reproducción, debes generar un error irrecuperable: establece el estado de transporte en STATE_ERROR y especifica un error asociado con setErrorMessage(int, CharSequence). Mientras el error bloquee la reproducción, el PlaybackState continuará informando STATE_ERROR y el error.

Un error recuperable ocurre cuando tu app no logra manejar una solicitud, pero puede continuar reproduciendo contenido: el transporte permanece en un estado "normal" (como STATE_PLAYING), pero el PlaybackState contiene un código de error. Por ejemplo, si se está reproduciendo la última canción y el usuario solicita pasar a la canción siguiente, la reproducción puede continuar, pero debes crear un nuevo PlaybackState con el código de error ERROR_CODE_END_OF_QUEUE y luego llamar a setPlaybackState(). Los controladores multimedia adjuntos a la sesión recibirán la devolución de llamada onPlaybackStateChanged() y le explicarán al usuario lo que sucedió. Un error recuperable solo se debe informar una vez, en el momento en que ocurre. La próxima vez que la sesión actualice el PlaybackState, no vuelvas a establecer el mismo error recuperable (a menos que el error se haya producido en respuesta a una nueva solicitud).

Pantallas de bloqueo de la sesión multimedia

A partir de Android 4.0 (API nivel 14), el sistema puede acceder a los metadatos y al estado de reproducción de una sesión multimedia. Así es como la pantalla de bloqueo puede mostrar los controles de contenido multimedia y la portada. El comportamiento varía según la versión de Android.

Portada del álbum

En Android 4.0 (API nivel 14) y versiones posteriores, el fondo de la pantalla de bloqueo muestra la portada del álbum, pero solo si los metadatos de la sesión multimedia incluyen un mapa de bits en segundo plano.

Controles de transporte

En Android 4.0 (API nivel 14) y hasta Android 4.4 (API nivel 19), cuando una sesión multimedia está activa y los metadatos de la sesión multimedia incluyen un mapa de bits en segundo plano, la pantalla de bloqueo muestra automáticamente los controles de transporte.

En Android 5.0 (API nivel 21) o versiones posteriores, el sistema no proporciona controles de transporte en la pantalla de bloqueo. En cambio, debes usar una notificación MediaStyle para mostrar los controles de transporte.

Cómo agregar acciones personalizadas

Puedes agregar acciones personalizadas con addCustomAction(). Por ejemplo, para agregar un control a fin de implementar una acción de Me gusta, usa el siguiente código:

Kotlin

    stateBuilder.addCustomAction(
            PlaybackStateCompat.CustomAction.Builder(
                    CUSTOM_ACTION_THUMBS_UP,
                    resources.getString(R.string.thumbs_up),
                    thumbsUpIcon
            ).run {
                setExtras(customActionExtras)
                build()
            }
    )
    

Java

    stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_THUMBS_UP, resources.getString(R.string.thumbs_up), thumbsUpIcon)
        .setExtras(customActionExtras)
        .build());
    

Consulta el Universal Music Player para ver un ejemplo completo.

Responde a la acción con onCustomAction().

Kotlin

    override fun onCustomAction(action: String, extras: Bundle?) {
        when(action) {
            CUSTOM_ACTION_THUMBS_UP -> {
                ...
            }
        }
    }
    

Java

    @Override
    public void onCustomAction(@NonNull String action, Bundle extras) {
        if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
            ...
        }
    }
    

Consulta también el Universal Music Player.

Devoluciones de llamada de sesiones multimedia

Los métodos principales de devolución de llamada son onPlay(), onPause() y onStop(). Aquí es donde agregas el código que controla tu reproductor.

Dado que creas una instancia de la devolución de llamada de la sesión y la estableces en el entorno de ejecución (en onCreate()), tu app puede definir devoluciones de llamada alternativas que usen reproductores distintos y elegir la combinación apropiada de devolución de llamada/reproductor en función del nivel del dispositivo o sistema. Puedes cambiar el reproductor sin modificar el resto de la app. Por ejemplo, puedes usar ExoPlayer si ejecutas Android 4.1 (API nivel 16) o versiones posteriores y usar MediaPlayer en sistemas previos.

Además de controlar el reproductor y administrar las transiciones de estado de la sesión multimedia, las devoluciones de llamada también habilitan e inhabilitan las funciones de tu app y controlan la forma en la que interactúa con otras aplicaciones y con el hardware del dispositivo. (Consulta Cómo controlar la salida de audio).

La implementación de los métodos de devolución de llamada de la sesión multimedia depende de la estructura de tu app. Consulta las páginas separadas que describen cómo usar las devoluciones de llamada en apps de audio y apps de video, donde se explica cómo deben implementarse las devoluciones de llamada para cada tipo de app.