Membuat aplikasi media player dasar menggunakan Media3 ExoPlayer

Jetpack Media3 menentukan antarmuka Player yang menguraikan fungsi dasar untuk pemutaran file video dan audio. ExoPlayer adalah implementasi default dari antarmuka ini di Media3. Kami merekomendasikan penggunaan ExoPlayer, karena menyediakan fitur komprehensif yang mencakup sebagian besar kasus penggunaan pemutaran dan dapat disesuaikan untuk menangani kasus penggunaan tambahan yang mungkin Anda miliki. ExoPlayer juga mengabstraksi fragmentasi perangkat dan OS sehingga kode Anda berfungsi secara konsisten di seluruh ekosistem Android. ExoPlayer mencakup:

Halaman ini memandu Anda melalui beberapa langkah penting dalam membuat dan untuk detail lebih lanjut, Anda dapat membuka panduan lengkap kami tentang Media3 ExoPlayer.

Memulai

Untuk memulai, tambahkan dependensi pada ExoPlayer, UI, dan modul Umum Jetpack Media3:

implementation "androidx.media3:media3-exoplayer:1.4.1"
implementation "androidx.media3:media3-ui:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"

Tergantung pada kasus penggunaan Anda, Anda mungkin juga memerlukan modul tambahan dari Media3, seperti exoplayer-dash untuk memutar streaming dalam format DASH.

Pastikan untuk mengganti 1.4.1 dengan versi versi pilihan Anda library. Anda dapat membaca catatan rilis untuk melihat versi terbaru.

Membuat pemutar media

Dengan Media3, Anda dapat menggunakan implementasi Player yang disertakan antarmuka, ExoPlayer, atau Anda dapat membuat implementasi kustom sendiri.

Membuat ExoPlayer

Cara paling sederhana untuk membuat instance ExoPlayer adalah sebagai berikut:

Kotlin

val player = ExoPlayer.Builder(context).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();

Anda dapat membuat pemutar media dalam metode siklus proses onCreate() dari Activity, Fragment, atau Service tempatnya berada.

Builder menyertakan serangkaian opsi penyesuaian yang mungkin Anda minati, seperti:

Media3 menyediakan komponen UI PlayerView yang dapat Anda sertakan dalam antarmuka file tata letak. Komponen ini mengenkapsulasi PlayerControlView untuk pemutaran kontrol, SubtitleView untuk menampilkan subtitel, dan Surface untuk rendering video Anda.

Menyiapkan pemain

Tambahkan item media ke playlist untuk pemutaran dengan metode seperti setMediaItem() dan addMediaItem(). Selanjutnya, panggil prepare() untuk mulai memuat media dan mendapatkan sumber daya yang diperlukan.

Anda tidak boleh melakukan langkah-langkah ini sebelum aplikasi berada di latar depan. Jika pemain berada dalam Activity atau Fragment, ini artinya menyiapkan pemain di Metode siklus proses onStart() pada API level 24 dan yang lebih tinggi atau onResume() siklus proses di API level 23 dan yang lebih lama. Untuk pemain yang berada di Service, Anda dapat mempersiapkannya di onCreate().

Mengontrol pemutar

Setelah pemutar siap, Anda dapat mengontrol pemutaran dengan memanggil metode pada pemutar, seperti:

Komponen UI seperti PlayerView atau PlayerControlView akan diupdate sebagaimana mestinya saat terikat dengan pemain.

Melepaskan pemutar

Pemutaran dapat memerlukan resource yang persediaannya terbatas, seperti video Decoder, sehingga penting untuk memanggil release() pada pemutar untuk mengosongkan sumber daya saat pemutar tidak lagi dibutuhkan.

Jika pemutar Anda berada di Activity atau Fragment, lepaskan pemutar di Metode siklus proses onStop() pada API level 24 dan yang lebih tinggi atau onPause() pada API level 23 dan yang lebih rendah. Untuk pemain yang berada di Service, Anda dapat merilisnya dalam onDestroy().

