Ringkasan MediaPlayer

Framework multimedia Android menyertakan dukungan untuk memutar berbagai jenis media umum, sehingga Anda dapat dengan mudah mengintegrasikan audio, video, dan gambar ke dalam aplikasi. Anda dapat memutar audio atau video dari file media yang disimpan dalam resource aplikasi (resource mentah), dari file mandiri dalam sistem file, atau dari aliran data yang masuk melalui koneksi jaringan, semuanya menggunakan MediaPlayer API.

Dokumen ini menunjukkan cara menggunakan MediaPlayer untuk menulis aplikasi pemutaran media yang berinteraksi dengan pengguna dan sistem untuk mendapatkan performa yang baik dan pengalaman pengguna yang menyenangkan. Atau, Anda mungkin ingin menggunakan ExoPlayer, yang merupakan library open source yang dapat disesuaikan dan mendukung fitur performa tinggi yang tidak tersedia di MediaPlayer

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 selama panggilan 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 memulai pengembangan pada 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 perlu menjaga layar agar tidak meredup atau prosesor tidak memasuki mode tidur, 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 dari framework media adalah class MediaPlayer. Objek class ini dapat mengambil, mendekode, dan memutar audio serta video dengan penyiapan minimal. 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 ini contoh cara memutar audio yang tersedia sebagai resource mentah lokal (disimpan di direktori res/raw/ aplikasi Anda):

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

Dalam hal ini, resource "mentah" adalah file yang tidak dicoba diurai oleh sistem dengan cara tertentu. Namun, konten resource ini tidak boleh berupa audio mentah. Konten harus berupa file media yang dienkode dan diformat dengan benar dalam salah satu format yang didukung.

Dan berikut ini cara memutar dari URI yang tersedia secara lokal dalam sistem (yang Anda peroleh melalui Content Resolver, misalnya):

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

Melakukan pemutaran dari URL jarak jauh melalui streaming HTTP akan terlihat seperti ini:

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

Catatan: Jika Anda meneruskan URL untuk melakukan streaming file media online, file tersebut harus dapat didownload secara progresif.

Perhatian: Anda harus menangkap atau meneruskan IllegalArgumentException dan IOException saat menggunakan setDataSource(), karena file yang Anda referensikan mungkin tidak ada.

Persiapan asinkron

Pada prinsipnya, penggunaan MediaPlayer dapat dilakukan dengan mudah. Namun, perlu diingat bahwa beberapa hal lagi diperlukan untuk mengintegrasikannya dengan benar menggunakan aplikasi Android standar. Misalnya, panggilan ke prepare() dapat memerlukan waktu lama untuk dieksekusi karena mungkin memerlukan pengambilan dan decoding data media. Jadi, seperti halnya metode apa pun yang mungkin memerlukan waktu lama untuk dieksekusi, Anda tidak boleh memanggilnya dari UI thread aplikasi Anda. Jika hal tersebut dilakukan, UI akan hang sampai metode kembali, yang merupakan pengalaman pengguna yang sangat buruk dan dapat menyebabkan error ANR (Aplikasi Tidak Merespons). Meskipun Anda mengharapkan resource dimuat dengan cepat, ingat bahwa apa pun yang memerlukan waktu lebih dari sepersepuluh detik untuk merespons di UI akan menyebabkan jeda yang cukup signifikan dan memberikan kesan bahwa aplikasi Anda lambat kepada pengguna.

Untuk menghindari UI thread yang macet, buat thread lain untuk menyiapkan MediaPlayer dan beri tahu thread utama jika sudah selesai. Namun, meskipun Anda dapat menulis sendiri logika threading, pola ini sangat umum saat menggunakan MediaPlayer sehingga framework menyediakan cara yang mudah untuk menyelesaikan tugas ini menggunakan metode prepareAsync(). Metode ini mulai menyiapkan media di latar belakang dan segera ditampilkan. Setelah media selesai disiapkan, metode onPrepared() dari MediaPlayer.OnPreparedListener yang dikonfigurasi melalui setOnPreparedListener() akan dipanggil.

