ExoPlayer reproduce la mayoría de las transmisiones en vivo adaptables de inmediato sin ninguna configuración especial. Consulta la página de formatos admitidos para obtener más detalles.
Las transmisiones en vivo adaptativas ofrecen una ventana de contenido multimedia disponible que se actualiza en intervalos regulares para seguir el contenido actual en tiempo real. Esto significa que la posición de reproducción siempre estará en algún lugar de esta ventana, en la mayoría de los casos, cerca del tiempo real actual en el que se produce la transmisión. La diferencia entre la posición actual en tiempo real y la de reproducción se denomina desplazamiento en vivo.
Cómo detectar y supervisar las reproducciones en vivo
Cada vez que se actualiza una ventana en vivo, las instancias de Player.Listener
registradas recibirán un evento onTimelineChanged
. Puedes recuperar detalles sobre la reproducción en vivo actual si consultas varios métodos Player
y Timeline.Window
, como se indica a continuación y se muestra en la siguiente figura.
Player.isCurrentWindowLive
indica si el elemento multimedia que se está reproduciendo es una transmisión en vivo. Este valor sigue siendo verdadero incluso si la transmisión en vivo finalizó.Player.isCurrentWindowDynamic
indica si el elemento multimedia que se está reproduciendo todavía se está actualizando. Por lo general, esto es así para las transmisiones en vivo que aún no finalizaron. Ten en cuenta que, en algunos casos, esta marca también se aplica a las transmisiones que no son en vivo.Player.getCurrentLiveOffset
muestra la compensación entre el tiempo real actual y la posición de reproducción (si está disponible).Player.getDuration
muestra la longitud de la ventana en vivo actual.Player.getCurrentPosition
muestra la posición de reproducción en relación con el comienzo de la ventana en vivo.Player.getCurrentMediaItem
muestra el elemento multimedia actual, en el queMediaItem.liveConfiguration
contiene anulaciones que proporciona la app para los parámetros de desplazamiento en vivo de destino y ajuste de desplazamiento en vivo.Player.getCurrentTimeline
muestra la estructura de contenido multimedia actual en unaTimeline
. ElTimeline.Window
actual se puede recuperar delTimeline
conPlayer.getCurrentMediaItemIndex
yTimeline.getWindow
. Dentro deWindow
:Window.liveConfiguration
contiene los parámetros de ajuste del offset en vivo y del offset en vivo objetivo. Estos valores se basan en la información del contenido multimedia y en cualquier anulación proporcionada por la app que se establezca enMediaItem.liveConfiguration
.Window.windowStartTimeMs
es el tiempo desde la época de Unix en el que comienza la ventana activa.Window.getCurrentUnixTimeMs
es el tiempo transcurrido desde la época Unix del tiempo real actual. Este valor se puede corregir con una diferencia de reloj conocida entre el servidor y el cliente.Window.getDefaultPositionMs
es la posición en la ventana en vivo en la que el reproductor iniciará la reproducción de forma predeterminada.
Cómo avanzar en las transmisiones en vivo
Puedes buscar en cualquier lugar de la ventana en vivo con Player.seekTo
. La posición de salto que se pasa es relativa al inicio de la ventana en vivo. Por ejemplo, seekTo(0)
buscará el inicio de la ventana en vivo. El reproductor intentará mantener el mismo desplazamiento en vivo que la posición de salto después de un salto.
La ventana en vivo también tiene una posición predeterminada en la que se supone que debe comenzar la reproducción. Por lo general, esta posición se encuentra cerca del borde activo. Puedes saltar a la posición predeterminada llamando a Player.seekToDefaultPosition
.
IU de reproducción en vivo
Los componentes de IU predeterminados de ExoPlayer muestran la duración de la ventana en vivo y la posición de reproducción actual en ella. Esto significa que la posición parecerá retroceder cada vez que se actualice la ventana en vivo. Si necesitas un comportamiento diferente, por ejemplo, mostrar la hora de Unix o la compensación en vivo actual, puedes bifurcar PlayerControlView
y modificarlo para satisfacer tus necesidades.
Configuración de los parámetros de la reproducción en vivo
ExoPlayer usa algunos parámetros para controlar el desplazamiento de la posición de reproducción desde el borde en vivo y el rango de velocidades de reproducción que se pueden usar para ajustar este desplazamiento.
ExoPlayer obtiene valores para estos parámetros de tres lugares, en orden de prioridad descendente (se usa el primer valor que se encuentra):
- Por valores de
MediaItem
que se pasan aMediaItem.Builder.setLiveConfiguration
. - Valores predeterminados globales establecidos en
DefaultMediaSourceFactory
. - Valores que se leen directamente del contenido multimedia
Kotlin
// Global settings. val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build() // Per MediaItem settings. val mediaItem = MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build() ) .build() player.setMediaItem(mediaItem)
Java
// Global settings. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build(); // Per MediaItem settings. MediaItem mediaItem = new MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()) .build(); player.setMediaItem(mediaItem);
Los valores de configuración disponibles son los siguientes:
targetOffsetMs
: el desplazamiento en vivo objetivo. Si es posible, el reproductor intentará acercarse a este desplazamiento en vivo durante la reproducción.minOffsetMs
: Es la compensación en vivo mínima permitida. Incluso cuando se ajusta el desplazamiento a las condiciones actuales de la red, el reproductor no intentará estar por debajo de este desplazamiento durante la reproducción.maxOffsetMs
: el desplazamiento en vivo máximo permitido Incluso cuando se ajusta el desplazamiento a las condiciones de red actuales, el reproductor no intentará superar este desplazamiento durante la reproducción.minPlaybackSpeed
: Es la velocidad de reproducción mínima que puede usar el reproductor para recurrir cuando intenta alcanzar el offset en vivo objetivo.maxPlaybackSpeed
: Es la velocidad de reproducción máxima que puede usar el reproductor para ponerse al día cuando intenta alcanzar el desfase en vivo objetivo.
Ajuste de velocidad de reproducción
Cuando se reproduce una transmisión en vivo de baja latencia, ExoPlayer ajusta el desfase en vivo cambiando ligeramente la velocidad de reproducción. El reproductor intentará coincidir con la compensación en vivo objetivo que proporciona el contenido multimedia o la app, pero también intentará reaccionar a las condiciones cambiantes de la red. Por ejemplo, si se producen rebuffers durante la reproducción, el reproductor ralentiza la reproducción un poco para alejarse del borde en vivo. Si la red se vuelve lo suficientemente estable como para admitir la reproducción más cerca del borde activo, el reproductor acelerará la reproducción para volver al desplazamiento activo objetivo.
Si no deseas que se realice el ajuste automático de la velocidad de reproducción, puedes inhabilitarlo configurando las propiedades minPlaybackSpeed
y maxPlaybackSpeed
en 1.0f
.
Del mismo modo, se puede habilitar para transmisiones en vivo que no tengan baja latencia si se configuran de forma explícita en valores distintos de 1.0f
. Consulta la sección de configuración anterior para obtener más detalles sobre cómo se pueden configurar estas propiedades.
Personalización del algoritmo de ajuste de velocidad de reproducción
Si el ajuste de velocidad está habilitado, un LivePlaybackSpeedControl
define qué ajustes se realizan. Es posible implementar un LivePlaybackSpeedControl
personalizado o personalizar la implementación predeterminada, que es DefaultLivePlaybackSpeedControl
. En ambos casos, se puede configurar una instancia cuando se compila el reproductor:
Kotlin
val player = ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build() ) .build()
Java
ExoPlayer player = new ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( new DefaultLivePlaybackSpeedControl.Builder() .setFallbackMaxPlaybackSpeed(1.04f) .build()) .build();
Los parámetros de personalización relevantes de DefaultLivePlaybackSpeedControl
son los siguientes:
fallbackMinPlaybackSpeed
yfallbackMaxPlaybackSpeed
: Son las velocidades de reproducción mínima y máxima que se pueden usar para el ajuste si ni el contenido multimedia ni elMediaItem
proporcionado por la app definen límites.proportionalControlFactor
: Controla la fluidez del ajuste de velocidad. Un valor alto hace que los ajustes sean más repentinos y reactivos, pero también es más probable que sean audibles. Un valor menor genera una transición más fluida entre las velocidades, pero a costa de ser más lento.targetLiveOffsetIncrementOnRebufferMs
: Este valor se agrega a la compensación en vivo objetivo cada vez que se produce un nuevo almacenamiento en búfer para proceder con más cautela. Esta función se puede inhabilitar configurando el valor en 0.minPossibleLiveOffsetSmoothingFactor
: Es un factor de suavización exponencial que se usa para hacer un seguimiento de la compensación en vivo mínima posible en función del contenido multimedia almacenado en búfer actualmente. Un valor muy cercano a 1 significa que la estimación es más prudente y puede tardar más en adaptarse a condiciones de red mejoradas, mientras que un valor más bajo significa que la estimación se ajustará más rápido con un mayor riesgo de encontrarse con rebuffers.
BehindLiveWindowException y ERROR_CODE_BEHIND_LIVE_WINDOW
Es posible que la posición de reproducción se retrase con respecto al período en vivo, por ejemplo, si el reproductor está pausado o en el búfer durante un período prolongado. Si esto sucede, la reproducción fallará y se informará una excepción con el código de error ERROR_CODE_BEHIND_LIVE_WINDOW
a través de Player.Listener.onPlayerError
. Es posible que el código de la aplicación desee controlar esos errores reanudando la reproducción en la posición predeterminada. La PlayerActivity de la app de demostración ejemplifica este enfoque.
Kotlin
override fun onPlayerError(error: PlaybackException) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition() player.prepare() } else { // Handle other errors } }
Java
@Override public void onPlayerError(PlaybackException error) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition(); player.prepare(); } else { // Handle other errors } }