Interface de lecteur

Un lecteur est le composant de votre application qui facilite la lecture des éléments multimédias. L'interface Player de Media3 définit un plan pour les fonctionnalités généralement gérées par un lecteur. Par exemple:

  • Affecter les commandes de lecture, comme la lecture, la pause et la recherche
  • Interroger les propriétés du contenu multimédia en cours de lecture, comme la position de lecture
  • Gérer une playlist/une file d'attente d'éléments multimédias
  • Configurer les propriétés de lecture, telles que le mode aléatoire, la répétition, la vitesse et le volume
  • Rendre la vidéo à l'écran

Media3 fournit également une implémentation de l'interface Player, appelée ExoPlayer.

Une interface commune entre les composants

Plusieurs composants de Media3 implémentent l'interface Player, par exemple:

Component Description et remarques sur le comportement
ExoPlayer Une API de lecteur multimédia et l'implémentation par défaut de l'interface Player.
MediaController Interagit avec un MediaSession pour envoyer des commandes de lecture. Si vos Player et MediaSession se trouvent dans un Service distinct du Activity ou du Fragment dans lequel se trouve l'UI de votre joueur, vous pouvez attribuer votre MediaController comme joueur pour votre UI PlayerView. Les appels de méthode de lecture et de playlist sont envoyés à votre Player via votre MediaSession.
MediaBrowser En plus des fonctionnalités proposées par un MediaController, interagit avec un MediaLibrarySession pour parcourir les contenus multimédias disponibles.
SimpleBasePlayer Implémentation Player qui réduit au minimum le nombre de méthodes à implémenter. Utile lorsque vous utilisez un lecteur personnalisé que vous souhaitez connecter à un MediaSession.
ForwardingSimpleBasePlayer Sous-classe SimpleBasePlayer conçue pour transférer les opérations de lecture vers un autre Player, tout en permettant les mêmes personnalisations de comportement cohérentes que SimpleBasePlayer. Utilisez cette classe pour supprimer ou modifier des opérations de lecture spécifiques.
CastPlayer Implémentation de Player qui communique avec une application de récepteur Cast. Le comportement dépend de la session Cast sous-jacente.

Bien qu'un MediaSession n'implémente pas l'interface Player, il nécessite un Player lors de sa création. Son objectif est de fournir un accès à Player à partir d'autres processus ou threads.

Architecture de lecture Media3

Si vous avez accès à un Player, vous devez appeler directement ses méthodes pour émettre des commandes de lecture. Vous pouvez annoncer votre lecture et accorder aux sources externes le contrôle de la lecture en implémentant un MediaSession. Ces sources externes implémentent un MediaController, qui facilite la connexion à une session multimédia et l'émission de requêtes de commande de lecture.

Lorsque vous lisez des contenus multimédias en arrière-plan, vous devez héberger votre session multimédia et votre lecteur dans un MediaSessionService ou un MediaLibraryService qui s'exécute en tant que service de premier plan. Vous pouvez ainsi séparer votre lecteur de l'activité de votre application qui contient l'UI de contrôle de la lecture. Vous devrez peut-être utiliser un contrôleur multimédia.

Schéma illustrant l'intégration des composants de lecture Media3 dans l'architecture d'une application multimédia.
Figure 1: L'interface Player joue un rôle clé dans l'architecture de Media3.

État du lecteur

L'état d'un lecteur multimédia implémentant l'interface Player se compose principalement de quatre catégories d'informations:

  1. État de la lecture
  2. Playlist d'éléments multimédias
    • Séquence d'instances MediaItem pour la lecture.
    • Récupération avec getCurrentTimeline()
    • Les instances Player peuvent fournir des méthodes d'opération de playlist telles que l'ajout ou la suppression d'un MediaItem, ainsi que des méthodes pratiques telles que getCurrentMediaItem().
  3. Propriétés de lecture/pause, par exemple :
    • playWhenReady : indique si l'utilisateur souhaite que le contenu multimédia soit lu lorsque cela est possible ou qu'il reste en pause.
    • Motif de suppression de la lecture : indique pourquoi la lecture est supprimée, le cas échéant, même si playWhenReady est true.
    • isPlaying : indique si le lecteur est en cours de lecture. Il ne sera true que si l'état de la lecture est STATE_READY, playWhenReady est true et que la lecture n'est pas supprimée.
  4. Position de lecture, y compris :

De plus, l'interface Player permet d'accéder aux pistes disponibles, aux métadonnées multimédias, à la vitesse de lecture, au volume et à d'autres propriétés auxiliaires de la lecture.

Écouter les modifications

Utilisez un Player.Listener pour écouter les modifications dans un Player. Pour savoir comment créer et utiliser un écouteur, consultez la documentation ExoPlayer sur les événements Player.

Notez que l'interface de l'écouteur n'inclut aucun rappel pour suivre la progression normale de la lecture. Pour surveiller en continu la progression de la lecture, par exemple pour configurer une interface utilisateur de barre de progression, vous devez interroger la position actuelle à des intervalles appropriés.

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

Contrôler la lecture

L'interface Player offre de nombreuses façons de manipuler l'état et de contrôler la lecture:

Implémentations Player personnalisées

Pour créer un lecteur personnalisé, vous pouvez étendre le SimpleBasePlayer inclus dans Media3. Cette classe fournit une implémentation de base de l'interface Player afin de réduire au minimum le nombre de méthodes que vous devez implémenter.

Commencez par remplacer la méthode getState(). Cette méthode doit renseigner l'état actuel du lecteur lorsqu'elle est appelée, y compris:

  • Ensemble des commandes disponibles
  • Propriétés de lecture, par exemple si le lecteur doit commencer à lire lorsque l'état de lecture est STATE_READY, l'indice de l'élément multimédia en cours de lecture et la position de lecture dans l'élément en cours

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer s'assurera que State est créé avec une combinaison valide de valeurs d'état. Il gérera également les écouteurs et les informera des changements d'état. Si vous devez déclencher manuellement une mise à jour d'état, appelez invalidateState().

En dehors de la méthode getState(), vous n'avez besoin d'implémenter que les méthodes utilisées pour les commandes que votre lecteur déclare être disponibles. Recherchez la méthode de gestionnaire remplaçable qui correspond à la fonctionnalité que vous souhaitez implémenter. Par exemple, remplacez la méthode handleSeek() pour prendre en charge des opérations telles que COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM et COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.