Jetpack Media3 définit une interface Player
qui décrit les fonctionnalités de base pour la lecture de fichiers vidéo et audio. ExoPlayer
est l'implémentation par défaut de cette interface dans Media3. Nous vous recommandons d'utiliser ExoPlayer, car il fournit un ensemble complet de fonctionnalités qui couvrent la plupart des cas d'utilisation de lecture et est personnalisable pour gérer tout autre cas d'utilisation possible. ExoPlayer élimine également la fragmentation des appareils et de l'OS afin que votre code fonctionne de manière cohérente sur l'ensemble de l'écosystème Android. ExoPlayer inclut:
- Compatibilité avec les playlists
- Compatibilité avec divers formats de streaming progressifs et adaptatifs
- Possibilité d'insérer des annonces côté client et côté serveur
- Compatibilité avec la lecture protégée par DRM
Cette page vous explique certaines des étapes clés de la création d'une application de lecture. Pour en savoir plus, consultez nos guides complets sur Media3 ExoPlayer.
Lancez-vous
Pour commencer, ajoutez une dépendance aux modules ExoPlayer, UI et Common de Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
En fonction de votre cas d'utilisation, vous aurez peut-être également besoin de modules supplémentaires de Media3, tels que exoplayer-dash
, pour lire des flux au format DASH.
Veillez à remplacer 1.3.1
par votre version préférée de la bibliothèque. Vous pouvez consulter les notes de version pour accéder à la dernière version.
Créer un lecteur multimédia
Avec Media3, vous pouvez utiliser l'implémentation incluse de l'interface Player
, ExoPlayer
, ou créer votre propre implémentation personnalisée.
Créer une instance ExoPlayer
Le moyen le plus simple de créer une instance ExoPlayer
est le suivant:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Vous pouvez créer votre lecteur multimédia dans la méthode de cycle de vie onCreate()
de l'élément Activity
, Fragment
ou Service
où il se trouve.
Le Builder
comprend différentes options de personnalisation qui pourraient vous intéresser, par exemple:
setAudioAttributes()
pour configurer la gestion du ciblage audiosetHandleAudioBecomingNoisy()
pour configurer le comportement de lecture lorsqu'un périphérique de sortie audio est déconnectésetTrackSelector()
pour configurer la sélection du titre
Media3 fournit un composant d'interface utilisateur PlayerView
que vous pouvez inclure dans le fichier de mise en page de votre application. Ce composant encapsule un élément PlayerControlView
pour les commandes de lecture, SubtitleView
pour l'affichage des sous-titres et Surface
pour le rendu vidéo.
Préparation du lecteur...
Ajoutez des éléments multimédias à une playlist pour la lecture à l'aide de méthodes telles que setMediaItem()
et addMediaItem()
.
Appelez ensuite prepare()
pour commencer à charger les fichiers multimédias et acquérir les ressources nécessaires.
Vous ne devez pas effectuer ces étapes avant que l'application ne soit au premier plan. Si le joueur se trouve dans une Activity
ou une Fragment
, cela signifie qu'il doit être préparé avec la méthode de cycle de vie onStart()
à partir du niveau d'API 24, ou avec la méthode de cycle de vie onResume()
à partir du niveau d'API 23. Pour un joueur qui se trouve dans un Service
, vous pouvez le préparer dans onCreate()
.
Contrôler le lecteur
Une fois le lecteur préparé, vous pouvez contrôler la lecture en appelant des méthodes sur le lecteur, telles que:
play()
etpause()
pour lancer et suspendre la lectureseekTo()
pour rechercher une position dans l'élément multimédia actuelseekToNextMediaItem()
etseekToPreviousMediaItem()
pour parcourir la playlist
Les composants d'interface utilisateur tels que PlayerView
ou PlayerControlView
sont mis à jour en conséquence lorsqu'ils sont liés à un lecteur.
Relâchez le lecteur
La lecture peut nécessiter des ressources limitées, telles que des décodeurs vidéo. Il est donc important d'appeler release()
sur votre lecteur pour libérer des ressources lorsqu'il n'est plus nécessaire.
Si le lecteur se trouve dans une Activity
ou une Fragment
, libérez-le dans la méthode de cycle de vie onStop()
à partir du niveau d'API 24, ou avec la méthode onPause()
au niveau d'API 23 ou inférieur. Pour un joueur qui se trouve dans un Service
, vous pouvez le libérer dans onDestroy()
.
Gérer la lecture avec une session multimédia
Sur Android, les sessions multimédias offrent un moyen standardisé d'interagir avec un lecteur multimédia au-delà des limites de processus. La connexion d'une session multimédia à votre lecteur vous permet de promouvoir votre lecture multimédia en externe et de recevoir des commandes de lecture de sources externes, par exemple pour l'intégrer aux commandes multimédias du système sur les appareils mobiles et à grand écran.
Pour utiliser les sessions multimédias, ajoutez une dépendance au module Session Media3:
implementation "androidx.media3:media3-session:1.3.1"
Créer une session multimédia
Vous pouvez créer un MediaSession
après avoir initialisé un lecteur comme suit:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 synchronise automatiquement l'état de Player
avec l'état de MediaSession
. Cela fonctionne avec n'importe quelle implémentation de Player
, y compris ExoPlayer
, CastPlayer
ou une implémentation personnalisée.
Accorder le contrôle à d'autres clients
Les applications clientes peuvent implémenter un contrôleur multimédia pour contrôler la lecture de votre session multimédia. Pour recevoir ces requêtes, définissez un objet de rappel lors de la création de votre MediaSession
.
Lorsqu'une manette est sur le point de se connecter à votre session multimédia, la méthode onConnect()
est appelée. Vous pouvez utiliser le ControllerInfo
fourni pour décider d'accepter ou de rejeter la requête. Vous trouverez un exemple dans l'application de démonstration Media3 Session.
Une fois connectée, la manette peut envoyer des commandes de lecture à la session. La session délègue ensuite ces commandes au joueur. Les commandes de lecture et de playlist définies dans l'interface Player
sont automatiquement gérées par la session.
D'autres méthodes de rappel vous permettent, par exemple, de gérer les requêtes de commandes de lecture personnalisées et la modification de la playlist. Ces rappels incluent également un objet ControllerInfo
afin que vous puissiez déterminer le contrôle des accès requête par requête.
Lecture de contenus multimédias en arrière-plan
Pour continuer à lire des contenus multimédias lorsque votre application n'est pas au premier plan, par exemple pour écouter de la musique, des livres audio ou des podcasts même lorsque l'utilisateur n'a pas ouvert votre application, votre Player
et votre MediaSession
doivent être encapsulés dans un service de premier plan. Media3 fournit l'interface MediaSessionService
à cette fin.
Implémenter un MediaSessionService
Créez une classe qui étend MediaSessionService
et instanciez votre MediaSession
dans la méthode de cycle de vie onCreate()
.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
Dans votre fichier manifeste, votre classe Service
avec un filtre d'intent MediaSessionService
et demandez l'autorisation FOREGROUND_SERVICE
pour exécuter un service de premier plan:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Enfin, dans la classe que vous avez créée, remplacez la méthode onGetSession()
pour contrôler l'accès client à votre session multimédia. Renvoyez un MediaSession
pour accepter la requête de connexion ou renvoyez null
pour la refuser.
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
Se connecter à l'interface utilisateur
Maintenant que votre session multimédia se trouve dans un Service
distinct du Activity
ou de l'Fragment
où se trouve l'interface utilisateur de votre lecteur, vous pouvez utiliser un MediaController
pour les associer. Dans la méthode onStart()
de Activity
ou Fragment
avec votre UI, créez un SessionToken
pour votre MediaSession
, puis utilisez SessionToken
pour compiler un MediaController
. La création d'une MediaController
s'effectue de manière asynchrone.
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController
implémente l'interface Player
. Vous pouvez donc utiliser les mêmes méthodes telles que play()
et pause()
pour contrôler la lecture. Comme pour les autres composants, n'oubliez pas de libérer le MediaController
lorsqu'il n'est plus nécessaire, comme la méthode de cycle de vie onStop()
d'un Activity
, en appelant MediaController.releaseFuture()
.
Publier une notification
Les services de premier plan sont nécessaires pour publier une notification lorsqu'ils sont actifs. MediaSessionService
crée automatiquement une notification MediaStyle
sous la forme d'un MediaNotification
.
Pour fournir une notification personnalisée, créez un MediaNotification.Provider
avec DefaultMediaNotificationProvider.Builder
ou créez une implémentation personnalisée de l'interface du fournisseur. Ajoutez votre fournisseur à votre MediaSession
avec setMediaNotificationProvider
.
Faire la promotion de votre bibliothèque de contenu
Un MediaLibraryService
s'appuie sur un MediaSessionService
en permettant aux applications clientes de parcourir le contenu multimédia fourni par votre application. Les applications clientes implémentent un MediaBrowser
pour interagir avec votre MediaLibraryService
.
L'implémentation d'un MediaLibraryService
est semblable à l'implémentation d'un MediaSessionService
, sauf que dans onGetSession()
, vous devez renvoyer un MediaLibrarySession
au lieu d'un MediaSession
. Par rapport à un MediaSession.Callback
, le MediaLibrarySession.Callback
inclut des méthodes supplémentaires qui permettent à un client de navigateur de parcourir le contenu proposé par votre service de bibliothèque.
Comme pour MediaSessionService
, déclarez MediaLibraryService
dans le fichier manifeste et demandez l'autorisation FOREGROUND_SERVICE
pour exécuter un service de premier plan:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
L'exemple ci-dessus inclut un filtre d'intent pour MediaLibraryService
et, pour des raisons de rétrocompatibilité, pour l'ancien MediaBrowserService
. Le filtre d'intent supplémentaire permet aux applications clientes utilisant l'API MediaBrowserCompat
de reconnaître votre Service
.
Un MediaLibrarySession
vous permet de diffuser votre bibliothèque de contenu dans une arborescence, avec une seule racine MediaItem
. Chaque MediaItem
de l'arborescence peut avoir un nombre illimité de nœuds MediaItem
enfants. Vous pouvez diffuser une racine différente ou une arborescence différente, en fonction de la requête de l'application cliente. Par exemple, l'arborescence que vous renvoyez à un client à la recherche d'une liste d'éléments multimédias recommandés peut ne contenir que la racine MediaItem
et un seul niveau de nœuds MediaItem
enfants, tandis que l'arborescence que vous revenez à une autre application cliente peut représenter une bibliothèque de contenu plus complète.
Créer un MediaLibrarySession
Un MediaLibrarySession
étend l'API MediaSession
pour ajouter des API de navigation de contenu. Par rapport au rappel MediaSession
, le rappel MediaLibrarySession
ajoute des méthodes telles que:
onGetLibraryRoot()
lorsque le client demande la racineMediaItem
d'une arborescence de contenuonGetChildren()
, lorsque le client demande les enfants d'un élémentMediaItem
dans l'arborescence de contenuonGetSearchResult()
, lorsque un client demande des résultats de recherche dans l'arborescence de contenu pour une requête donnée.
Les méthodes de rappel pertinentes incluent un objet LibraryParams
avec des signaux supplémentaires sur le type d'arborescence de contenu qui intéresse une application cliente.