Panoramica di MediaPlayer

Il framework multimediale Android include il supporto per la riproduzione di vari tipi di contenuti multimediali comuni, in modo da poter integrare facilmente audio, video e immagini nelle tue applicazioni. Puoi riprodurre audio o video da file multimediali archiviati nelle risorse dell'applicazione (risorse non elaborate), da file autonomi nel file system o da uno stream di dati in arrivo tramite una connessione di rete, il tutto utilizzando le API MediaPlayer.

Questo documento spiega come utilizzare MediaPlayer per scrivere un'applicazione per la riproduzione di contenuti multimediali che interagisca con l'utente e il sistema al fine di ottenere buone prestazioni e un'esperienza utente piacevole. In alternativa, puoi utilizzare ExoPlayer, una libreria open source personalizzabile che supporta funzionalità ad alte prestazioni non disponibili in MediaPlayer

Nota: puoi riprodurre i dati audio solo sul dispositivo di output standard. Attualmente, si tratta dell'altoparlante del dispositivo mobile o delle cuffie Bluetooth. Non puoi riprodurre file audio nell'audio della conversazione durante una chiamata.

Nozioni di base

Per riprodurre audio e video nel framework Android vengono utilizzate le seguenti classi:

MediaPlayer
Questa classe è l'API principale per la riproduzione di audio e video.
AudioManager
Questo corso gestisce le sorgenti audio e l'output audio su un dispositivo.

Dichiarazioni del file manifest

Prima di iniziare lo sviluppo della tua applicazione utilizzando MediaPlayer, assicurati che il file manifest contenga le dichiarazioni appropriate per consentire l'utilizzo delle funzionalità correlate.

  • Autorizzazione Internet. Se utilizzi MediaPlayer per la riproduzione in streaming di contenuti basati su rete, l'applicazione deve richiedere l'accesso alla rete.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Autorizzazione wakelock: se l'applicazione del player deve impedire l'oscuramento dello schermo o del processore, oppure se utilizza i metodi MediaPlayer.setScreenOnWhilePlaying() o MediaPlayer.setWakeMode(), devi richiedere questa autorizzazione.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

Utilizzo di MediaPlayer

Uno dei componenti più importanti del framework multimediale è la classe MediaPlayer. Un oggetto di questa classe può recuperare, decodificare e riprodurre audio e video con una configurazione minima. Supporta diverse fonti multimediali quali:

  • Risorse locali
  • URI interni, ad esempio quello che potresti ottenere da un sistema di risoluzione dei contenuti
  • URL esterni (streaming)

Per un elenco dei formati multimediali supportati da Android, consulta la pagina Formati multimediali supportati.

Ecco un esempio di come riprodurre l'audio disponibile come risorsa non elaborata locale (salvato nella directory res/raw/ dell'applicazione):

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

In questo caso, una risorsa "non elaborata" è un file che il sistema non prova ad analizzare in alcun modo. Tuttavia, i contenuti di questa risorsa non devono essere audio non elaborati. Deve essere un file multimediale correttamente codificato e formattato in uno dei formati supportati.

Ecco come potresti riprodurre un URI da un URI disponibile localmente nel sistema (ottenuto tramite un sistema di risoluzione dei contenuti, ad esempio):

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 riproduzione da un URL remoto tramite streaming HTTP ha il seguente aspetto:

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

Nota: se trasmetti un URL per trasmettere in streaming un file multimediale online, il file deve poter essere scaricato progressivo.

Attenzione: devi rilevare o passare IllegalArgumentException e IOException quando utilizzi setDataSource(), perché il file a cui fai riferimento potrebbe non esistere.

Preparazione asincrona

