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()
oMediaPlayer.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:
- Se vuoi che la tua app esegua una configurazione personalizzata, definisci un'interfaccia
OnDrmConfigHelper
e collegala al player utilizzandosetOnDrmConfigHelper()
. - Chiama il numero
prepare()
. - Chiama il numero
getDrmInfo()
. Se l'origine ha contenuti DRM, il metodo restituisce un valoreMediaPlayer.DrmInfo
diverso da null.
Se MediaPlayer.DrmInfo
esiste:
- Esamina la mappa degli UUID disponibili e scegline uno.
- Prepara la configurazione DRM per l'origine attuale chiamando
prepareDrm()
. - Se hai creato e registrato un callback
OnDrmConfigHelper
, questo viene chiamato mentreprepareDrm()
è 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 chiamatoprepareDrm()
. Per accedere alle proprietà DRM, chiamagetDrmPropertyString()
esetDrmPropertyString()
. 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. - Per ottenere un array di byte di richiesta della chiave opaca da inviare a un server delle licenze, chiama
getKeyRequest()
. - 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.
- 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
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.