Crea y configura un DefaultPreloadManager

En esta página, se describe cómo crear un objeto DefaultPreloadManager, que precarga contenido multimedia para tu app según la estrategia que elijas.

Los administradores de carga previa basados en la clase abstracta BasePreloadManager te permiten clasificar el contenido según los criterios que elijas. En este documento, se explica cómo usar la clase derivada DefaultPreloadManager, en la que cada elemento multimedia se clasifica con un número entero que representa su ubicación en una lista (por ejemplo, su posición en un carrusel de videos). El administrador de carga previa prioriza la carga de los elementos según qué tan cerca se encuentre del elemento que el usuario está reproduciendo. De esta manera, si un usuario se desplaza a otro elemento, el nuevo elemento puede comenzar a reproducirse de inmediato.

Existen tres pasos para crear una instancia de DefaultPreloadManager:

  • Define un TargetPreloadStatusControl que el administrador de carga previa pueda consultar para saber si el elemento multimedia está listo para cargarse y cuánto se debe cargar.
  • Crea el compilador que usarás para crear el administrador de carga previa y los objetos ExoPlayer de tu app.
  • Usa el compilador para crear el administrador de carga previa llamando al método build() del compilador.

Crea un control de estado de carga previa de destino

Cuando crees el objeto DefaultPreloadManager.Builder, le pasarás un objeto control de estado de carga previa de destino que definas. Este objeto implementa la interfaz TargetPreloadStatusControl. Cuando el administrador de carga previa se prepara para cargar previamente contenido multimedia, llama al método getTargetPreloadStatus() del control de estado para determinar si se debe preparar, cargar o almacenar en caché el contenido de un elemento multimedia. La carga previa carga los datos multimedia directamente en el búfer en memoria de un reproductor, lo que los prepara para la reproducción instantánea, mientras que el almacenamiento en caché guarda los datos multimedia en una caché de disco persistente para ahorrar memoria del reproductor. El control de estado puede responder con uno de los siguientes códigos de estado:

  • STAGE_SPECIFIED_RANGE_LOADED: El administrador de carga previa debe cargar el contenido desde la posición de inicio especificada y durante la duración especificada (en milisegundos) en el búfer en memoria del reproductor.
  • STAGE_SPECIFIED_RANGE_CACHED: El administrador de carga previa debe almacenar en caché el contenido desde la posición de inicio especificada y durante la duración especificada (en milisegundos) en la caché de disco.
  • STAGE_TRACKS_SELECTED: El administrador de carga previa debe cargar y procesar la información del segmento de contenido, y seleccionar los segmentos. El administrador de carga previa aún no debería comenzar a cargar el contenido.
  • STAGE_SOURCE_PREPARED: El administrador de carga previa debe preparar la fuente de contenido. Por ejemplo, si los metadatos del contenido se encuentran en un archivo de manifiesto independiente, el administrador de carga previa podría recuperar y analizar ese manifiesto.
  • null: El administrador de carga previa no debe cargar ningún contenido ni metadatos para ese elemento multimedia.

Deberás tener una estrategia para decidir cuánto contenido cargar para cada elemento multimedia. En este ejemplo, se carga más contenido para los elementos más cercanos al elemento que se está reproduciendo. Si el usuario reproduce contenido con el índice n, el controlador devuelve los siguientes códigos:

  • Índice n+1 (el siguiente elemento multimedia): Carga 3,000 ms (3 segundos) desde la posición de inicio predeterminada.
  • Índice n-1 (el elemento multimedia anterior): Carga 1,000 ms (1 segundo) desde la posición de inicio predeterminada.
  • Otros elementos multimedia en el rango de n-2 a n+2: Devolución PreloadStatus.TRACKS_SELECTED
  • Otros elementos multimedia en el rango de n-4 a n+4: Devolución PreloadStatus.SOURCE_PREPARED
  • Para todos los demás elementos multimedia, devuelve null.

