Présentation de MediaPlayer

Le framework multimédia Android prend en charge la lecture de divers types de contenus multimédias courants, ce qui vous permet d'intégrer facilement des contenus audio, vidéo et image à vos applications. Vous pouvez lire du contenu audio ou vidéo à partir de fichiers multimédias stockés dans les ressources de votre application (ressources brutes), à partir de fichiers autonomes du système de fichiers ou d'un flux de données arrivant via une connexion réseau, le tout à l'aide des API MediaPlayer.

Ce document explique comment utiliser MediaPlayer pour écrire une application de lecture multimédia qui interagit avec l'utilisateur et le système afin d'obtenir de bonnes performances et une expérience utilisateur agréable. Vous pouvez également utiliser ExoPlayer, une bibliothèque Open Source personnalisable qui prend en charge des fonctionnalités hautes performances non disponibles dans MediaPlayer.

Remarque:Vous ne pouvez lire les données audio que sur le périphérique de sortie standard. Actuellement, il s'agit du haut-parleur de l'appareil mobile ou d'un casque Bluetooth. Vous ne pouvez pas lire de fichiers audio dans l'audio de la conversation pendant un appel.

Principes de base

Les classes suivantes sont utilisées pour lire du son et de la vidéo dans le framework Android:

MediaPlayer
Cette classe est l'API principale pour la lecture de contenus audio et vidéo.
AudioManager
Cette classe gère les sources audio et la sortie audio d'un appareil.

Déclarations du fichier manifeste

Avant de commencer le développement de votre application avec MediaPlayer, assurez-vous que votre fichier manifeste contient les déclarations appropriées pour permettre l'utilisation des fonctionnalités associées.

  • Autorisation Internet : si vous utilisez MediaPlayer pour diffuser du contenu basé sur le réseau, votre application doit demander l'accès au réseau.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Autorisation Wake Lock : Si l'application de lecteur doit empêcher l'écran de s'assombrir ou le processeur pour se mettre en veille, ou si elle utilise les méthodes MediaPlayer.setScreenOnWhilePlaying() ou MediaPlayer.setWakeMode(), vous devez demander cette autorisation.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

Utiliser MediaPlayer

L'un des composants les plus importants du framework multimédia est la classe MediaPlayer. Un objet de cette classe peut récupérer, décoder et lire des contenus audio et vidéo avec une configuration minimale. Il est compatible avec plusieurs sources multimédias, dont les suivantes:

  • Ressources locales
  • URI internes, tels que celui que vous pouvez obtenir via un résolveur de contenu.
  • URL externes (flux)

Pour obtenir la liste des formats multimédias compatibles avec Android, consultez la page Formats multimédias compatibles.

Voici un exemple de lecture de contenu audio disponible en tant que ressource brute locale (enregistrée dans le répertoire res/raw/ de votre application):

Kotlin

var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer.start() // no need to call prepare(); create() does that for you

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

Dans ce cas, une ressource "brute" est un fichier que le système n'essaie pas d'analyser d'une manière particulière. Toutefois, le contenu de cette ressource ne doit pas être de l'audio brut. Il doit s'agir d'un fichier multimédia correctement encodé et formaté dans l'un des formats acceptés.

Voici comment effectuer la lecture à partir d'un URI disponible localement dans le système (obtenu via un résolveur de contenu, par exemple):

Kotlin

val myUri: Uri = .... // initialize Uri here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, myUri)
    prepare()
    start()
}

Java

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

La lecture à partir d'une URL distante via le streaming HTTP se présente comme suit:

Kotlin

val url = "http://........" // your URL here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(url)
    prepare() // might take long! (for buffering, etc)
    start()
}

Java

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

Remarque:Si vous transmettez une URL pour diffuser un fichier multimédia en ligne, le fichier doit être compatible avec le téléchargement progressif.

Attention:Vous devez intercepter ou transmettre IllegalArgumentException et IOException lorsque vous utilisez setDataSource(), car le fichier auquel vous faites référence n'existe peut-être pas.

Préparation asynchrone