Mengelola status

Aspek lain dari MediaPlayer yang harus Anda ingat adalah berbasis status. Artinya, MediaPlayer memiliki status internal yang harus selalu Anda ketahui saat menulis kode, karena operasi tertentu hanya akan valid saat pemutar dalam status tertentu. Jika Anda menjalankan operasi dalam status yang salah, sistem dapat menampilkan pengecualian atau menyebabkan perilaku lain yang tidak diinginkan.

Dokumentasi di class MediaPlayer menunjukkan diagram status lengkap, yang menjelaskan metode mana yang memindahkan MediaPlayer 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(), membawanya ke status Diinisialisasi. Setelah itu, Anda harus mempersiapkannya menggunakan metode prepare() atau prepareAsync(). Setelah selesai disiapkan, MediaPlayer akan memasuki status Disiapkan, yang berarti Anda dapat memanggil start() agar memutar media. Pada tahap tersebut, seperti yang diilustrasikan dalam diagram, Anda dapat beralih antara status Started, Pause, dan PlaybackCompleted dengan memanggil metode seperti start(), pause(), seekTo(), dan lain-lain. Namun, saat memanggil stop(), perhatikan bahwa Anda tidak dapat memanggil start() lagi sampai Anda menyiapkan MediaPlayer lagi.

Selalu perhatikan diagram status saat menulis kode yang berinteraksi dengan objek MediaPlayer, karena memanggil metodenya dari status yang salah sering kali menyebabkan bug.

Merilis MediaPlayer

MediaPlayer dapat memakai resource sistem yang berharga. Oleh karena itu, Anda harus selalu melakukan tindakan pencegahan tambahan untuk memastikan bahwa Anda tidak mempertahankan instance MediaPlayer lebih lama dari yang diperlukan. Setelah selesai, Anda harus selalu memanggil release() untuk memastikan resource sistem apa pun yang dialokasikan untuknya dirilis dengan benar. Misalnya, jika Anda menggunakan MediaPlayer dan aktivitas menerima panggilan ke onStop(), Anda harus melepaskan MediaPlayer, karena tidak masuk akal untuk mempertahankannya saat aktivitas Anda tidak berinteraksi dengan pengguna (kecuali jika Anda memutar media di latar belakang, yang akan dibahas di bagian berikutnya). Saat aktivitas dilanjutkan atau dimulai ulang, tentu saja Anda perlu 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;

Sebagai contoh, pertimbangkan masalah yang dapat terjadi jika Anda lupa merilis MediaPlayer saat aktivitas dihentikan, tetapi buat yang baru saat aktivitas dimulai lagi. Seperti yang Anda ketahui, saat pengguna mengubah orientasi layar (atau mengubah konfigurasi perangkat dengan cara lain), sistem akan menanganinya dengan memulai ulang aktivitas (secara default), sehingga Anda dapat dengan cepat menggunakan semua resource sistem saat pengguna memutar perangkat bolak-balik antara potret dan lanskap, karena pada setiap perubahan orientasi, Anda akan membuat MediaPlayer baru yang tidak pernah dilepaskan. (Untuk informasi selengkapnya tentang pemulaian ulang waktu proses, lihat Menangani Perubahan Waktu Proses.)

Anda mungkin ingin tahu apa yang terjadi jika ingin terus memutar "media latar belakang" bahkan saat pengguna meninggalkan aktivitas, dengan cara yang sama seperti perilaku aplikasi Musik bawaan. Dalam hal ini, yang Anda butuhkan adalah MediaPlayer yang dikontrol oleh Layanan, seperti yang dibahas di bagian berikutnya

Menggunakan MediaPlayer dalam layanan