class MyTargetPreloadStatusControl(var currentPlayingIndex: Int = 0) :
  TargetPreloadStatusControl<Int, DefaultPreloadManager.PreloadStatus> {

  override fun getTargetPreloadStatus(index: Int): DefaultPreloadManager.PreloadStatus {
    if (index - currentPlayingIndex == 1) { // next track
      // return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and
      // suggest loading 3000ms from the default start position
      return DefaultPreloadManager.PreloadStatus.specifiedRangeLoaded(3000L)
    } else if (index - currentPlayingIndex == -1) { // previous track
      // return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and
      // suggest loading 3000ms from the default start position
      return DefaultPreloadManager.PreloadStatus.specifiedRangeLoaded(3000L)
    } else if (abs(index - currentPlayingIndex) == 2) {
      // return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
      return DefaultPreloadManager.PreloadStatus.PRELOAD_STATUS_TRACKS_SELECTED
    } else if (abs(index - currentPlayingIndex) <= 4) {
      // return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
      return DefaultPreloadManager.PreloadStatus.PRELOAD_STATUS_SOURCE_PREPARED
    }
    return DefaultPreloadManager.PreloadStatus.PRELOAD_STATUS_NOT_PRELOADED
  }
}

Puntos clave sobre el código

  • Cuando lo crees, pasarás una instancia de MyTargetPreloadStatusControl al compilador del administrador de carga previa.
  • currentPlayingIndex contiene el índice del elemento multimedia que se está reproduciendo. La app debe mantener ese valor actualizado.
  • Cuando el administrador de carga previa está listo para cargar contenido, llama a getTargetPreloadStatus y pasa la información de clasificación que especificaste para ese elemento multimedia correspondiente. En el caso de DefaultPreloadManager, esa información de clasificación es un número entero que especifica la posición del elemento en un carrusel. El método elige qué código devolver comparando ese índice con el del elemento seleccionado actualmente.

Crea el administrador de carga previa

Para crear tu administrador de carga previa, necesitas un DefaultPreloadManager.Builder. Ese compilador se configura con el contexto actual y el control del estado de precarga objetivo de la app. Puedes crear un administrador de carga previa con todos los parámetros de configuración predeterminados.

val targetPreloadStatusControl = MyTargetPreloadStatusControl()
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl)
val preloadManager = preloadManagerBuilder.build()

El compilador también proporciona métodos setter que puedes usar para establecer los componentes personalizados del administrador de carga previa.

Por ejemplo, puedes personalizar los bytes totales del búfer objetivo para todas las fuentes de medios de carga previa en DefaultPreloadManager, de modo que los datos precargados no superen ese límite. Puedes configurar ese límite con setPlayerTargetBufferBytes(String, int) en un DefaultLoadControl.Builder personalizado con el nombre del reproductor "preload" y pasar esa instancia al compilador del administrador de carga previa:

val targetPreloadStatusControl = MyTargetPreloadStatusControl()
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl)

preloadManagerBuilder.setLoadControl(
  DefaultLoadControl.Builder()
    .setPlayerTargetBufferBytes("preload", 128 * 1024 * 1024) // 128 MiB
    .build()
)
val preloadManager = preloadManagerBuilder.build()

Si bien los métodos setter del compilador son básicamente opcionales para la personalización, si deseas almacenar en caché elementos multimedia en el disco, debes configurar el compilador con un Cache llamando a setCache(). Si no se configura ninguna caché, intentar almacenar en caché los elementos multimedia generará un error IllegalStateException.

Crea el ExoPlayer para reproducir el elemento multimedia precargado

Además de usar el compilador para crear el administrador de carga previa, también lo usarás para crear los objetos ExoPlayer que tu app usa para reproducir el contenido, de modo que ExoPlayer comparta correctamente los componentes con el administrador de carga previa. Aún puedes establecer la configuración específica de reproducción para el ExoPlayer pasando una instancia de ExoPlayer.Builder con esos parámetros de configuración establecidos.

// Direct creation
val exoPlayer = preloadManagerBuilder.buildExoPlayer()

// Creation with custom playback specific configurations
val skipSilenceExoPlayerBuilder = ExoPlayer.Builder(context).setSkipSilenceEnabled(true)
val skipSilenceExoPlayer = preloadManagerBuilder.buildExoPlayer(skipSilenceExoPlayerBuilder)