ExoPlayer reproduce la mayoría de las transmisiones en vivo adaptables de forma inmediata sin ninguna configuración especial. Consulta la página de formatos compatibles para obtener más detalles.
Las transmisiones en vivo adaptables ofrecen una ventana de contenido multimedia disponible que se actualiza en intervalos regulares para avanzar con el tiempo real actual. 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 de la hora real actual en la que se produce la transmisión. La diferencia entre el tiempo real actual y la posición 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 consultando varios métodos Player y Timeline.Window, como se indica más adelante y se muestra en la siguiente figura.
Player.isCurrentWindowLiveindica 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 ya finalizó.Player.isCurrentWindowDynamicindica si el elemento multimedia que se está reproduciendo aún se está actualizando. Por lo general, esto es así en las transmisiones en vivo que aún no terminaron. Ten en cuenta que esta marca también es verdadera para las transmisiones no en vivo en algunos casos.Player.getCurrentLiveOffsetdevuelve el desplazamiento entre la hora real actual y la posición de reproducción (si está disponible).Player.getDurationdevuelve la duración de la ventana en vivo actual.Player.getCurrentPositiondevuelve la posición de reproducción en relación con el inicio de la ventana en vivo.Player.getCurrentMediaItemdevuelve el elemento multimedia actual, en el queMediaItem.liveConfigurationcontiene las anulaciones proporcionadas por la app para los parámetros de ajuste de compensación en vivo y compensación en vivo de destino.Player.getCurrentTimelinedevuelve la estructura de medios actual en unTimeline. ElTimeline.Windowactual se puede recuperar deTimelineconPlayer.getCurrentMediaItemIndexyTimeline.getWindow. EnWindow, haz lo siguiente:Window.liveConfigurationcontiene los parámetros de ajuste de compensación en vivo y compensación en vivo objetivo. Estos valores se basan en la información del contenido multimedia y en las anulaciones proporcionadas por la app que se establecen enMediaItem.liveConfiguration.Window.windowStartTimeMses el tiempo transcurrido desde el tiempo Unix en el que comienza la ventana en vivo.Window.getCurrentUnixTimeMses el tiempo transcurrido desde el tiempo Unix del tiempo real actual. Este valor se puede corregir con 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 iniciará la reproducción de forma predeterminada.
Cómo avanzar o retroceder en las transmisiones en vivo
Puedes buscar en cualquier parte 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. El reproductor intentará mantener el mismo desplazamiento en vivo que la posición buscada después de una búsqueda.
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 de transmisión 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 parece retroceder cada vez que se actualiza la ventana en vivo. Si necesitas un comportamiento diferente, por ejemplo, mostrar el tiempo Unix o el desplazamiento en vivo actual, puedes bifurcar PlayerControlView y modificarlo para que se adapte a tus necesidades.
Configura 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 encontrado):
- Se pasaron valores por
MediaItemaMediaItem.Builder.setLiveConfiguration. - Los valores predeterminados globales se establecen en
DefaultMediaSourceFactory. - Son los 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: Es el desplazamiento en vivo objetivo. El reproductor intentará acercarse a este desplazamiento en vivo durante la reproducción, si es posible.minOffsetMs: Es el desplazamiento en vivo mínimo permitido. Incluso cuando se ajusta el desplazamiento a las condiciones actuales de la red, el reproductor no intentará bajar de este desplazamiento durante la reproducción.maxOffsetMs: Es el desplazamiento en vivo máximo permitido. Incluso cuando se ajusta el desplazamiento a las condiciones actuales de la red, 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 desplazamiento 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 desplazamiento en vivo objetivo.
Ajuste de la 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 el desplazamiento 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 nuevos almacenamientos en búfer durante la reproducción, el reproductor ralentizará un poco la reproducción 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 en vivo, el reproductor acelerará la reproducción para volver al desplazamiento en vivo objetivo.
Si no se necesita el ajuste automático de la velocidad de reproducción, se puede inhabilitar estableciendo 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 de forma explícita en valores que no sean 1.0f. Consulta la
sección de configuración 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 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 más pequeño genera una transición más fluida entre las velocidades, pero a costa de ser más lenta.targetLiveOffsetIncrementOnRebufferMs: Este valor se agrega a la compensación de transmisión en vivo objetivo cada vez que se produce un almacenamiento en búfer para proceder con más cautela. Esta función se puede inhabilitar si se establece el valor en 0.minPossibleLiveOffsetSmoothingFactor: Es un factor de suavizado exponencial que se usa para hacer un seguimiento del desplazamiento en vivo mínimo posible en función del contenido multimedia almacenado en búfer en ese momento. Un valor muy cercano a 1 significa que la estimación es más cautelosa y puede tardar más en ajustarse a las 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 que se produzcan nuevos almacenamientos en búfer.
BehindLiveWindowException y ERROR_CODE_BEHIND_LIVE_WINDOW
La posición de reproducción puede retrasarse con respecto a la ventana en vivo, por ejemplo, si el reproductor se pausa o almacena en búfer durante un período lo suficientemente largo. 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. Te recomendamos que controles estos errores reanudando
la reproducción en la posición predeterminada. La clase 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 } }