Pratinjau Developer untuk Android 11 kini tersedia; uji dan sampaikan masukan Anda.

Ringkasan MediaPlayer

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() atau MediaPlayer.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:

  1. Jika ingin aplikasi Anda melakukan konfigurasi kustom, tentukan antarmuka OnDrmConfigHelper, lalu lampirkan ke pemutar menggunakan setOnDrmConfigHelper().
  2. Panggil prepare().
  3. Panggil getDrmInfo(). Jika sumbernya memiliki konten DRM, metode tersebut akan mengembalikan nilai MediaPlayer.DrmInfo non-null.

Jika MediaPlayer.DrmInfo ada:

  1. Periksa peta UUID yang tersedia dan pilih salah satunya.
  2. Persiapkan konfigurasi DRM untuk sumber saat ini dengan memanggil prepareDrm().
    • Jika Anda membuat dan mendaftarkan callback OnDrmConfigHelper, callback tersebut akan dipanggil saat prepareDrm() dieksekusi. Hal ini memungkinkan Anda melakukan konfigurasi kustom properti DRM sebelum membuka sesi DRM. Callback ini dipanggil secara tersinkron dalam thread yang memanggil prepareDrm(). Untuk mengakses properti DRM, panggil getDrmPropertyString() dan setDrmPropertyString(). 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.
  3. Untuk mendapatkan array byte permintaan kunci opaque yang akan dikirim ke server lisensi, panggil getKeyRequest().
  4. 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.

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.