Transmisión en vivo

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.

API de consulta de ventana en vivo
Figura 1: Ventana de transmisión 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 la transmisión en vivo ya finalizó.
  • Player.isCurrentWindowDynamic indica 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.getCurrentLiveOffset devuelve el desplazamiento entre la hora real actual y la posición de reproducción (si está disponible).
  • Player.getDuration devuelve la duración de la ventana en vivo actual.
  • Player.getCurrentPosition devuelve la posición de reproducción en relación con el inicio de la ventana en vivo.
  • Player.getCurrentMediaItem devuelve el elemento multimedia actual, en el que MediaItem.liveConfiguration contiene 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.getCurrentTimeline devuelve la estructura de medios actual en un Timeline. El Timeline.Window actual se puede recuperar de Timeline con Player.getCurrentMediaItemIndex y Timeline.getWindow. En Window, haz lo siguiente:
    • Window.liveConfiguration contiene 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 en MediaItem.liveConfiguration.
    • Window.windowStartTimeMs es el tiempo transcurrido desde el tiempo Unix en el que comienza la ventana en vivo.
    • Window.getCurrentUnixTimeMs es 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.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 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 MediaItem a MediaItem.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:

  • fallbackMinPlaybackSpeed y fallbackMaxPlaybackSpeed: Son las velocidades de reproducción mínima y máxima que se pueden usar para el ajuste si ni el contenido multimedia ni el MediaItem 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 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
  }
}