ExoPlayer reproduce la mayoría de las transmisiones en vivo adaptativas de forma predeterminada sin necesidad de una configuración especial. Para obtener más detalles, consulta la página Formatos admitidos.
Las transmisiones en vivo adaptativas ofrecen una ventana de contenido multimedia disponible que se actualiza en intervalos regulares para seguir el tiempo real actual. Esto significa que la posición de reproducción siempre estará en algún punto de esta ventana, y, 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 posición de reproducción se denomina compensación 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 consultando varios métodos Player y Timeline.Window, como se indica a continuación y se muestra en la siguiente figura.

Player.isCurrentWindowLiveindica si el elemento multimedia que se está reproduciendo actualmente es una transmisión en vivo. Este valor sigue siendo verdadero incluso si finalizó la transmisión en vivo.Player.isCurrentWindowDynamicindica si el elemento multimedia que se está reproduciendo actualmente se sigue actualizando. Esto suele ser cierto para las transmisiones en vivo que aún no finalizaron. Ten en cuenta que esta marca también es verdadera para las transmisiones que no son en vivo en algunos casos.Player.getCurrentLiveOffsetdevuelve el desplazamiento entre la hora actual en tiempo real y la posición de reproducción (si está disponible).Player.getDurationdevuelve la longitud de la ventana en vivo actual.Player.getCurrentPositiondevuelve la posición de reproducción relativa al inicio de la ventana en vivo.Player.getCurrentMediaItemdevuelve el elemento multimedia actual, en el queMediaItem.liveConfigurationcontiene anulaciones proporcionadas por la app para los parámetros de ajuste y desplazamiento en vivo objetivo.Player.getCurrentTimelinedevuelve la estructura de medios actual en un objetoTimeline. ElTimeline.Windowactual se puede recuperar delTimelineconPlayer.getCurrentMediaItemIndexyTimeline.getWindow. EnWindow, haz lo siguiente:Window.liveConfigurationcontiene los parámetros de ajuste del desplazamiento en vivo y el desplazamiento en vivo de destino. Estos valores se basan en la información de los medios y en cualquier anulación proporcionada por la app que se haya establecido enMediaItem.liveConfiguration.Window.windowStartTimeMses la hora desde la época de Unix en la que comienza el período en vivo.Window.getCurrentUnixTimeMses el tiempo transcurrido desde la época de Unix del tiempo real actual. Este valor se puede corregir según una diferencia de reloj conocida entre el servidor y el cliente.Window.getDefaultPositionMses la posición en la ventana en vivo en la que el reproductor comenzará la reproducción de forma predeterminada.
Cómo buscar en las transmisiones en vivo
Puedes avanzar a cualquier punto dentro de la ventana en vivo con Player.seekTo. La posición de búsqueda que se pasa es relativa al inicio de la ventana en vivo. Por ejemplo, seekTo(0) buscará el inicio de la ventana en vivo. Después de una búsqueda, el reproductor intentará mantener el mismo desplazamiento en vivo que la posición a la que se buscó.
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 en vivo. Puedes buscar 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 dentro de 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 Unix o el desplazamiento en vivo actual, puedes bifurcar PlayerControlView y modificarlo para que se adapte a tus necesidades.
Cómo configurar los parámetros de 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 los valores de estos parámetros de tres lugares, en orden descendente de prioridad (se usa el primer valor que se encuentra):
- Son los valores de
MediaItemque se pasan aMediaItem.Builder.setLiveConfiguration. - Valores predeterminados globales establecidos en
DefaultMediaSourceFactory. - Son los valores que se leen directamente de los medios.
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: Es el desplazamiento en vivo de destino. Si es posible, el reproductor intentará acercarse a este desplazamiento en vivo durante la reproducción.minOffsetMs: Es el desplazamiento en vivo mínimo permitido. Incluso cuando se ajusta la compensación a las condiciones de red actuales, el reproductor no intentará reducirla durante la reproducción.maxOffsetMs: Es el desplazamiento en vivo máximo permitido. Incluso cuando se ajusta la compensación según las condiciones actuales de la red, el reproductor no intentará superar esta compensación durante la reproducción.minPlaybackSpeed: Es la velocidad de reproducción mínima que el reproductor puede usar como alternativa cuando intenta alcanzar el desplazamiento en vivo objetivo.maxPlaybackSpeed: Es la velocidad de reproducción máxima que puede usar el reproductor para alcanzar el desfase en vivo objetivo.
Ajuste de la velocidad de reproducción
Cuando se reproduce una transmisión en vivo de baja latencia, ExoPlayer ajusta el desplazamiento en vivo cambiando ligeramente la velocidad de reproducción. El reproductor intentará coincidir con el desplazamiento en vivo objetivo proporcionado por el contenido multimedia o la app, pero también intentará reaccionar a las condiciones cambiantes de la red. Por ejemplo, si se producen interrupciones durante la reproducción, el reproductor la ralentizará ligeramente para alejarse más del borde en vivo. Si la red vuelve a ser lo suficientemente estable como para permitir la reproducción más cerca del borde activo, el reproductor acelerará la reproducción para volver al desplazamiento en vivo objetivo.
Si no deseas 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 sean de baja latencia si se configuran explícitamente en valores distintos de 1.0f. Consulta la sección de configuración anterior para obtener más detalles sobre cómo se pueden establecer estas propiedades.
Cómo personalizar el algoritmo de ajuste de la 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 establecer 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:
fallbackMinPlaybackSpeedyfallbackMaxPlaybackSpeed: Son las velocidades de reproducción mínima y máxima que se pueden usar para el ajuste si ni el contenido multimedia ni elMediaItemproporcionado por la app definen límites.proportionalControlFactor: Controla qué tan suave es el ajuste de velocidad. Un valor alto hace que los ajustes sean más repentinos y reactivos, pero también es más probable que se escuchen. Un valor más pequeño 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 rebuffer, para proceder con más cautela. Para inhabilitar esta función, establece 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 cautelosa y puede tardar más en ajustarse a las mejores condiciones de la red, mientras que un valor más bajo significa que la estimación se ajustará más rápido con un mayor riesgo de interrupciones.
BehindLiveWindowException y ERROR_CODE_BEHIND_LIVE_WINDOW
La posición de reproducción puede quedar rezagada con respecto a la ventana en vivo, por ejemplo, si el reproductor se pausa o se almacena en el búfer durante un período lo suficientemente largo. Si esto sucede, fallará la reproducción y se informará una excepción con el código de error ERROR_CODE_BEHIND_LIVE_WINDOW a través de Player.Listener.onPlayerError. El código de la aplicación puede controlar estos 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 } }