L'uso di MediaPlayer può essere semplice in linea di principio. Tuttavia, è importante tenere presente che sono necessarie alcune altre cose per integrarlo correttamente con una tipica applicazione Android. Ad esempio, l'esecuzione della chiamata a prepare() può richiedere molto tempo perché potrebbe comportare il recupero e la decodifica dei dati multimediali. Pertanto, come nel caso di qualsiasi metodo che richieda molto tempo per l'esecuzione, non dovresti mai chiamarlo dal thread dell'interfaccia utente della tua applicazione. In questo modo l'interfaccia utente si blocca fino a quando non viene restituito il metodo, il che costituisce un'esperienza utente molto negativa e può causare un errore ANR (L'applicazione non risponde). Anche se prevedi che la risorsa venga caricata rapidamente, ricorda che tutto ciò che richiede più di un decimo di secondo per rispondere nell'interfaccia utente causa una pausa notevole e dà all'utente l'impressione che l'applicazione sia lenta.

Per evitare di bloccare il thread dell'interfaccia utente, genera un altro thread per preparare MediaPlayer e invia una notifica al thread principale una volta terminato. Tuttavia, anche se puoi scrivere autonomamente la logica di threading, questo pattern è talmente comune quando utilizzi MediaPlayer che il framework offre un modo pratico per svolgere questa attività utilizzando il metodo prepareAsync(). Questo metodo avvia la preparazione dei contenuti multimediali in background e viene restituito immediatamente. Una volta terminata la preparazione dei contenuti multimediali, viene richiamato il metodo onPrepared() di MediaPlayer.OnPreparedListener, configurato tramite setOnPreparedListener().

Gestione dello stato

Un altro aspetto di MediaPlayer da tenere presente è che è basato sullo stato. In altre parole, MediaPlayer ha uno stato interno di cui devi sempre essere a conoscenza quando scrivi il codice, perché alcune operazioni sono valide solo quando il player si trova in uno stato specifico. Se esegui un'operazione in stato errato, il sistema potrebbe generare un'eccezione o causare altri comportamenti indesiderati.

La documentazione della classe MediaPlayer mostra un diagramma di stato completo che chiarisce i metodi che consentono di spostare MediaPlayer da uno stato a un altro. Ad esempio, quando crei un nuovo MediaPlayer, questo è nello stato Inattivo. A quel punto, devi inizializzarlo chiamando setDataSource(), portandolo allo stato Inizializzato. Successivamente, devi prepararlo utilizzando il metodo prepare() o prepareAsync(). Al termine della preparazione, MediaPlayer entra nello stato Preparato, il che significa che puoi chiamare start() per riprodurre i contenuti multimediali. A quel punto, come illustrato nel diagramma, puoi spostarti tra gli stati Avviato, In pausa e RiproduzioneCompletato richiamando metodi come start(), pause() e seekTo(), tra gli altri. Quando chiami stop(), tuttavia, nota che non puoi chiamare di nuovo start() finché non prepari di nuovo MediaPlayer.

Tieni sempre a mente il diagramma di stato quando scrivi codice che interagisce con un oggetto MediaPlayer, poiché la chiamata dei metodi dallo stato sbagliato è una causa comune di bug.

Rilascio di Media Player

Un elemento MediaPlayer può consumare preziose risorse di sistema. Pertanto, dovresti sempre prendere precauzioni aggiuntive per assicurarti di non agganciare a un'istanza MediaPlayer più a lungo del necessario. Al termine, devi sempre chiamare release() per assicurarti che tutte le risorse di sistema allocate siano rilasciate correttamente. Ad esempio, se stai utilizzando un MediaPlayer e la tua attività riceve una chiamata al numero onStop(), devi rilasciare MediaPlayer perché non ha senso tenerlo premuto mentre l'attività non interagisce con l'utente (a meno che tu non stia riproducendo contenuti multimediali in background, come illustrato nella sezione successiva). Quando l'attività viene ripresa o riavviata, ovviamente devi creare un nuovo MediaPlayer e prepararlo di nuovo prima di riprendere la riproduzione.

Ecco come rilasciare e annullare MediaPlayer:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

Ad esempio, considera i problemi che potrebbero verificarsi se dimentichi di rilasciare MediaPlayer quando l'attività viene interrotta, ma creane uno nuovo quando l'attività ricomincia. Come forse saprai, quando l'utente cambia l'orientamento dello schermo (o la configurazione del dispositivo in altro modo), il sistema lo gestisce riavviando l'attività (per impostazione predefinita), pertanto potresti rapidamente utilizzare tutte le risorse di sistema mentre l'utente ruota il dispositivo avanti e indietro tra verticale e orizzontale, perché a ogni modifica di orientamento crei un nuovo MediaPlayer che non rilascerai mai. Per ulteriori informazioni sui riavvii del runtime, consulta Gestione delle modifiche al runtime.

Forse ti starai chiedendo che cosa succede se vuoi continuare a riprodurre "contenuti multimediali in background" anche quando l'utente abbandona la tua attività, più o meno come si comporta l'applicazione Music integrata. In questo caso, ti serve un MediaPlayer controllato da un servizio, come discusso nella prossima sezione

Utilizzo di MediaPlayer in un servizio

Se vuoi che i tuoi contenuti multimediali vengano riprodotti in background anche quando la tua applicazione non è sullo schermo, ovvero vuoi che la riproduzione continui mentre l'utente interagisce con altre applicazioni, devi avviare un servizio e controllare l'istanza MediaPlayer da lì. Devi incorporare il MediaPlayer in un servizio MediaBrowserServiceCompat e farlo interagire con un MediaBrowserCompat in un'altra attività.

Devi fare attenzione a questa configurazione client/server. Esistono aspettative su come un player in esecuzione in un servizio in background interagisca con il resto del sistema. Se l'applicazione non soddisfa queste aspettative, l'utente potrebbe avere un'esperienza negativa. Per ulteriori dettagli, consulta Creazione di un'app audio.

In questa sezione vengono descritte istruzioni speciali per la gestione di un Media Player quando è implementato all'interno di un servizio.

Esecuzione asincrona

Prima di tutto, come un Activity, tutto il lavoro in un Service viene eseguito in un singolo thread per impostazione predefinita. Infatti, se stai eseguendo un'attività e un servizio dalla stessa applicazione, utilizzano lo stesso thread (il "thread principale") per impostazione predefinita. Pertanto, i servizi devono elaborare rapidamente gli intent in entrata e non eseguire mai lunghi calcoli quando rispondono. Se sono previsti lavori pesanti o chiamate di blocco, devi eseguire queste attività in modo asincrono: da un altro thread che implementi personalmente o utilizzando le numerose strutture del framework per l'elaborazione asincrona.

Ad esempio, se utilizzi un oggetto MediaPlayer dal thread principale, devi chiamare prepareAsync() anziché prepare() e implementare un MediaPlayer.OnPreparedListener per ricevere una notifica al termine della preparazione e poter iniziare a giocare. Ecco alcuni esempi:

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

Gestione degli errori asincroni

Nelle operazioni sincrone, gli errori in genere vengono segnalati con un'eccezione o un codice di errore, ma ogni volta che utilizzi risorse asincrone, assicurati che la tua applicazione riceva correttamente gli errori. Nel caso di MediaPlayer, puoi eseguire questa operazione implementando MediaPlayer.OnErrorListener e impostandola nell'istanza 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!
    }
}