Jika ingin media diputar di latar belakang bahkan saat aplikasi tidak ada di layar—yaitu, Anda ingin media terus diputar saat pengguna berinteraksi dengan aplikasi lain—Anda harus memulai Layanan dan mengontrol instance MediaPlayer dari sana. Anda harus menyematkan MediaPlayer di 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 bagian sistem lainnya. Jika aplikasi Anda tidak memenuhi ekspektasi tersebut, pengguna mungkin akan mendapatkan pengalaman yang buruk. Baca Membangun Aplikasi Audio untuk detail selengkapnya.

Bagian ini menjelaskan petunjuk khusus untuk mengelola MediaPlayer jika diterapkan dalam layanan.

Menjalankan secara asinkron

Pertama-tama, seperti Activity, semua tugas di Service dilakukan dalam satu thread secara default—bahkan, jika Anda menjalankan aktivitas dan layanan dari aplikasi yang sama, keduanya menggunakan thread yang sama ("thread utama") secara default. Oleh karena itu, layanan perlu memproses intent yang masuk dengan cepat dan tidak pernah melakukan komputasi yang panjang saat meresponsnya. Jika ada panggilan pekerjaan yang berat atau pemblokiran yang diharapkan, Anda harus melakukan tugas tersebut secara asinkron: baik dari thread lain yang Anda terapkan sendiri, atau menggunakan berbagai fasilitas framework untuk pemrosesan asinkron.

Misalnya, saat menggunakan MediaPlayer dari thread utama, Anda harus memanggil prepareAsync(), bukan prepare(), dan mengimplementasikan 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 sinkron, error biasanya akan diberi sinyal dengan pengecualian atau kode error, tetapi setiap kali menggunakan resource asinkron, Anda harus memastikan bahwa aplikasi diberi tahu tentang error dengan tepat. Dalam kasus 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!
    }
}

Penting untuk diingat bahwa saat terjadi error, MediaPlayer akan berpindah ke status Error (lihat dokumentasi class MediaPlayer untuk mengetahui diagram status lengkap) dan Anda harus meresetnya sebelum dapat menggunakannya lagi.

Menggunakan penguncian layar saat aktif

Saat mendesain aplikasi yang memutar media di latar belakang, perangkat mungkin akan masuk ke mode tidur saat layanan Anda sedang berjalan. Sistem Android mencoba menghemat baterai saat perangkat tidur, sistem akan mencoba menonaktifkan fitur ponsel yang tidak diperlukan, termasuk hardware Wi-Fi dan CPU. Namun, jika layanan Anda memutar atau melakukan streaming musik, Anda ingin mencegah sistem mengganggu pemutaran Anda.

Untuk memastikan layanan terus berjalan dalam kondisi tersebut, Anda harus menggunakan "penguncian layar saat aktif". Penguncian layar saat aktif adalah cara untuk memberi tahu sistem bahwa aplikasi Anda menggunakan beberapa fitur yang seharusnya tetap tersedia meskipun ponsel sedang tidak ada aktivitas.

Pemberitahuan: Anda harus selalu menggunakan penguncian layar saat aktif dan menahannya hanya selama benar-benar diperlukan, karena fitur ini secara signifikan mengurangi masa pakai baterai perangkat.

Untuk memastikan CPU terus berjalan saat MediaPlayer diputar, panggil metode setWakeMode() saat melakukan inisialisasi MediaPlayer. Setelah Anda melakukannya, MediaPlayer akan menahan kunci yang ditentukan saat video diputar, lalu akan melepas kunci 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 menyimpan WifiLock, yang harus diperoleh dan dirilis secara manual. Jadi, saat Anda mulai menyiapkan MediaPlayer dengan URL jarak jauh, Anda harus membuat dan mendapatkan kunci 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 melepaskan penguncian:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Melakukan pembersihan

Seperti yang disebutkan sebelumnya, objek MediaPlayer dapat menggunakan resource sistem dalam jumlah yang signifikan, jadi sebaiknya Anda menyimpannya hanya selama yang Anda perlukan dan memanggil release() setelah selesai. Penting untuk memanggil metode pembersihan ini secara eksplisit daripada mengandalkan pembersihan sampah memori sistem karena mungkin perlu waktu beberapa saat sebelum pembersih sampah memori mengklaim kembali MediaPlayer, karena hanya sensitif terhadap kebutuhan memori dan bukan kekurangan resource terkait media lainnya. Jadi, jika menggunakan layanan, Anda harus selalu mengganti metode onDestroy() untuk memastikan Anda merilis 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();
   }
}

