Un reproductor es el componente de tu app que facilita la reproducción de elementos multimedia.
La interfaz Player
de Media3 configura un esquema de la funcionalidad que generalmente controla un reproductor. Esto incluye lo siguiente:
- Afectar los controles de reproducción, como reproducir, pausar y saltar
- Consultar propiedades del contenido multimedia que se está reproduciendo en el momento, como la posición de reproducción
- Cómo administrar una playlist o una cola de elementos multimedia
- Cómo configurar propiedades de reproducción, como la reproducción aleatoria, la repetición, la velocidad y el volumen
- Procesando el video en la pantalla
Media3 también proporciona una implementación de la interfaz Player
, llamada ExoPlayer
.
Una interfaz común entre los componentes
Varios componentes de Media3 implementan la interfaz del reproductor, por ejemplo:
Componente | Notas sobre la descripción y el comportamiento |
---|---|
ExoPlayer |
Una API de reproductor multimedia y la implementación predeterminada de la interfaz Player . |
MediaController |
Interactúa con un MediaSession para enviar comandos de reproducción. Si tu Player y MediaSession están en un Service independiente de Activity o Fragment en el que se encuentra la IU del reproductor, puedes asignar MediaController como el reproductor de la IU de PlayerView . Las llamadas de los métodos de reproducción y de playlists se envían al Player a través de MediaSession .
|
MediaBrowser |
Además de la funcionalidad que ofrece un MediaController , interactúa con un MediaLibrarySession para explorar contenido multimedia disponible.
|
ForwardingPlayer |
Una implementación de Player que reenvía llamadas de método a otro Player Usa esta clase para suprimir o modificar operaciones específicas anulando los métodos respectivos.
|
SimpleBasePlayer |
Es una implementación de Player que reduce al mínimo la cantidad de métodos que se deben implementar. Es útil cuando usas un reproductor personalizado que quieres conectar a un MediaSession .
|
CastPlayer |
Una implementación de Player que se comunica con una app receptora de Cast. El comportamiento depende de la sesión de transmisión subyacente.
|
Si bien un MediaSession
no implementa la interfaz Player
, requiere un Player
cuando se crea una. Su propósito es brindar acceso a Player
desde otros procesos o subprocesos.
Arquitectura de reproducción de Media3
Si tienes acceso a un Player
, debes llamar a sus métodos directamente para emitir comandos de reproducción. Para anunciar la reproducción y otorgar control de reproducción a fuentes externas, implementa un MediaSession
. Estas fuentes externas implementan un MediaController
, que facilita la conexión a una sesión multimedia y la emisión de solicitudes de comandos de reproducción.
Cuando se reproduce contenido multimedia en segundo plano, debes alojar la sesión y el reproductor multimedia en un MediaSessionService
o MediaLibraryService
que se ejecute como servicio en primer plano. Si lo haces, puedes separar el reproductor de la actividad de tu app que contiene la IU para controlar la reproducción. Es posible que debas usar un controlador multimedia.
Estado del reproductor
El estado de un reproductor multimedia que implementa la interfaz Player
consta principalmente de 4 categorías de información:
- Estado de reproducción
- Recupera con
getPlaybackState()
. - El valor de estado que define la interfaz es
STATE_IDLE
,STATE_BUFFERING
,STATE_READY
ySTATE_ENDED
.
- Recupera con
- Playlist de elementos multimedia
- Una secuencia de instancias de
MediaItem
para la reproducción. - Recuperar con
getCurrentTimeline()
- Las instancias de
Player
pueden proporcionar métodos de operación de listas de reproducción, como agregar o quitar unMediaItem
, y métodos prácticos comogetCurrentMediaItem()
.
- Una secuencia de instancias de
- Propiedades de reproducción y pausa, como las siguientes:
playWhenReady
: Indica si el usuario quiere que el contenido multimedia se reproduzca cuando sea posible o permanezca detenido.- Motivo de supresión de reproducción: Indica por qué se suprime la reproducción, si corresponde, incluso si
playWhenReady
estrue
. isPlaying
: Indica si el reproductor está reproduciendo actualmente, que solo serátrue
si el estado de reproducción esSTATE_READY
,playWhenReady
estrue
y la reproducción no se suprime.
- Posición de reproducción, que incluye lo siguiente:
- Índice actual de elementos multimedia: Es el índice del
MediaItem
actual en la playlist. isPlayingAd
: Indica si se está reproduciendo un anuncio insertado.- Posición de reproducción actual: Es la posición de reproducción actual dentro del
MediaItem
actual o el anuncio insertado.
- Índice actual de elementos multimedia: Es el índice del
Además, la interfaz Player
permite el acceso a las pistas disponibles, los metadatos de contenido multimedia, la velocidad de reproducción, el volumen y otras propiedades auxiliares de la reproducción.
Cómo detectar cambios
Usa un objeto Player.Listener
para detectar cambios en un objeto Player
. Consulta la documentación de ExoPlayer sobre los eventos del reproductor para obtener detalles sobre cómo crear y usar un objeto de escucha.
Ten en cuenta que la interfaz del objeto de escucha no incluye ninguna devolución de llamada para realizar un seguimiento del progreso normal de la reproducción. Para supervisar el progreso de la reproducción de forma continua, como configurar una IU de la barra de progreso, debes consultar la posición actual en intervalos adecuados.
Kotlin
val handler = Handler(Looper.getMainLooper()) fun checkPlaybackPosition(delayMs: Long): Boolean = handler.postDelayed( { val currentPosition = player.currentPosition // Update UI based on currentPosition checkPlaybackPosition(delayMs) }, delayMs)
Java
Handler handler = new Handler(Looper.getMainLooper()); boolean checkPlaybackPosition(long delayMs) { return handler.postDelayed(() -> { long currentPosition = player.getCurrentPosition(); // Update UI based on currentPosition checkPlaybackPosition(delayMs); }, delayMs); }
Cómo controlar la reproducción
La interfaz Player
ofrece muchas formas de manipular el estado y controlar la reproducción:
- Controles de reproducción básicos, como
play()
,pause()
,prepare()
ystop()
- Operaciones de listas de reproducción, como
addMediaItem()
oremoveMediaItem()
- Busca para cambiar el elemento o la posición actual.
- Configura los modos de repetición y el modo aleatorio.
- Actualiza las preferencias de selección de pistas.
- Establece la velocidad de reproducción.
Implementaciones personalizadas de Player
Para crear un reproductor personalizado, puedes extender el SimpleBasePlayer
incluido en Media3. Esta clase proporciona una implementación básica de la interfaz Player
para reducir al mínimo la cantidad de métodos que debes implementar.
Comienza anulando el método getState()
. Este método debe propagar el estado actual del reproductor cuando se lo llame, incluido lo siguiente:
- El conjunto de comandos disponibles
- Propiedades de reproducción, como si el reproductor debe comenzar a reproducir cuando el estado de reproducción es
STATE_READY
, el índice del elemento multimedia que se está reproduciendo y la posición de reproducción dentro del elemento actual
Kotlin
class CustomPlayer : SimpleBasePlayer(looper) { override fun getState(): State { return State.Builder() .setAvailableCommands(...) // Set which playback commands the player can handle // Configure additional playback properties .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST) .setCurrentMediaItemIndex(0) .setContentPositionMs(0) .build() } }
Java
public class CustomPlayer extends SimpleBasePlayer { public CustomPlayer(Looper looper) { super(looper); } @Override protected State getState() { return new State.Builder() .setAvailableCommands(...) // Set which playback commands the player can handle // Configure additional playback properties .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST) .setCurrentMediaItemIndex(0) .setContentPositionMs(0) .build(); } }
SimpleBasePlayer
exigirá que se cree el State
con una combinación válida de valores de estado. También controlará los objetos de escucha y también informará a los objetos de escucha sobre los cambios de estado. Si necesitas activar manualmente una actualización de estado, llama a invalidateState()
.
Más allá del método getState()
, solo debes implementar métodos que se usen para los comandos que tu jugador declara que están disponibles. Busca el método de controlador reemplazable que corresponda a la funcionalidad que desees implementar. Por ejemplo, anula el método handleSeek()
para admitir operaciones como COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
y COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
.