È importante ricordare che quando si verifica un errore, MediaPlayer passa allo stato Error (consulta la documentazione della classe MediaPlayer per il diagramma dello stato completo) e devi reimpostarlo per poterlo utilizzare di nuovo.

Utilizzo dei wakelock

Durante la progettazione di applicazioni che riproducono contenuti multimediali in background, il dispositivo può entrare in modalità di sospensione mentre il servizio è in esecuzione. Il sistema Android cerca di risparmiare batteria mentre il dispositivo è in modalità di sospensione, pertanto tenta di disattivare tutte le funzionalità del telefono non necessarie, tra cui la CPU e l'hardware Wi-Fi. Tuttavia, se il servizio riproduce o riproduce musica in streaming, è consigliabile evitare che il sistema interferisca con la riproduzione.

Per assicurarti che il servizio continui a essere eseguito a queste condizioni, devi utilizzare i "wakelock". Un wakelock è un modo per segnalare al sistema che l'applicazione sta utilizzando alcune funzionalità che dovrebbero rimanere disponibili anche quando il telefono è inattivo.

Attenzione: dovresti sempre utilizzare i wakelock con moderazione e tenerli solo per il tempo necessario, poiché riducono notevolmente la durata della batteria del dispositivo.

Per assicurarti che la CPU continui a essere eseguita durante la riproduzione di MediaPlayer, chiama il metodo setWakeMode() durante l'inizializzazione di MediaPlayer. Dopo averlo fatto, MediaPlayer trattiene il blocco specificato durante la riproduzione e rilascia il blocco quando viene messo in pausa o interrotto:

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

