Streaming en direct

ExoPlayer lit la plupart des flux en direct adaptatifs prêts à l'emploi, sans configuration particulière. Pour en savoir plus, consultez la page Formats acceptés.

Les diffusions en direct adaptatives offrent une fenêtre de contenus multimédias disponibles qui est mise à jour à intervalles réguliers pour refléter les changements en temps réel. Cela signifie que la position de lecture se trouvera toujours quelque part dans cette fenêtre, dans la plupart des cas, à proximité du temps réel actuel de production du flux. La différence entre le temps réel et la position de lecture actuelle est appelée décalage en direct.

Détecter et surveiller les lectures en direct

Chaque fois qu'une fenêtre en direct est mise à jour, les instances Player.Listener enregistrées reçoivent un événement onTimelineChanged. Vous pouvez obtenir des informations sur la lecture en direct en cours en interrogeant diverses méthodes Player et Timeline.Window, comme indiqué ci-dessous et illustré dans la figure suivante.

Vitre en direct

  • Player.isCurrentWindowLive indique si l'élément multimédia en cours de lecture est un flux en direct. Cette valeur reste vraie même si la diffusion en direct est terminée.
  • Player.isCurrentWindowDynamic indique si l'élément multimédia en cours de lecture est toujours en cours de mise à jour. C'est généralement le cas pour les diffusions en direct qui ne sont pas encore terminées. Notez que, dans certains cas, cet indicateur s'applique également aux diffusions qui ne sont pas en direct.
  • Player.getCurrentLiveOffset renvoie le décalage entre le temps réel actuel et la position de lecture (si disponible).
  • Player.getDuration renvoie la durée de la fenêtre en direct actuelle.
  • Player.getCurrentPosition renvoie la position de lecture par rapport au début de la fenêtre en direct.
  • Player.getCurrentMediaItem renvoie l'élément multimédia actuel, où MediaItem.liveConfiguration contient des remplacements fournis par l'application pour les paramètres de décalage en direct cible et d'ajustement de décalage en direct.
  • Player.getCurrentTimeline renvoie la structure multimédia actuelle dans un Timeline. Le Timeline.Window actuel peut être récupéré à partir de Timeline à l'aide de Player.getCurrentWindowIndex et de Timeline.getWindow. Dans Window :
    • Window.liveConfiguration contient les paramètres de décalage en direct cible et d'ajustement du décalage en direct. Ces valeurs sont basées sur les informations du contenu multimédia et sur les forçages fournis par l'application définis dans MediaItem.liveConfiguration.
    • Window.windowStartTimeMs est l'heure à laquelle la fenêtre en direct commence depuis l'epoch Unix.
    • Window.getCurrentUnixTimeMs est le temps écoulé depuis l'epoch Unix de la période actuelle. Cette valeur peut être corrigée par une différence d'horloge connue entre le serveur et le client.
    • Window.getDefaultPositionMs correspond à la position par défaut du lecteur dans la fenêtre en direct.

Rechercher dans les diffusions en direct

Vous pouvez rechercher n'importe où dans la fenêtre en direct avec Player.seekTo. La position de recherche transmise dépend du début de la fenêtre en direct. Par exemple, seekTo(0) recherche le début de la fenêtre en direct. Le joueur tente de conserver le même décalage en direct que la position recherchée après une recherche.

La fenêtre en direct possède également une position par défaut à laquelle la lecture est censée commencer. Cette position se trouve généralement quelque part près du bord direct. Vous pouvez rechercher la position par défaut en appelant Player.seekToDefaultPosition.

UI de lecture en direct

Les composants d'interface utilisateur par défaut d'ExoPlayer affichent la durée de la fenêtre en direct et la position de lecture actuelle dans celle-ci. Cela signifie que la position semble reculer chaque fois que la fenêtre en direct est mise à jour. Si vous avez besoin d'un comportement différent, par exemple pour afficher l'heure Unix ou le décalage en direct actuel, vous pouvez dupliquer PlayerControlView et le modifier en fonction de vos besoins.

Configurer les paramètres de lecture en direct

ExoPlayer utilise certains paramètres pour contrôler le décalage de la position de lecture par rapport au bord direct, ainsi que la plage de vitesses de lecture pouvant être utilisée pour ajuster ce décalage.

ExoPlayer obtient les valeurs de ces paramètres à partir de trois emplacements, par ordre de priorité décroissante (la première valeur trouvée est utilisée):

  • Valeurs pour MediaItem transmises à MediaItem.Builder.setLiveConfiguration.
  • Valeurs globales par défaut définies sur DefaultMediaSourceFactory.
  • Valeurs lues directement depuis le contenu multimédia.

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);