L'utilisation de MediaPlayer peut être simple en principe. Cependant, il est important de garder à l'esprit que quelques opérations sont nécessaires pour l'intégrer correctement à une application Android standard. Par exemple, l'exécution de l'appel à prepare() peut prendre beaucoup de temps, car il peut impliquer l'extraction et le décodage des données multimédias. Par conséquent, comme c'est le cas pour toute méthode dont l'exécution peut prendre du temps, vous ne devez jamais l'appeler à partir du thread UI de votre application. Cela entraîne le blocage de l'interface utilisateur jusqu'à ce que la méthode soit renvoyée, ce qui nuit à l'expérience utilisateur et peut entraîner une erreur ANR (l'application ne répond pas). Même si vous pensez que votre ressource se charge rapidement, n'oubliez pas que toute réponse d'un dixième de seconde dans l'interface utilisateur entraîne une pause notable et donne à l'utilisateur l'impression que votre application est lente.

Pour éviter de suspendre votre thread UI, générez un autre thread pour préparer MediaPlayer et avertissez le thread principal une fois l'opération terminée. Toutefois, bien que vous puissiez écrire la logique de thread vous-même, ce modèle est si courant lorsque vous utilisez MediaPlayer que le framework fournit un moyen pratique d'effectuer cette tâche à l'aide de la méthode prepareAsync(). Cette méthode commence à préparer le contenu multimédia en arrière-plan et s'affiche immédiatement. Une fois la préparation du média terminée, la méthode onPrepared() du MediaPlayer.OnPreparedListener, configurée via setOnPreparedListener(), est appelée.

Gérer l'état

Un autre aspect d'une MediaPlayer que vous devez garder à l'esprit est qu'elle est basée sur l'état. Autrement dit, MediaPlayer possède un état interne dont vous devez toujours être conscient lorsque vous écrivez votre code, car certaines opérations ne sont valides que lorsque le lecteur se trouve dans des états spécifiques. Si vous effectuez une opération dans le mauvais état, le système peut générer une exception ou provoquer d'autres comportements indésirables.

La documentation de la classe MediaPlayer présente un diagramme d'état complet, qui explique quelles méthodes déplacent l'MediaPlayer d'un état à un autre. Par exemple, lorsque vous créez une nouvelle MediaPlayer, elle est à l'état Inactif. À ce stade, vous devez l'initialiser en appelant setDataSource() et en passant à l'état Initialized. Vous devez ensuite le préparer à l'aide de la méthode prepare() ou prepareAsync(). Une fois la préparation de MediaPlayer terminée, il passe à l'état Prepared (préparé), ce qui signifie que vous pouvez appeler start() pour qu'il lit le contenu multimédia. À ce stade, comme l'illustre le diagramme, vous pouvez passer de l'un des états Started (démarré) à l'état PlaybackCompleted (Lecture terminée) en appelant des méthodes telles que start(), pause() et seekTo(), entre autres. Toutefois, lorsque vous appelez stop(), notez que vous ne pouvez pas appeler à nouveau start() tant que vous n'avez pas préparé à nouveau le MediaPlayer.

Gardez toujours à l'esprit le diagramme d'état lorsque vous écrivez du code qui interagit avec un objet MediaPlayer, car appeler ses méthodes à partir d'un état incorrect est une cause fréquente de bugs.

Libérer MediaPlayer

Un MediaPlayer peut consommer de précieuses ressources système. Par conséquent, vous devez toujours prendre des précautions supplémentaires pour vous assurer de ne pas vous accrocher à une instance MediaPlayer plus longtemps que nécessaire. Lorsque vous en avez terminé, vous devez toujours appeler release() pour vous assurer que toutes les ressources système qui lui sont allouées sont correctement libérées. Par exemple, si vous utilisez un MediaPlayer et que votre activité reçoit un appel à onStop(), vous devez libérer MediaPlayer, car il est peu logique de le conserver pendant que votre activité n'interagit pas avec l'utilisateur (sauf si vous lisez du contenu multimédia en arrière-plan, comme expliqué dans la section suivante). Bien entendu, lorsque votre activité est réactivée ou redémarrée, vous devez créer un MediaPlayer et le préparer à nouveau avant de reprendre la lecture.

Voici comment libérer votre MediaPlayer, puis l'annuler:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

Par exemple, prenez en compte les problèmes qui peuvent se produire si vous avez oublié de libérer le MediaPlayer lorsque votre activité est arrêtée, mais que vous en créez un autre lorsque l'activité redémarre. Comme vous le savez peut-être, lorsque l'utilisateur modifie l'orientation de l'écran (ou modifie la configuration de l'appareil d'une autre manière), le système gère cela en redémarrant l'activité (par défaut). Vous pouvez donc consommer rapidement toutes les ressources système lorsque l'utilisateur fait pivoter l'appareil entre les modes portrait et paysage. En effet, à chaque changement d'orientation, vous créez un MediaPlayer que vous ne libérez jamais. Pour en savoir plus sur les redémarrages de l'environnement d'exécution, consultez Gérer les modifications apportées à l'environnement d'exécution.

Vous vous demandez peut-être ce qui se passe si vous souhaitez continuer à lire des "contenus multimédias en arrière-plan" même lorsque l'utilisateur quitte votre activité, à peu près de la même manière que l'application Music intégrée. Dans ce cas, vous avez besoin d'un MediaPlayer contrôlé par un service, comme indiqué dans la section suivante.

Utiliser MediaPlayer dans un service

Si vous souhaitez que votre contenu multimédia s'exécute en arrière-plan même lorsque votre application n'est pas à l'écran (c'est-à-dire si vous voulez que la lecture se poursuive pendant que l'utilisateur interagit avec d'autres applications), vous devez démarrer un service et contrôler l'instance MediaPlayer à partir de là. Vous devez intégrer MediaPlayer à un service MediaBrowserServiceCompat et le faire interagir avec MediaBrowserCompat dans une autre activité.