Tuttavia, il wakelock acquisito in questo esempio garantisce solo che la CPU rimanga attiva. Se trasmetti in streaming contenuti multimediali sulla rete e usi il Wi-Fi, probabilmente vorrai tenere anche un WifiLock, che devi acquisire e rilasciare manualmente. Di conseguenza, quando inizi a preparare MediaPlayer con l'URL remoto, devi creare e acquisire il blocco del Wi-Fi. Ecco alcuni esempi:

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

Quando metti in pausa o interrompi i contenuti multimediali o quando non hai più bisogno della rete, devi rilasciare il blocco:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Esecuzione della pulizia in corso...

Come accennato in precedenza, un oggetto MediaPlayer può consumare una notevole quantità di risorse di sistema, quindi devi conservarlo solo per il tempo necessario e chiamare release() al termine dell'operazione. È importante chiamare questo metodo di pulizia in modo esplicito anziché fare affidamento sulla garbage collection del sistema, perché potrebbe trascorrere del tempo prima che il garbage collector rivendichi MediaPlayer, poiché è sensibile solo alle esigenze di memoria e non alla carenza di altre risorse relative ai contenuti multimediali. Quindi, nel caso in cui utilizzi un servizio, dovresti sempre eseguire l'override del metodo onDestroy() per assicurarti di rilasciare 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();
   }
}

