Framework multimedia Android menyertakan dukungan untuk memutar berbagai jenis media umum agar Anda dapat mengintegrasikan audio, video, dan gambar dengan mudah ke dalam aplikasi Anda. Anda dapat memutar audio atau video dari file media yang disimpan dalam resource aplikasi (resource mentah), dari file mandiri dalam sistem file, atau dari streaming data yang masuk melalui koneksi jaringan, semuanya menggunakan MediaPlayer
API.
Dokumen ini menunjukkan cara menulis aplikasi pemutar media yang berinteraksi dengan pengguna dan sistem untuk mendapatkan performa yang baik dan pengalaman pengguna yang menyenangkan.
Catatan: Anda hanya dapat memutar data audio ke perangkat output standar. Saat ini, perangkat tersebut mencakup speaker perangkat seluler atau headset Bluetooth. Anda tidak dapat memutar file suara dalam audio percakapan saat panggilan sedang berlangsung.
Dasar-dasar
Class berikut digunakan untuk memutar suara dan video dalam framework Android:
MediaPlayer
- Class ini adalah API utama untuk memutar suara dan video.
AudioManager
- Class ini mengelola sumber audio dan output audio di perangkat.
Deklarasi manifes
Sebelum mulai mengembangkan aplikasi menggunakan MediaPlayer, pastikan manifes Anda memiliki deklarasi yang sesuai untuk mengizinkan penggunaan fitur terkait.
- Izin Internet - Jika Anda menggunakan MediaPlayer untuk melakukan streaming konten berbasis
jaringan, aplikasi Anda harus meminta akses jaringan.
<uses-permission android:name="android.permission.INTERNET" />
- Izin Penguncian Layar Saat Aktif - Jika aplikasi pemutar Anda mengharuskan layar tetap menyala
atau mengharuskan prosesor tetap bekerja, atau menggunakan metode
MediaPlayer.setScreenOnWhilePlaying()
atauMediaPlayer.setWakeMode()
, Anda harus meminta izin ini.<uses-permission android:name="android.permission.WAKE_LOCK" />
Menggunakan MediaPlayer
Salah satu komponen terpenting framework media adalah class MediaPlayer
. Objek class ini dapat mengambil, mendekode, serta memutar audio dan video dengan sedikit penyiapan. Class ini mendukung beberapa sumber media yang berbeda, seperti:
- Resource lokal
- URI internal, seperti yang mungkin Anda peroleh dari Content Resolver
- URL eksternal (streaming)
Untuk daftar format media yang didukung Android, lihat halaman Format Media yang Didukung.
Berikut contoh cara memutar audio yang tersedia sebagai resource mentah lokal (disimpan dalam direktori res/raw/
aplikasi Anda):
Kotlin
var mediaPlayer: 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
Dalam hal ini, resource "mentah" adalah file yang tidak akan diuraikan oleh sistem dengan cara khusus apa pun. Namun, konten resource ini tidak boleh berupa audio mentah. Konten ini harus berupa file media yang dienkode dan diformat dengan benar dalam salah satu format yang didukung.
Berikut adalah cara melakukan pemutaran dari URI yang tersedia secara lokal dalam sistem (yang diperoleh melalui Content Resolver, misalnya):
Kotlin
val myUri: Uri = .... // initialize Uri here val mediaPlayer: MediaPlayer? = MediaPlayer().apply { setAudioStreamType(AudioManager.STREAM_MUSIC) setDataSource(applicationContext, myUri) prepare() start() }
Java
Uri myUri = ....; // initialize Uri here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(getApplicationContext(), myUri); mediaPlayer.prepare(); mediaPlayer.start();
Melakukan pemutaran dari URL jarak jauh melalui streaming HTTP akan terlihat seperti ini:
Kotlin
val url = "http://........" // your URL here val mediaPlayer: MediaPlayer? = MediaPlayer().apply { setAudioStreamType(AudioManager.STREAM_MUSIC) setDataSource(url) prepare() // might take long! (for buffering, etc) start() }
Java
String url = "http://........"; // your URL here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(url); mediaPlayer.prepare(); // might take long! (for buffering, etc) mediaPlayer.start();
Catatan: Jika Anda meneruskan URL untuk melakukan streaming file media online, file tersebut harus dapat didownload secara progresif.
Perhatian: Anda harus mengambil atau meneruskan IllegalArgumentException
dan IOException
saat menggunakan setDataSource()
karena file yang Anda referensikan mungkin tidak ada.
Persiapan asinkron
Penggunaan MediaPlayer
pada dasarnya dapat dilakukan dengan cukup mudah. Namun, penting untuk diingat bahwa beberapa hal lainnya diperlukan untuk mengintegrasikannya dengan benar ke aplikasi Android biasa. Contohnya, panggilan ke prepare()
dapat membutuhkan waktu lama untuk dieksekusi karena mungkin memerlukan pengambilan dan dekode data media. Jadi, seperti semua metode yang memerlukan waktu lama untuk dieksekusi, Anda tidak boleh memanggilnya dari UI thread aplikasi. Jika dilakukan, UI akan berhenti sampai metode kembali, yang merupakan pengalaman pengguna yang sangat buruk dan dapat menyebabkan error ANR (Application Not Responding). Meskipun Anda berharap resource akan dimuat dengan cepat, ingatlah bahwa apa pun yang memerlukan waktu lebih dari sepersepuluh detik untuk merespons dalam UI akan menyebabkan jeda yang cukup signifikan dan memberikan kesan bahwa aplikasi Anda lambat.
Untuk menghindari UI thread yang tidak merespons, buat thread lain untuk mempersiapkan MediaPlayer
dan beri tahu thread utama setelah selesai. Namun, meskipun Anda dapat menulis logika thread sendiri, pola ini sudah cukup umum saat menggunakan MediaPlayer
, sehingga framework tersebut akan memudahkan Anda melakukan tugas ini menggunakan metode prepareAsync()
. Metode ini akan mulai mempersiapkan media di latar belakang dan kembali secara langsung. Setelah media selesai disiapkan, metode onPrepared()
dari MediaPlayer.OnPreparedListener
yang dikonfigurasi melalui setOnPreparedListener()
akan dipanggil.
Mengelola status
Aspek lain MediaPlayer
yang harus diingat adalah bahwa class ini didasarkan pada status. Artinya, MediaPlayer
memiliki status internal yang harus selalu Anda perhatikan saat menulis kode, karena operasi tertentu hanya akan valid jika pemutar berada dalam status tertentu. Jika Anda menjalankan operasi dalam status yang salah, sistem mungkin akan menampilkan pengecualian atau menyebabkan perilaku lain yang tidak diinginkan.
Dokumentasi dalam class MediaPlayer
menunjukkan diagram status selengkapnya, yang menjelaskan metode mana yang akan mengalihkan dari satu status ke status lainnya.
Misalnya, saat Anda membuat MediaPlayer
baru, class tersebut akan berada dalam status Tidak ada aktivitas. Pada saat itu, Anda harus menginisialisasinya dengan memanggil setDataSource()
, yang mengalihkannya ke status Diinisialisasi. Setelah itu, Anda harus mempersiapkannya menggunakan metode prepare()
atau prepareAsync()
. Setelah selesai disiapkan, MediaPlayer
akan beralih ke status Disiapkan, yang berarti Anda dapat memanggil start()
agar memutar media. Pada saat tersebut, seperti yang diilustrasikan oleh diagram, Anda dapat mengalihkan status antara Dimulai, Dijeda, dan PlaybackCompleted dengan memanggil metode seperti start()
, pause()
, dan seekTo()
. Namun, saat memanggil stop()
, perhatikan bahwa Anda tidak dapat lagi memanggil start()
sampai MediaPlayer
dipersiapkan kembali.
Selalu ingat diagram status saat menulis kode yang berinteraksi dengan objek MediaPlayer
, karena memanggil metodenya dari status yang salah sering kali menjadi penyebab munculnya bug.
Merilis MediaPlayer
MediaPlayer
dapat menggunakan resource sistem yang cukup signifikan.
Oleh karena itu, Anda harus benar-benar memastikan bahwa instance MediaPlayer
tidak dipertahankan lebih lama dari waktu yang diperlukan. Setelah selesai, Anda harus selalu memanggil release()
untuk memastikan setiap resource sistem yang dialokasikan untuknya dirilis dengan benar. Sebagai contoh, jika Anda menggunakan MediaPlayer
dan aktivitas Anda menerima panggilan ke onStop()
, MediaPlayer
harus dirilis karena tidak ada gunanya bagi Anda untuk mempertahankannya apabila aktivitas sedang tidak berinteraksi dengan pengguna (kecuali media sedang diputar di latar belakang, yang akan dibahas di bagian berikutnya).
Saat aktivitas dilanjutkan atau dimulai ulang, Anda tentu harus membuat MediaPlayer
baru dan mempersiapkannya lagi sebelum melanjutkan pemutaran.
Berikut cara merilis dan menghapus MediaPlayer
:
Kotlin
mediaPlayer?.release() mediaPlayer = null
Java
mediaPlayer.release(); mediaPlayer = null;
Misalnya, pertimbangkan masalah yang mungkin terjadi jika Anda belum merilis MediaPlayer
saat aktivitas dihentikan, tetapi Anda sudah membuat yang baru saat aktivitas dimulai kembali. Seperti yang mungkin sudah Anda ketahui, saat pengguna mengubah orientasi layar (atau mengubah konfigurasi perangkat dengan cara lain), sistem akan menanganinya dengan memulai ulang aktivitas (secara default); akibatnya, Anda mungkin akan menghabiskan semua resource sistem dengan cepat saat pengguna terus-menerus memutar orientasi perangkatnya antara potret dan lanskap, karena setiap kali orientasi berubah, Anda akan membuat MediaPlayer
baru yang tidak pernah dirilis. (Untuk informasi selengkapnya tentang pemulaian ulang waktu proses, lihat Menangani Perubahan Waktu Proses.)
Anda mungkin ingin tahu apa yang akan terjadi jika Anda ingin terus memutar "media latar belakang" meskipun pengguna telah meninggalkan aktivitas Anda, seperti dalam perilaku aplikasi Musik bawaan. Untuk kasus ini, yang Anda butuhkan adalah MediaPlayer
yang dikontrol oleh sebuah Layanan, seperti yang dibahas di bagian berikutnya
Menggunakan MediaPlayer dalam layanan
Jika Anda ingin media tetap diputar di latar belakang meskipun aplikasi sedang tidak ditampilkan di layar, atau dengan kata lain aplikasi terus diputar selagi pengguna berinteraksi dengan aplikasi lain, Anda harus memulai sebuah Layanan dan mengontrol instance MediaPlayer
dari sana.
Anda perlu menyematkan MediaPlayer dalam layanan MediaBrowserServiceCompat
dan membuatnya berinteraksi dengan MediaBrowserCompat
dalam aktivitas lain.
Anda harus berhati-hati dengan penyiapan klien/server ini. Ada ekspektasi tentang cara pemutar yang berjalan di layanan latar belakang berinteraksi dengan seluruh bagian sistem lainnya. Jika aplikasi Anda tidak memenuhi ekspektasi tersebut, pengguna mungkin akan mendapatkan pengalaman yang buruk. Baca Mem-build Aplikasi Audio untuk detail selengkapnya.
Bagian ini menjelaskan petunjuk khusus untuk mengelola MediaPlayer jika diterapkan dalam layanan.
Menjalankan secara asinkron
Sama seperti Activity
, semua tugas dalam Service
dilakukan pada satu thread secara default. Meskipun Anda menjalankan aktivitas dan layanan dari aplikasi yang sama, thread yang sama (“thread utama”) juga akan digunakan oleh keduanya secara default. Oleh karena itu, layanan perlu memproses intent yang masuk dengan cepat dan tidak melakukan komputasi yang panjang saat meresponsnya. Jika ada tugas yang berat atau ada panggilan pemblokir yang diketahui, Anda harus melakukan tugas tersebut secara asinkron: baik dari thread lain yang Anda terapkan sendiri, maupun menggunakan fasilitas framework yang beragam untuk pemrosesan asinkron.
Sebagai contoh, saat menggunakan MediaPlayer
dari thread utama, Anda harus memanggil prepareAsync()
, bukan prepare()
, lalu menerapkan MediaPlayer.OnPreparedListener
agar diberi tahu saat persiapan selesai dan Anda dapat mulai melakukan pemutaran.
Contoh:
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(); } }
Menangani error asinkron
Pada operasi tersinkron, error biasanya akan ditandai dengan pengecualian atau kode kesalahan. Namun, setiap kali menggunakan resource asinkron, Anda harus memastikan bahwa aplikasi diberi tahu tentang error dengan cara yang tepat. Untuk MediaPlayer
, Anda dapat melakukannya dengan menerapkan MediaPlayer.OnErrorListener
dan menyetelnya dalam 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! } }
Perlu diingat bahwa ketika error terjadi, MediaPlayer
akan beralih ke status Error (lihat dokumentasi class
untuk melihat diagram status selengkapnya) dan
Anda harus menyetelnya kembali sebelum dapat menggunakannya lagi.
Menggunakan penguncian layar saat aktif
Ketika Anda merancang aplikasi yang memutar media di latar belakang, perlu diingat bahwa perangkat mungkin akan masuk ke mode tidur saat layanan Anda sedang berjalan. Sistem Android mencoba menghemat baterai saat perangkat tidur, dan oleh karena itu, sistem akan mencoba menonaktifkan semua fitur ponsel yang tidak diperlukan, termasuk hardware Wi-Fi dan CPU. Namun, jika fungsi layanan Anda adalah untuk memutar atau melakukan streaming musik, Anda pasti ingin mencegah sistem mengganggu pemutaran Anda.
Untuk memastikan layanan terus berjalan dalam kondisi tersebut, gunakan "penguncian layar saat aktif". Penguncian layar saat aktif merupakan cara untuk memberi tahu sistem bahwa aplikasi Anda menggunakan beberapa fitur yang harus tetap tersedia meskipun ponsel sedang tidak ada aktivitas.
Pemberitahuan: Gunakan penguncian layar saat aktif seperlunya saja dan hanya pertahankan selama yang diperlukan karena fitur ini dapat mengurangi masa pakai baterai perangkat secara signifikan.
Untuk memastikan CPU terus berjalan saat MediaPlayer
diputar, panggil metode setWakeMode()
saat menginisialisasi Anda. Setelah itu, MediaPlayer
akan mempertahankan penguncian yang ditentukan sembari melakukan pemutaran, lalu membukanya saat dijeda atau dihentikan:
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);
Namun, penguncian layar saat aktif yang diperoleh dalam contoh ini hanya menjamin bahwa CPU akan tetap aktif. Jika Anda melakukan streaming media melalui jaringan dan menggunakan Wi-Fi, Anda mungkin juga perlu menambahkan WifiLock
, yang harus diperoleh dan dirilis secara manual. Jadi, saat mulai mempersiapkan MediaPlayer
dengan URL jarak jauh, Anda harus membuat dan memperoleh penguncian Wi-Fi.
Contoh:
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();
Saat menjeda atau menghentikan media, atau saat tidak lagi memerlukan jaringan, Anda harus merilis penguncian tersebut:
Kotlin
wifiLock.release()
Java
wifiLock.release();
Melakukan pembersihan
Seperti yang sudah dijelaskan, objek MediaPlayer
dapat menggunakan resource sistem dalam jumlah yang signifikan sehingga Anda hanya perlu mempertahankannya selama yang dibutuhkan dan memanggil release()
setelah selesai menggunakannya. Penting bagi Anda untuk memanggil metode pembersihan ini secara eksplisit daripada mengandalkan pembersihan sampah memori yang memerlukan beberapa saat sebelum mengklaim ulang MediaPlayer
, karena fitur ini hanya sensitif terhadap kebutuhan memori tanpa memperhatikan kekurangan resource terkait media lainnya.
Jadi, jika menggunakan layanan, Anda harus selalu mengganti metode onDestroy()
untuk memastikan bahwa MediaPlayer
akan selalu dirilis:
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(); } }
Anda juga harus selalu mencari kesempatan lain untuk merilis MediaPlayer
di samping merilisnya saat ditutup. Sebagai contoh, jika Anda ingin media berhenti diputar setelah jangka waktu yang terlalu lama (misalnya setelah kehilangan fokus audio), Anda tentu harus merilis MediaPlayer
yang sudah ada dan membuatnya lagi nanti. Di sisi lain, jika Anda hanya ingin pemutaran dihentikan untuk waktu yang sangat singkat, sebaiknya pertahankan MediaPlayer
untuk menghindari overhead proses pembuatan dan penyiapan ulang.
Manajemen Hak Digital (DRM)
Dimulai dari Android 8.0 (API level 26), MediaPlayer
menyertakan API yang mendukung pemutaran materi yang dilindungi DRM. API ini mirip dengan API level rendah yang disediakan oleh MediaDrm
, tetapi beroperasi pada level yang lebih tinggi serta tidak menampilkan objek kripto, drm, dan ekstraktor yang mendasarinya.
Meskipun tidak menyediakan fungsionalitas penuh MediaDrm
, API DRM MediaPlayer ini mendukung kasus penggunaan yang paling umum. Penerapan saat ini dapat menangani jenis konten berikut:
- File media lokal yang dilindungi Widevine
- File media jarak jauh/streaming yang dilindungi Widevine
Cuplikan kode berikut menunjukkan cara menggunakan metode MediaPlayer DRM yang baru dalam penerapan tersinkron sederhana.
Untuk mengelola media yang dikontrol DRM, Anda harus menyertakan metode baru tersebut bersama alur biasa pemanggilan MediaPlayer, seperti yang ditunjukkan di bawah ini:
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();
Mulailah seperti biasa dengan menginisialisasi objek MediaPlayer
dan menentukan sumbernya menggunakan setDataSource()
. Kemudian, untuk menggunakan DRM, lakukan langkah-langkah berikut:
- Jika ingin aplikasi Anda melakukan konfigurasi kustom, tentukan antarmuka
OnDrmConfigHelper
, lalu lampirkan ke pemutar menggunakansetOnDrmConfigHelper()
. - Panggil
prepare()
. - Panggil
getDrmInfo()
. Jika sumbernya memiliki konten DRM, metode tersebut akan mengembalikan nilaiMediaPlayer.DrmInfo
non-null.
Jika MediaPlayer.DrmInfo
ada:
- Periksa peta UUID yang tersedia dan pilih salah satunya.
- Persiapkan konfigurasi DRM untuk sumber saat ini dengan memanggil
prepareDrm()
. - Jika Anda membuat dan mendaftarkan callback
OnDrmConfigHelper
, callback tersebut akan dipanggil saatprepareDrm()
dieksekusi. Hal ini memungkinkan Anda melakukan konfigurasi kustom properti DRM sebelum membuka sesi DRM. Callback ini dipanggil secara tersinkron dalam thread yang memanggilprepareDrm()
. Untuk mengakses properti DRM, panggilgetDrmPropertyString()
dansetDrmPropertyString()
. Jangan melakukan operasi yang panjang. - Jika perangkat belum disiapkan,
prepareDrm()
juga akan mengakses server penyediaan untuk menyediakan perangkat. Penyelesaian tindakan ini dapat memakan waktu yang bervariasi, bergantung pada konektivitas jaringan. - Untuk mendapatkan array byte permintaan kunci opaque yang akan dikirim ke server lisensi, panggil
getKeyRequest()
. - Untuk memberi tahu mesin DRM tentang respons kunci yang diterima dari server lisensi, panggil
provideKeyResponse()
. Hasilnya bergantung pada jenis permintaan kunci:- Jika respons ditujukan untuk permintaan kunci offline, hasilnya akan berupa ID rangkaian kunci Anda dapat menggunakan ID rangkaian kunci ini dengan
restoreKeys()
untuk memulihkan kunci ke sesi baru. - Jika respons ditujukan untuk permintaan streaming atau rilis, hasilnya adalah null.
- Jika respons ditujukan untuk permintaan kunci offline, hasilnya akan berupa ID rangkaian kunci Anda dapat menggunakan ID rangkaian kunci ini dengan
Menjalankan prepareDrm()
secara asinkron
Secara default, prepareDrm()
berjalan secara tersinkron, yang melakukan pemblokiran hingga persiapan selesai. Namun, persiapan DRM pada kali pertama di perangkat baru juga mungkin memerlukan penyediaan, yang ditangani secara internal oleh prepareDrm()
, dan mungkin memerlukan waktu lama untuk diselesaikan karena melibatkan operasi jaringan. Anda dapat menghindari pemblokiran pada prepareDrm()
dengan menentukan dan menetapkan MediaPlayer.OnDrmPreparedListener
.
Jika Anda menetapkan OnDrmPreparedListener
, prepareDrm()
akan melakukan penyediaan (jika perlu) dan persiapan di latar belakang. Setelah penyediaan dan persiapan selesai, pemroses akan dipanggil. Jangan berasumsi apa pun tentang urutan pemanggilan atau thread yang menjadi tempat pemroses berjalan (kecuali pemroses didaftarkan dengan thread pengendali).
Pemroses tersebut dapat dipanggil sebelum atau setelah prepareDrm()
kembali.
Menyiapkan DRM secara asinkron
Anda dapat menginisialisasi DRM secara asinkron dengan membuat dan mendaftarkan MediaPlayer.OnDrmInfoListener
untuk persiapan DRM dan MediaPlayer.OnDrmPreparedListener
untuk memulai pemutar.
Keduanya bekerja sama dengan prepareAsync()
, seperti yang ditunjukkan di bawah ini:
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(); }
Menangani media yang dienkripsi
Dimulai dari Android 8.0 (API level 26), MediaPlayer
juga dapat mendekripsi Common Encryption Scheme (CENC) dan media yang dienkripsi dengan level sampel HLS (METHOD=SAMPLE-AES) untuk jenis streaming dasar H.264, dan AAC. Sebelumnya, media terenkripsi segmen penuh (METHOD=AES-128) didukung.
Mengambil media dari ContentResolver
Fitur lain yang mungkin berguna dalam aplikasi pemutar media adalah kemampuan untuk mengambil musik yang ada di perangkat pengguna. Anda dapat melakukannya dengan meminta ContentResolver
untuk media eksternal:
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()); }
Untuk menggunakannya dengan MediaPlayer
, Anda dapat melakukan hal berikut:
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 { setAudioStreamType(AudioManager.STREAM_MUSIC) 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.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(getApplicationContext(), contentUri); // ...prepare and start...
Kode contoh
Contoh BasicMediaDecoder dan DeviceOwner menunjukkan penggunaan API yang dibahas di halaman ini.
Pelajari selengkapnya
Halaman ini membahas topik terkait perekaman, penyimpanan, dan pemutaran audio dan video.