Streaming en direct

ExoPlayer lit la plupart des flux en direct adaptatifs prêts à l'emploi sans aucune configuration spéciale. 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 suivre l'heure actuelle 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 près du temps réel actuel auquel le flux est produit. La différence entre la position actuelle en temps réel et la position de lecture est appelée décalage en direct.

Détecter et surveiller les diffusions 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 récupérer des informations sur la lecture en direct actuelle en interrogeant différentes méthodes Player et Timeline.Window, comme indiqué ci-dessous et illustré dans la figure suivante.

Fenêtre en direct

  • Player.isCurrentWindowLive indique si l'élément multimédia en cours de lecture est une diffusion en direct. Cette valeur reste "true" 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. Cela est généralement vrai pour les diffusions en direct qui ne sont pas encore terminées. Notez que ce signalement est également vrai pour les flux non en direct dans certains cas.
  • 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 de diffusion en direct.
  • Player.getCurrentMediaItem renvoie l'élément multimédia actuel, où MediaItem.liveConfiguration contient les remplacements fournis par l'application pour les paramètres de décalage en direct et d'ajustement du décalage en direct cibles.
  • Player.getCurrentTimeline renvoie la structure média actuelle dans un Timeline. Le Timeline.Window actuel peut être récupéré à partir de Timeline à l'aide de Player.getCurrentMediaItemIndex et 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 média et sur les éventuels remplacements fournis par l'application et définis dans MediaItem.liveConfiguration.
    • Window.windowStartTimeMs correspond à la durée écoulée depuis l'époque Unix au début de la période de diffusion en direct.
    • Window.getCurrentUnixTimeMs correspond à la durée écoulée depuis l'époque Unix de l'heure actuelle. Cette valeur peut être corrigée en fonction d'une différence d'horloge connue entre le serveur et le client.
    • Window.getDefaultPositionMs correspond à la position dans la fenêtre de diffusion en direct à partir de laquelle le lecteur lancera la lecture par défaut.

Rechercher dans les diffusions en direct

Vous pouvez accéder à n'importe quel moment de la diffusion en direct à l'aide de Player.seekTo. La position de recherche transmise est relative au début de la fenêtre de diffusion en direct. Par exemple, seekTo(0) permet d'accéder au début de la fenêtre de diffusion en direct. Après une recherche, le lecteur essaie de conserver le même décalage en direct que la position de recherche.

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

UI de lecture en direct

Les composants UI 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 semblera reculer chaque fois que la fenêtre en direct sera actualisée. 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 forker PlayerControlView et le modifier selon 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 en direct, ainsi que la plage de vitesses de lecture pouvant être utilisées pour ajuster ce décalage.

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

  • Valeurs MediaItem transmises à MediaItem.Builder.setLiveConfiguration.
  • Valeurs globales par défaut définies sur DefaultMediaSourceFactory.
  • Valeurs lues directement à partir du mé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 du flux en direct cible. Le lecteur tentera de se rapprocher de ce décalage en direct pendant la lecture, si possible.
  • minOffsetMs : décalage en direct minimal autorisé. Même en ajustant le décalage aux conditions réseau actuelles, le lecteur ne tentera pas de passer en dessous de ce décalage pendant la lecture.
  • maxOffsetMs : décalage maximal autorisé pour le flux en direct. Même si vous ajustez le décalage aux conditions réseau actuelles, le lecteur ne tentera pas de dépasser ce décalage pendant la lecture.
  • minPlaybackSpeed : vitesse de lecture minimale que le lecteur peut utiliser pour revenir à la vitesse cible en direct.
  • maxPlaybackSpeed : vitesse de lecture maximale que le lecteur peut utiliser pour rattraper son retard lorsqu'il tente d'atteindre le décalage en direct cible.

Ajustement de la vitesse de lecture

Lors de la lecture d'un flux en direct à faible latence, ExoPlayer ajuste le décalage en direct en modifiant légèrement la vitesse de lecture. Le lecteur tentera de faire correspondre le décalage en direct cible fourni par le contenu multimédia ou l'application, mais tentera également de réagir aux conditions réseau changeantes. Par exemple, si des remises en mémoire tampon se produisent pendant la lecture, le lecteur ralentit légèrement la lecture pour s'éloigner davantage du bord en direct. Si le réseau redevient suffisamment stable pour permettre une lecture plus proche du seuil, le lecteur accélère la lecture pour revenir au décalage cible.

Si vous ne souhaitez pas que la vitesse de lecture soit ajustée automatiquement, vous pouvez la 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 à latence non faible en définissant explicitement ces valeurs sur une valeur autre que 1.0f. Pour en savoir plus sur la façon de définir ces propriétés, consultez la section de configuration ci-dessus.

Personnaliser l'algorithme d'ajustement de la vitesse de lecture

Si l'ajustement de la vitesse est activé, un LivePlaybackSpeedControl définit les ajustements effectués. Il est possible d'implémenter un LivePlaybackSpeedControl personnalisé ou de personnaliser l'implémentation par défaut, qui est 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();

Voici les paramètres de personnalisation pertinents de DefaultLivePlaybackSpeedControl :

  • fallbackMinPlaybackSpeed et fallbackMaxPlaybackSpeed : vitesses de lecture minimale et maximale pouvant être utilisées pour l'ajustement si ni le média ni le 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 aussi plus susceptibles d'être audibles. Une valeur plus faible permet une transition plus fluide entre les vitesses, mais au détriment de la vitesse.
  • targetLiveOffsetIncrementOnRebufferMs : cette valeur est ajoutée au décalage en direct cible chaque fois qu'une mise en mémoire tampon se produit, afin de procéder plus prudemment. Vous pouvez désactiver cette fonctionnalité 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 contenu multimé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 à s'adapter à l'amélioration des conditions du réseau. À l'inverse, une valeur plus faible signifie que l'estimation s'ajustera plus rapidement, avec un risque plus élevé de rencontrer des problèmes de mise en mémoire tampon.

BehindLiveWindowException et ERROR_CODE_BEHIND_LIVE_WINDOW

La position de lecture peut être en retard par rapport à la fenêtre de diffusion en direct, par exemple si le lecteur est mis en pause ou en mémoire tampon pendant une période suffisamment longue. Dans ce cas, la lecture échoue et une exception avec le code d'erreur ERROR_CODE_BEHIND_LIVE_WINDOW est signalée via Player.Listener.onPlayerError. Le code de l'application peut gérer ces erreurs en reprenant la lecture à la position par défaut. La classe 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
  }
}