Les valeurs de configuration disponibles sont les suivantes:

  • targetOffsetMs: décalage en direct cible. Si possible, le lecteur tente de se rapprocher de ce décalage en direct lors de la lecture.
  • minOffsetMs: décalage en direct minimal autorisé. Même lorsque vous ajustez le décalage en fonction des conditions actuelles du réseau, le lecteur ne tente pas de passer en dessous de ce décalage pendant la lecture.
  • maxOffsetMs: décalage en direct maximal autorisé. Même lorsque vous ajustez le décalage en fonction des conditions actuelles du réseau, le lecteur ne tente pas de dépasser ce décalage pendant la lecture.
  • minPlaybackSpeed: vitesse de lecture minimale que le lecteur peut utiliser pour revenir en arrière lorsqu'il tente d'atteindre le décalage en direct cible.
  • maxPlaybackSpeed: vitesse de lecture maximale que le lecteur peut rattraper lorsqu'il tente d'atteindre le décalage en direct cible.

Ajustement de la vitesse de lecture

Lors de la lecture d'une diffusion en direct à faible latence, ExoPlayer ajuste le décalage en direct en modifiant légèrement la vitesse de lecture. Le lecteur tente de correspondre au décalage en direct cible fourni par le contenu multimédia ou l'application, mais tente également de réagir à l'évolution des conditions du réseau. Par exemple, en cas de remise en mémoire tampon pendant la lecture, le lecteur ralentit légèrement la lecture pour s'éloigner du bord en direct. Si le réseau redevient suffisamment stable pour permettre la lecture plus près du bord en direct, le lecteur accélère la lecture pour revenir vers le décalage cible en direct.

Si vous ne souhaitez pas ajuster automatiquement la vitesse de lecture, vous pouvez le désactiver en définissant les propriétés minPlaybackSpeed et maxPlaybackSpeed sur 1.0f. De même, vous pouvez l'activer pour les diffusions en direct à faible latence en les définissant explicitement sur des valeurs autres que 1.0f. Consultez la section de configuration ci-dessus pour en savoir plus sur la manière de définir ces propriétés.

Personnaliser l'algorithme de réglage de la vitesse de lecture

Si l'ajustement de la vitesse est activé, LivePlaybackSpeedControl définit les ajustements qui sont effectués. Il est possible d'implémenter un LivePlaybackSpeedControl personnalisé ou de personnaliser l'implémentation par défaut, à savoir DefaultLivePlaybackSpeedControl. Dans les deux cas, une instance peut être définie lors de la création du lecteur:

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();

Les paramètres de personnalisation pertinents de DefaultLivePlaybackSpeedControl sont les suivants:

  • fallbackMinPlaybackSpeed et fallbackMaxPlaybackSpeed: vitesses de lecture minimale et maximale pouvant être utilisées pour l'ajustement si aucun contenu multimédia ni MediaItem fourni par l'application ne définissent de limites.
  • proportionalControlFactor: contrôle la fluidité de l'ajustement de la vitesse. Une valeur élevée rend les ajustements plus soudains et réactifs, mais également plus susceptibles d'être audibles. Une valeur inférieure permet une transition plus fluide entre les vitesses, mais au prix d'un ralentissement.
  • targetLiveOffsetIncrementOnRebufferMs: cette valeur est ajoutée au décalage en temps réel cible chaque fois qu'une remise en mémoire tampon se produit, afin d'être plus prudente. Cette fonctionnalité peut être désactivée en définissant la valeur sur 0.
  • minPossibleLiveOffsetSmoothingFactor: facteur de lissage exponentiel utilisé pour suivre le décalage en direct minimal possible en fonction du média actuellement mis en mémoire tampon. Une valeur très proche de 1 signifie que l'estimation est plus prudente et peut prendre plus de temps pour s'adapter à l'amélioration des conditions du réseau, tandis qu'une valeur inférieure indique que l'estimation s'ajuste plus rapidement, ce qui augmente le risque de remise en mémoire tampon.

BehindLiveWindowException et ERROR_CODE_DR_LIVE_WINDOW

La position de lecture peut être en retard par rapport à la fenêtre en direct, par exemple si le lecteur est mis en pause ou met en mémoire tampon pendant une période suffisamment longue. Dans ce cas, la lecture échouera et une exception avec le code d'erreur ERROR_CODE_BEHIND_LIVE_WINDOW sera signalée via Player.Listener.onPlayerError. Le code de l'application peut souhaiter gérer ces erreurs en reprenant la lecture à la position par défaut. La propriété PlayerActivity de l'application de démonstration illustre cette approche.

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
  }
}