Transmisión en vivo

ExoPlayer reproduce la mayoría de las transmisiones en vivo adaptables y sin ninguna configuración especial. Consulta la página Formatos admitidos para obtener más información.

Las transmisiones en vivo adaptables ofrecen una ventana de contenido multimedia disponible que se actualiza en intervalos regulares para moverse 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 del tiempo real actual en el que se produce la transmisión. La diferencia entre la posición en tiempo real actual y la posición de reproducción se denomina desplazamiento en vivo.

Detectar y supervisar las reproducciones en vivo

Cada vez que se actualice un período en vivo, las instancias de Player.Listener registradas recibirán un evento onTimelineChanged. Para recuperar detalles sobre la reproducción en vivo actual, consulta varios métodos Player y Timeline.Window, como se indica a continuación y se muestra en la siguiente figura.

Período en vivo

  • Player.isCurrentWindowLive indica si el elemento multimedia que se está reproduciendo es una transmisión en vivo. Este valor sigue siendo verdadero incluso si finalizó la transmisión en vivo.
  • Player.isCurrentWindowDynamic indica si todavía se está actualizando el elemento multimedia que se está reproduciendo. Esto suele suceder con las transmisiones en vivo que aún no han finalizado. Ten en cuenta que, en algunos casos, esta marca también se aplica para las transmisiones que no son en vivo.
  • Player.getCurrentLiveOffset: Muestra el desplazamiento entre el tiempo real actual y la posición de reproducción (si está disponible).
  • Player.getDuration muestra la duración de la ventana publicada actual.
  • Player.getCurrentPosition: Muestra la posición de reproducción relativa al inicio de la ventana en vivo.
  • Player.getCurrentMediaItem muestra el elemento multimedia actual, en el que MediaItem.liveConfiguration contiene las anulaciones que proporciona la app para los parámetros de ajuste de desplazamiento en vivo objetivo y de desplazamiento en vivo.
  • Player.getCurrentTimeline muestra la estructura multimedia actual en un Timeline. El Timeline.Window actual se puede recuperar de Timeline mediante Player.getCurrentWindowIndex y Timeline.getWindow. Dentro de Window, haz lo siguiente:
    • Window.liveConfiguration contiene los parámetros de ajuste de desplazamiento en vivo objetivo y de desplazamiento en vivo. Estos valores se basan en la información del contenido multimedia y en cualquier anulación proporcionada por la app establecida en MediaItem.liveConfiguration.
    • Window.windowStartTimeMs es la hora desde la época Unix en la que comienza la ventana activa.
    • Window.getCurrentUnixTimeMs es la hora 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 comenzará la reproducción de forma predeterminada.

Buscar en las transmisiones en vivo

Puedes buscar en cualquier parte de la ventana en vivo con Player.seekTo. La posición de búsqueda pasada es relativa al inicio de la ventana en vivo. Por ejemplo, seekTo(0) buscará el inicio de la ventana activa. El jugador intentará mantener el mismo desplazamiento en vivo que la posición de búsqueda posterior 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. Esta posición suele estar en algún lugar cerca del borde activo. Puedes saltar a la posición predeterminada llamando a Player.seekToDefaultPosition.

IU de reproducción en vivo

Los componentes predeterminados de la IU 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, como mostrar la hora Unix o el desplazamiento activo actual, puedes bifurcar PlayerControlView y modificarlo para que se ajuste a 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 descendente de prioridad (se usa el primer valor encontrado):

  • Por MediaItem, los valores se pasan a MediaItem.Builder.setLiveConfiguration.
  • Valores predeterminados globales establecidos en DefaultMediaSourceFactory.
  • Valores que se leen directamente desde el medio.

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. 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 ajuste el desplazamiento según las condiciones actuales de la red, el reproductor no intentará estar por debajo de este durante la reproducción.
  • maxOffsetMs: Es el desplazamiento en vivo máximo permitido. Incluso cuando se ajuste el desplazamiento según las condiciones actuales de la red, el reproductor no intentará superar este desplazamiento durante la reproducción.
  • minPlaybackSpeed: Es la velocidad mínima de reproducción que puede usar el reproductor para retroceder cuando intenta alcanzar el desplazamiento en vivo objetivo.
  • maxPlaybackSpeed: Es la velocidad máxima de reproducción que el reproductor puede usar para ponerse al día cuando intenta alcanzar el desplazamiento en vivo objetivo.

Ajuste de 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 jugador intentará hacer coincidir el desplazamiento en vivo objetivo proporcionado por el contenido multimedia o la app, pero también intentará reaccionar ante los cambios en las condiciones de la red. Por ejemplo, si se producen realmacenamiento en el 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 activo nuevamente, el reproductor acelerará la reproducción y se moverá hacia el 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 latencia baja 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 configurar estas propiedades.

Cómo personalizar el 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 y fallbackMaxPlaybackSpeed: Son las velocidades de reproducción mínima y máxima que se pueden usar para realizar ajustes si ni el contenido multimedia ni el MediaItem proporcionado 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 sean audibles. Un valor más pequeño da como resultado una transición más fluida entre las velocidades, a costa de ser más lentas.
  • targetLiveOffsetIncrementOnRebufferMs: Este valor se agrega al desplazamiento en vivo objetivo cada vez que se vuelve a almacenar en búfer, a fin de proceder con mayor cautela. Esta función se puede inhabilitar estableciendo el valor en 0.
  • minPossibleLiveOffsetSmoothingFactor: Es un factor de suavizado exponencial que se usa para realizar un seguimiento del desplazamiento en vivo mínimo posible según el 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 tiempo en ajustarse a las mejores condiciones de red, mientras que un valor más bajo significa que la estimación se ajustará más rápido con un mayor riesgo de encontrar repeticiones en el búfer.

BehindLiveWindowException y ERROR_CODE_BEHIND_LIVE_WINDOW

La posición de reproducción puede retrasarse en la ventana en vivo, por ejemplo, si el reproductor está pausado o almacenando en búfer durante un período lo suficientemente 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 es un ejemplo de 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
  }
}