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. Show
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-dasarClass 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 manifesSebelum mulai mengembangkan aplikasi menggunakan MediaPlayer, pastikan manifes Anda memiliki deklarasi yang sesuai untuk mengizinkan penggunaan fitur terkait.
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:
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):
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):
Melakukan pemutaran dari URL jarak jauh melalui streaming HTTP akan terlihat seperti ini:
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 asinkronPenggunaan 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 statusAspek 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 MediaPlayerMediaPlayer 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:
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 layananJika 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 asinkronSama 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:
Menangani error asinkronPada 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:
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 aktifKetika 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:
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:
Saat menjeda atau menghentikan media, atau saat tidak lagi memerlukan jaringan, Anda harus merilis penguncian tersebut:
Melakukan pembersihanSeperti 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:
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:
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:
Mulailah seperti biasa dengan menginisialisasi objek MediaPlayer dan menentukan sumbernya menggunakan setDataSource(). Kemudian, untuk menggunakan DRM, lakukan langkah-langkah berikut: Jika MediaPlayer.DrmInfo ada:
Menjalankan prepareDrm() secara asinkronSecara 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 asinkronAnda 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:
Menangani media yang dienkripsiDimulai 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 ContentResolverFitur 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:
Untuk menggunakannya dengan MediaPlayer, Anda dapat melakukan hal berikut:
Kode contohContoh BasicMediaDecoder dan DeviceOwner menunjukkan penggunaan API yang dibahas di halaman ini. Pelajari selengkapnyaHalaman ini membahas topik terkait perekaman, penyimpanan, dan pemutaran audio dan video.
|