Mengelola pemutaran dengan sesi media

Di Android, sesi media menyediakan cara terstandardisasi untuk berinteraksi dengan media pemain lintas batas proses. Menghubungkan sesi media ke pemutar Anda memungkinkan Anda mengiklankan pemutaran media secara eksternal dan menerima pemutaran perintah dari sumber eksternal, misalnya untuk mengintegrasikan kontrol media sistem di perangkat seluler dan perangkat seluler perangkat layar.

Untuk menggunakan sesi media, tambahkan dependensi pada modul Sesi Media3:

implementation "androidx.media3:media3-session:1.4.1"

Membuat sesi media

Anda dapat membuat MediaSession setelah melakukan inisialisasi pemutar seperti berikut:

Kotlin

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

Media3 otomatis menyinkronkan status Player dengan status MediaSession. Ini berfungsi dengan implementasi Player apa pun, termasuk ExoPlayer, CastPlayer, atau implementasi kustom.

Memberikan kontrol ke klien lain

Aplikasi klien dapat mengimplementasikan pengontrol media untuk mengontrol pemutaran sesi media Anda. Untuk menerima permintaan ini, setel callback saat dalam membangun MediaSession.

Saat pengontrol akan terhubung ke sesi media Anda, onConnect() dipanggil. Anda dapat menggunakan ControllerInfo yang disediakan untuk memutuskan apakah akan menerima atau tolak terhadap permintaan. Lihat contohnya di aplikasi demo Sesi Media3.

Setelah terhubung, pengontrol dapat mengirimkan perintah pemutaran ke sesi. Tujuan lalu mendelegasikan perintah tersebut ke pemain. Pemutaran dan playlist perintah yang ditentukan dalam antarmuka Player secara otomatis ditangani oleh sesi.

Metode callback lainnya memungkinkan Anda menangani, misalnya, permintaan untuk perintah pemutaran kustom dan mengubah playlist. Callback ini juga menyertakan objek ControllerInfo sehingga Anda dapat menentukan kontrol akses berdasarkan permintaan.

Memutar media di latar belakang

Untuk terus memutar media saat aplikasi tidak di latar depan, misalnya untuk memutar musik, buku audio, atau podcast meskipun pengguna tidak memiliki aplikasi Anda terbuka, Player dan MediaSession Anda harus dienkapsulasi dalam layanan latar depan. Media3 menyediakan MediaSessionService untuk tujuan ini.

Mengimplementasikan MediaSessionService

Buat class yang memperluas MediaSessionService dan buat instance MediaSession dalam metode siklus proses onCreate().

Kotlin

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    // Create your Player and MediaSession in the onCreate lifecycle event
    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
    }

    // Remember to release the player and media session in onDestroy
    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

Java

public class PlaybackService extends MediaSessionService {
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player).build();
    }

    @Override
    public void onDestroy() {
        mediaSession.getPlayer().release();
        mediaSession.release();
        mediaSession = null;
        super.onDestroy();
    }
}

Dalam manifes, class Service dengan intent MediaSessionService memfilter dan meminta izin FOREGROUND_SERVICE untuk menjalankan latar depan layanan:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Terakhir, di class yang Anda buat, ganti metode onGetSession() untuk mengontrol akses klien ke sesi media Anda. Tampilkan MediaSession untuk menyetujui permintaan koneksi, atau tampilkan null untuk menolak permintaan.

Kotlin

// This example always accepts the connection request
override fun onGetSession(
    controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession

Java

@Override
public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
  // This example always accepts the connection request
  return mediaSession;
}

Menghubungkan ke UI Anda

Setelah sesi media Anda berada di Service yang terpisah dari Activity atau Fragment tempat UI pemutar Anda berada, Anda dapat menggunakan MediaController untuk menautkan mereka bersama-sama. Di metode onStart() Activity atau Fragment dengan UI, buat SessionToken untuk MediaSession Anda, lalu gunakan SessionToken untuk membangun MediaController. Membuat MediaController terjadi secara asinkron.