Soyez prudent lors de la configuration client/serveur. Il existe des attentes quant à la manière dont un joueur qui s'exécute dans un service d'arrière-plan interagit avec le reste du système. Si votre application ne répond pas à ces attentes, l'utilisateur risque de subir une mauvaise expérience. Pour en savoir plus, consultez Créer une application audio.

Cette section décrit des instructions spéciales pour gérer un MediaPlayer lorsqu'il est implémenté dans un service.

Exécuter de manière asynchrone

Tout d'abord, à l'instar d'un Activity, toutes les tâches d'un Service sont effectuées par défaut dans un seul thread. En fait, si vous exécutez une activité et un service de la même application, ils utilisent le même thread (le "thread principal") par défaut. Par conséquent, les services doivent traiter rapidement les intents entrants et ne jamais effectuer de longs calculs lorsqu'ils y répondent. Si des appels importants ou bloquants sont attendus, vous devez effectuer ces tâches de manière asynchrone: soit à partir d'un autre thread que vous implémentez vous-même, soit en utilisant les nombreuses fonctionnalités du framework pour un traitement asynchrone.

Par exemple, lorsque vous utilisez un MediaPlayer à partir de votre thread principal, vous devez appeler prepareAsync() plutôt que prepare(), et implémenter un MediaPlayer.OnPreparedListener afin d'être averti lorsque la préparation est terminée et que vous pouvez commencer à jouer. Par exemple :

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

Gérer les erreurs asynchrones

Pour les opérations synchrones, les erreurs sont normalement signalées par une exception ou un code d'erreur. Toutefois, lorsque vous utilisez des ressources asynchrones, vous devez vous assurer que votre application est informée des erreurs de manière appropriée. Dans le cas d'une MediaPlayer, vous pouvez y parvenir en implémentant un MediaPlayer.OnErrorListener et en le définissant dans votre instance MediaPlayer:

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

N'oubliez pas que lorsqu'une erreur se produit, MediaPlayer passe à l'état Error (erreur) (consultez la documentation de la classe MediaPlayer pour obtenir le schéma d'état complet). Vous devez alors la réinitialiser avant de pouvoir l'utiliser à nouveau.

Utiliser des wakelocks

Lorsque vous concevez des applications qui lisent des contenus multimédias en arrière-plan, l'appareil peut se mettre en veille pendant l'exécution de votre service. Comme le système Android tente de préserver la batterie pendant que l'appareil est en veille, le système tente de désactiver toutes les fonctionnalités du téléphone qui ne sont pas nécessaires, y compris le processeur et le matériel Wi-Fi. Toutefois, si votre service lit ou diffuse de la musique en streaming, vous devez empêcher le système d'interférer avec la lecture.

Pour vous assurer que votre service continue de fonctionner dans ces conditions, vous devez utiliser des wakelocks. Un wakelock est un moyen de signaler au système que votre application utilise une fonctionnalité qui doit rester disponible même si le téléphone est inactif.

Remarque:Vous devez toujours utiliser les wakelocks avec parcimonie et ne les maintenir enfoncés que le temps vraiment nécessaire, car ils réduisent considérablement l'autonomie de la batterie de l'appareil.