Dovresti sempre cercare anche altre opportunità per rilasciare MediaPlayer, a parte il rilascio durante la chiusura. Ad esempio, se prevedi di non riuscire a riprodurre i contenuti multimediali per un lungo periodo di tempo (ad esempio dopo aver perso lo stato attivo sull'audio), devi rilasciare il tuo file MediaPlayer esistente e crearlo di nuovo in un secondo momento. Se, invece, prevedi di interrompere la riproduzione solo per un breve periodo di tempo, probabilmente dovresti tenere premuto il tuo MediaPlayer per evitare l'overhead associato alla creazione e alla nuova preparazione.

Gestione dei diritti digitali (DRM)

A partire da Android 8.0 (livello API 26), MediaPlayer include le API che supportano la riproduzione di materiale protetto da DRM. Sono simili all'API di basso livello fornita da MediaDrm, ma operano a un livello superiore e non espongono l'estrattore, drm e gli oggetti crittografici sottostanti.

Sebbene l'API MediaPlayer DRM non fornisca tutte le funzionalità di MediaDrm, supporta i casi d'uso più comuni. L'implementazione corrente è in grado di gestire i seguenti tipi di contenuti:

  • File multimediali locali protetti da Widevine
  • File multimediali in streaming/remoti protetti da widevine

Il seguente snippet di codice mostra come utilizzare i nuovi metodi DRM MediaPlayer in una semplice implementazione sincrona.

Per gestire i contenuti multimediali controllati con DRM, devi includere i nuovi metodi insieme al normale flusso di chiamate MediaPlayer, come mostrato di seguito:

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

Inizia inizializzando l'oggetto MediaPlayer e impostando la sua origine utilizzando setDataSource(), come di consueto. Quindi, per utilizzare DRM, segui questi passaggi:

  1. Se vuoi che la tua app esegua una configurazione personalizzata, definisci un'interfaccia OnDrmConfigHelper e collegala al player utilizzando setOnDrmConfigHelper().
  2. Chiama il numero prepare().
  3. Chiama il numero getDrmInfo(). Se l'origine ha contenuti DRM, il metodo restituisce un valore MediaPlayer.DrmInfo diverso da null.

Se MediaPlayer.DrmInfo esiste:

  1. Esamina la mappa degli UUID disponibili e scegline uno.
  2. Prepara la configurazione DRM per l'origine attuale chiamando prepareDrm().
    • Se hai creato e registrato un callback OnDrmConfigHelper, questo viene chiamato mentre prepareDrm() è in esecuzione. In questo modo puoi eseguire la configurazione personalizzata delle proprietà DRM prima di aprire la sessione DRM. Il callback è chiamato in modo sincrono nel thread che ha chiamato prepareDrm(). Per accedere alle proprietà DRM, chiama getDrmPropertyString() e setDrmPropertyString(). Evita di eseguire operazioni lunghe.
    • Se non è stato ancora eseguito il provisioning del dispositivo, prepareDrm() accede anche al server di provisioning per eseguire il provisioning del dispositivo. Questa operazione può richiedere un periodo di tempo variabile, a seconda della connettività di rete.
  3. Per ottenere un array di byte di richiesta della chiave opaca da inviare a un server delle licenze, chiama getKeyRequest().
  4. Per informare il motore DRM della risposta della chiave ricevuta dal server delle licenze, chiama provideKeyResponse(). Il risultato dipende dal tipo di richiesta della chiave:
    • Se la risposta riguarda una richiesta di chiave offline, il risultato è un identificatore del set di chiavi. Puoi utilizzare questo identificatore del set di chiavi con restoreKeys() per ripristinare le chiavi in una nuova sessione.
    • Se la risposta riguarda una richiesta di streaming o di rilascio, il risultato è null.

Esecuzione di prepareDrm() in modo asincrono

Per impostazione predefinita, prepareDrm() viene eseguito in modo sincrono, bloccando fino al termine della preparazione. Tuttavia, la primissima preparazione di DRM su un nuovo dispositivo potrebbe richiedere anche il provisioning, che è gestito internamente da prepareDrm() e il suo completamento potrebbe richiedere del tempo a causa dell'operazione di rete interessata. Per evitare di bloccare l'elemento in prepareDrm(), definisci e imposta un valore MediaPlayer.OnDrmPreparedListener.

Quando imposti un OnDrmPreparedListener, prepareDrm() esegue il provisioning (se necessario) e la preparazione in background. Al termine del provisioning e della preparazione, viene chiamato il listener. Non devi presupporre che la sequenza di chiamata o il thread in cui viene eseguito l'ascoltatore (a meno che il listener non sia registrato con un thread del gestore). Il listener può essere chiamato prima o dopo il ritorno di prepareDrm().

Configurazione asincrona di DRM

Puoi inizializzare il DRM in modo asincrono creando e registrando il MediaPlayer.OnDrmInfoListener per la preparazione DRM e il MediaPlayer.OnDrmPreparedListener per avviare il player. Funzionano in combinazione con prepareAsync(), come mostrato di seguito:

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

Gestione dei contenuti multimediali criptati

A partire da Android 8.0 (livello API 26) MediaPlayer può anche decriptare lo schema Common Encryption Scheme (CENC) e i contenuti multimediali HLS criptati a livello di campione (METHOD=CAMPAIGN-AES) per i tipi di stream elementari H.264 e AAC. I contenuti multimediali criptati a segmento completo (METHOD=AES-128) erano precedentemente supportati.

Recupero di contenuti multimediali da un ContentResolver

Un'altra funzione che può essere utile in un'applicazione per media player è la possibilità di recuperare la musica presente sull'utente sul dispositivo. Per farlo, puoi eseguire una query su ContentResolver per i supporti esterni:

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

Per usare la funzionalità con l'MediaPlayer, puoi:

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

Scopri di più

Queste pagine trattano argomenti relativi alla registrazione, all'archiviazione e alla riproduzione di audio e video.