Kotlin

override fun onStart() {
  val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
  val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
  controllerFuture.addListener(
    {
        // Call controllerFuture.get() to retrieve the MediaController.
        // MediaController implements the Player interface, so it can be
        // attached to the PlayerView UI component.
        playerView.setPlayer(controllerFuture.get())
      },
    MoreExecutors.directExecutor()
  )
}

Java

@Override
public void onStart() {
  SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, PlaybackService.class));
  ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();
  controllerFuture.addListener(() -> {
    // Call controllerFuture.get() to retrieve the MediaController.
    // MediaController implements the Player interface, so it can be
    // attached to the PlayerView UI component.
    playerView.setPlayer(controllerFuture.get());
  }, MoreExecutors.directExecutor())
}

MediaController mengimplementasikan antarmuka Player, sehingga Anda dapat menggunakan metode seperti play() dan pause() untuk mengontrol pemutaran. Serupa dengan lainnya komponen, ingatlah untuk merilis MediaController jika sudah tidak diperlukan, seperti metode siklus proses onStop() dari Activity, dengan memanggil MediaController.releaseFuture()

Memublikasikan notifikasi

Layanan latar depan diperlukan untuk memublikasikan notifikasi saat aktif. J MediaSessionService akan otomatis membuat Notifikasi MediaStyle untuk dalam bentuk MediaNotification. Untuk memberikan notifikasi kustom, buat MediaNotification.Provider dengan DefaultMediaNotificationProvider.Builder atau dengan membuat implementasi khusus dari antarmuka penyedia. Tambahkan penyedia layanan ke MediaSession Anda dengan setMediaNotificationProvider.

Mengiklankan koleksi konten Anda

MediaLibraryService di-build di MediaSessionService dengan mengizinkan klien aplikasi untuk menjelajahi konten media yang disediakan oleh aplikasi Anda. Aplikasi klien menerapkan MediaBrowser untuk berinteraksi dengan MediaLibraryService Anda.

Mengimplementasikan MediaLibraryService mirip dengan menerapkan MediaSessionService, kecuali bahwa dalam onGetSession() Anda harus menampilkan MediaLibrarySession, bukan MediaSession. Dibandingkan dengan MediaSession.Callback, MediaLibrarySession.Callback mencakup metode yang memungkinkan klien browser untuk membuka konten yang ditawarkan oleh layanan perpustakaan.

Serupa dengan MediaSessionService, deklarasikan MediaLibraryService di manifes dan meminta izin FOREGROUND_SERVICE untuk menjalankan latar depan layanan:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Contoh di atas menyertakan filter intent untuk MediaLibraryService dan, untuk kompatibilitas mundur, MediaBrowserService lama. Tujuan filter intent tambahan memungkinkan aplikasi klien menggunakan MediaBrowserCompat API untuk mengenali Service Anda.

MediaLibrarySession memungkinkan Anda menayangkan library konten di hierarki dengan satu root MediaItem. Setiap MediaItem dalam hierarki dapat memiliki berapa pun jumlah node turunan MediaItem. Anda dapat menyalurkan {i>root <i}yang berbeda, atau pohon yang berbeda, berdasarkan permintaan aplikasi klien. Misalnya, pohon yang Anda kembali ke klien yang mencari daftar item media yang direkomendasikan mungkin hanya berisi root MediaItem dan satu level node MediaItem turunan, Sedangkan pohon yang Anda kembalikan ke aplikasi klien yang berbeda bisa mewakili koleksi konten yang lengkap.

Membuat MediaLibrarySession

MediaLibrarySession memperluas API MediaSession untuk menambahkan API penjelajahan konten. Dibandingkan dengan Callback MediaSession, callback MediaLibrarySession menambahkan metode seperti:

Metode callback yang relevan akan menyertakan LibraryParams objek dengan sinyal tambahan tentang jenis hierarki konten yang diterima oleh aplikasi klien yang Anda minati.