Pour vous assurer que le processeur continue de s'exécuter pendant la lecture de votre MediaPlayer, appelez la méthode setWakeMode() lors de l'initialisation de votre MediaPlayer. Une fois cette opération effectuée, MediaPlayer conserve le verrou spécifié pendant la lecture et le libère lorsqu'il est mis en pause ou arrêté:

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

Toutefois, le wakelock acquis dans cet exemple garantit uniquement que le processeur reste activé. Si vous diffusez du contenu multimédia en streaming sur le réseau et que vous utilisez le Wi-Fi, vous souhaiterez probablement conserver également un WifiLock, que vous devez acquérir et publier manuellement. Ainsi, lorsque vous commencez à préparer le MediaPlayer avec l'URL distante, vous devez créer et acquérir le verrou Wi-Fi. Par exemple :

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

Lorsque vous mettez en pause ou arrêtez votre contenu multimédia, ou lorsque vous n'avez plus besoin du réseau, vous devez débloquer le verrouillage:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Nettoyage en cours

Comme indiqué précédemment, un objet MediaPlayer peut consommer une quantité importante de ressources système. Vous ne devez donc le conserver que pendant la durée nécessaire et appeler release() lorsque vous n'en avez plus besoin. Il est important d'appeler explicitement cette méthode de nettoyage plutôt que d'utiliser la récupération de mémoire du système. En effet, le récupérateur de mémoire peut mettre un certain temps à récupérer le MediaPlayer, car il est uniquement sensible aux besoins de mémoire et non à la pénurie d'autres ressources multimédias. Ainsi, lorsque vous utilisez un service, vous devez toujours remplacer la méthode onDestroy() pour vous assurer de publier le MediaPlayer:

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

Vous devez toujours rechercher d'autres opportunités pour libérer votre MediaPlayer, en plus de le libérer lors de son arrêt. Par exemple, si vous vous attendez à ne pas pouvoir lire le contenu multimédia pendant une période prolongée (après avoir perdu la priorité audio, par exemple), vous devez absolument libérer votre MediaPlayer existant et le recréer plus tard. En revanche, si vous prévoyez d'arrêter la lecture pendant une courte période, vous devez probablement conserver votre MediaPlayer pour éviter de devoir le créer et le préparer à nouveau.

Gestion des droits numériques (DRM)

À partir d'Android 8.0 (niveau d'API 26), MediaPlayer inclut des API compatibles avec la lecture de contenus protégés par DRM. Ils sont semblables à l'API de bas niveau fournie par MediaDrm, mais ils fonctionnent à un niveau plus élevé et n'exposent pas les objets extracteurs, drm et cryptos sous-jacents.

Bien que l'API DRM de MediaPlayer n'offre pas toutes les fonctionnalités de MediaDrm, elle est compatible avec les cas d'utilisation les plus courants. L'implémentation actuelle peut gérer les types de contenu suivants:

  • Fichiers multimédias locaux protégés par Widevine
  • Fichiers multimédias distants/en streaming protégés par Widevine

L'extrait de code suivant montre comment utiliser les nouvelles méthodes DRM MediaPlayer dans une implémentation synchrone simple.

Pour gérer des contenus multimédias contrôlés par DRM, vous devez inclure les nouvelles méthodes en plus du flux habituel d'appels MediaPlayer, comme indiqué ci-dessous:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

Commencez par initialiser l'objet MediaPlayer et définir sa source à l'aide de setDataSource(), comme d'habitude. Ensuite, pour utiliser la DRM, procédez comme suit:

  1. Si vous souhaitez que votre application effectue une configuration personnalisée, définissez une interface OnDrmConfigHelper et associez-la au lecteur à l'aide de setOnDrmConfigHelper().
  2. Appelez prepare().
  3. Appelez getDrmInfo(). Si la source comporte du contenu DRM, la méthode renvoie une valeur MediaPlayer.DrmInfo non nulle.