Anda juga harus selalu mencari peluang lain untuk merilis MediaPlayer, selain merilisnya saat dinonaktifkan. Misalnya, jika Anda berharap tidak dapat memutar media dalam waktu lama (misalnya setelah kehilangan fokus audio), Anda harus merilis MediaPlayer yang sudah ada dan membuatnya lagi nanti. Di sisi lain, jika Anda hanya ingin menghentikan pemutaran untuk waktu yang sangat singkat, sebaiknya Anda mempertahankan MediaPlayer untuk menghindari overhead pembuatan dan persiapan lagi.

Manajemen Hak Digital (DRM)

Mulai 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 mengekspos objek ekstraktor, drm, dan kripto yang mendasarinya.

Meskipun MediaPlayer DRM API tidak menyediakan fungsi MediaDrm penuh, API ini mendukung kasus penggunaan yang paling umum. Implementasi 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 implementasi sinkron sederhana.

Untuk mengelola media yang dikontrol DRM, Anda harus menyertakan metode baru tersebut bersama alur panggilan MediaPlayer yang biasa, 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 dengan melakukan inisialisasi objek MediaPlayer dan menetapkan sumbernya menggunakan setDataSource(), seperti biasa. Kemudian, untuk menggunakan DRM, lakukan langkah-langkah berikut:

  1. Jika Anda ingin aplikasi melakukan konfigurasi kustom, tentukan antarmuka OnDrmConfigHelper, dan lampirkan ke pemain menggunakan setOnDrmConfigHelper().
  2. Panggil prepare().
  3. Panggil getDrmInfo(). Jika sumbernya memiliki konten DRM, metode ini akan menampilkan 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 dipanggil secara sinkron dalam thread yang memanggil prepareDrm(). Untuk mengakses properti DRM, panggil getDrmPropertyString() dan setDrmPropertyString(). Jangan melakukan operasi yang panjang.
    • Jika perangkat belum disediakan, prepareDrm() juga akan mengakses server penyediaan untuk menyediakan perangkat. Tindakan ini dapat memerlukan waktu yang bervariasi, bergantung pada konektivitas jaringan.
  3. Untuk mendapatkan array byte permintaan kunci buram untuk 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 kumpulan 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 sinkron, melakukan pemblokiran hingga persiapan selesai. Namun, persiapan DRM yang pertama kali di perangkat baru mungkin juga memerlukan penyediaan, yang ditangani secara internal oleh prepareDrm(), dan mungkin memerlukan waktu beberapa saat untuk diselesaikan karena melibatkan operasi jaringan. Anda dapat menghindari pemblokiran di prepareDrm() dengan menentukan dan menetapkan MediaPlayer.OnDrmPreparedListener.

Jika Anda menetapkan OnDrmPreparedListener, prepareDrm() akan melakukan penyediaan (jika diperlukan) dan persiapan di latar belakang. Saat penyediaan dan persiapan selesai, pemroses akan dipanggil. Anda tidak boleh membuat asumsi apa pun tentang urutan panggilan atau thread tempat pemroses berjalan (kecuali jika pemroses terdaftar dengan thread pengendali). Pemroses dapat dipanggil sebelum atau setelah prepareDrm() ditampilkan.

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 berfungsi bersama 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

Mulai dari Android 8.0 (API level 26), MediaPlayer juga dapat mendekripsi Common Encryption Scheme (CENC) dan media terenkripsi tingkat sampel HLS (METHOD=CONTOH-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 pengguna pada perangkat. 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 {
    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...

Pelajari lebih lanjut

Halaman ini membahas topik yang berkaitan dengan perekaman, penyimpanan, dan pemutaran kembali audio dan video.