Si MediaPlayer.DrmInfo existe:

  1. Examinez le plan des UUID disponibles et choisissez-en un.
  2. Préparez la configuration DRM pour la source actuelle en appelant prepareDrm().
    • Si vous avez créé et enregistré un rappel OnDrmConfigHelper, il est appelé pendant l'exécution de prepareDrm(). Cela vous permet d'effectuer une configuration personnalisée des propriétés DRM avant d'ouvrir la session DRM. Le rappel est appelé de manière synchrone dans le thread qui a appelé prepareDrm(). Pour accéder aux propriétés DRM, appelez getDrmPropertyString() et setDrmPropertyString(). Évitez d'effectuer des opérations longues.
    • Si l'appareil n'a pas encore été provisionné, prepareDrm() accède également au serveur de provisionnement pour le provisionner. Cette opération peut prendre un certain temps, en fonction de la connectivité réseau.
  3. Pour obtenir un tableau d'octets de requête de clé opaque à envoyer à un serveur de licences, appelez getKeyRequest().
  4. Pour informer le moteur DRM de la réponse de clé reçue du serveur de licences, appelez provideKeyResponse(). Le résultat dépend du type de requête de clé :
    • Si la réponse concerne une requête de clé hors connexion, le résultat est un identifiant de jeu de clés. Vous pouvez utiliser cet identifiant de jeu de clés avec restoreKeys() pour restaurer les clés dans une nouvelle session.
    • Si la réponse concerne une requête de streaming ou de libération, le résultat est nul.

Exécuter prepareDrm() de manière asynchrone

Par défaut, prepareDrm() s'exécute de manière synchrone et bloque jusqu'à la fin de la préparation. Cependant, la toute première préparation DRM sur un nouvel appareil peut également nécessiter un provisionnement, géré en interne par prepareDrm(), et peut prendre un certain temps en raison de l'opération réseau impliquée. Vous pouvez éviter le blocage sur prepareDrm() en définissant et en définissant un MediaPlayer.OnDrmPreparedListener.

Lorsque vous définissez un OnDrmPreparedListener, prepareDrm() effectue le provisionnement (si nécessaire) et la préparation en arrière-plan. Une fois le provisionnement et la préparation terminés, l'écouteur est appelé. Vous ne devez faire aucune hypothèse concernant la séquence d'appel ni le thread dans lequel l'écouteur s'exécute (sauf si l'écouteur est enregistré auprès d'un thread de gestionnaire). L'écouteur peut être appelé avant ou après le renvoi de prepareDrm().

Configurer la DRM de manière asynchrone

Vous pouvez initialiser la DRM de manière asynchrone en créant et en enregistrant le MediaPlayer.OnDrmInfoListener pour la préparation de la DRM et le MediaPlayer.OnDrmPreparedListener pour démarrer le lecteur. Elles fonctionnent avec prepareAsync(), comme indiqué ci-dessous:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

Gérer les contenus multimédias chiffrés

À partir d'Android 8.0 (niveau d'API 26), MediaPlayer peut également déchiffrer le schéma CENC (Common Encryption Scheme) et les contenus multimédias chiffrés au niveau de l'échantillon HLS (Method=Sample-AES) pour les types de flux élémentaires H.264 et AAC. Auparavant, le chiffrement du segment complet (MÉTHODE=AES-128) était pris en charge.

Récupérer des fichiers multimédias à partir d'un ContentResolver

Une autre fonctionnalité qui peut être utile dans une application de lecteur multimédia est la possibilité de récupérer de la musique présente sur l'appareil de l'utilisateur. Pour ce faire, interrogez ContentResolver pour obtenir des médias externes:

Kotlin

val resolver: ContentResolver = contentResolver
val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor? = resolver.query(uri, null, null, null, null)
when {
    cursor == null -> {
        // query failed, handle error.
    }
    !cursor.moveToFirst() -> {
        // no media on the device
    }
    else -> {
        val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)
        val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)
        do {
            val thisId = cursor.getLong(idColumn)
            val thisTitle = cursor.getString(titleColumn)
            // ...process entry...
        } while (cursor.moveToNext())
    }
}
cursor?.close()

Java

ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
    // query failed, handle error.
} else if (!cursor.moveToFirst()) {
    // no media on the device
} else {
    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
    do {
       long thisId = cursor.getLong(idColumn);
       String thisTitle = cursor.getString(titleColumn);
       // ...process entry...
    } while (cursor.moveToNext());
}

Pour l'utiliser avec MediaPlayer, procédez comme suit:

Kotlin

val id: Long = /* retrieve it from somewhere */
val contentUri: Uri =
    ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id )

mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, contentUri)
}

// ...prepare and start...

Java

long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), contentUri);

// ...prepare and start...

En savoir plus

Ces pages couvrent des sujets liés à l'enregistrement, au stockage et à la lecture de contenus audio et vidéo.