Sesi media menyediakan cara universal untuk berinteraksi dengan pemutar
audio atau video. Di Media3, pemutar default adalah class ExoPlayer
, yang mengimplementasikan
antarmuka Player
. Menghubungkan sesi media ke pemutar memungkinkan aplikasi
mengumumkan pemutaran media secara eksternal dan menerima perintah pemutaran dari
sumber eksternal.
Perintah dapat berasal dari tombol fisik seperti tombol putar di headset atau remote control TV. Perintah ini juga dapat berasal dari aplikasi klien yang memiliki pengontrol media, seperti memberikan perintah "jeda" ke Asisten Google. Sesi media mendelegasikan perintah ini ke pemutar aplikasi media.
Kapan harus memilih sesi media
Saat menerapkan MediaSession
, Anda mengizinkan pengguna mengontrol pemutaran:
- Melalui headphone mereka. Sering kali ada tombol atau interaksi sentuh yang dapat dilakukan pengguna di headphone untuk memutar atau menjeda media atau membuka trek berikutnya atau sebelumnya.
- Dengan berbicara kepada Asisten Google. Pola umum adalah mengucapkan "Ok Google, jeda" untuk menjeda media apa pun yang sedang diputar di perangkat.
- Melalui smartwatch Wear OS. Hal ini memungkinkan akses yang lebih mudah ke kontrol pemutaran yang paling umum saat memutar di ponsel.
- Melalui Kontrol media. Carousel ini menampilkan kontrol untuk setiap sesi media yang berjalan.
- Di TV. Memungkinkan tindakan dengan tombol pemutaran fisik, kontrol pemutaran platform, dan pengelolaan daya (misalnya, jika TV, soundbar, atau penerima A/V dinonaktifkan atau input diubah, pemutaran akan berhenti di aplikasi).
- Dan proses eksternal lainnya yang perlu memengaruhi pemutaran.
Hal ini sangat cocok untuk banyak kasus penggunaan. Secara khusus, Anda harus mempertimbangkan
penggunaan MediaSession
jika:
- Anda melakukan streaming konten video panjang, seperti film atau TV live.
- Anda melakukan streaming konten audio berdurasi panjang, seperti podcast atau playlist musik.
- Anda sedang mem-build aplikasi TV.
Namun, tidak semua kasus penggunaan cocok dengan MediaSession
. Anda mungkin ingin
hanya menggunakan Player
dalam kasus berikut:
- Anda menampilkan konten berdurasi singkat, yang memerlukan engagement dan interaksi pengguna yang penting.
- Tidak ada satu video aktif, seperti pengguna men-scroll daftar dan beberapa video ditampilkan di layar secara bersamaan.
- Anda memutar video pengantar atau penjelasan satu kali, yang Anda harapkan akan ditonton secara aktif oleh pengguna.
- Konten Anda sensitif terhadap privasi dan Anda tidak ingin proses eksternal mengakses metadata media (misalnya mode Samaran di browser)
Jika kasus penggunaan Anda tidak sesuai dengan salah satu yang tercantum di atas, pertimbangkan apakah Anda
memungkinkan aplikasi melanjutkan pemutaran saat pengguna tidak berinteraksi secara aktif
dengan konten. Jika jawabannya ya, sebaiknya pilih
MediaSession
. Jika jawabannya tidak, sebaiknya gunakan Player
sebagai gantinya.
Membuat sesi media
Sesi media berdampingan dengan pemutar yang dikelolanya. Anda dapat membuat
sesi media dengan objek Context
dan Player
. Anda harus membuat dan
melakukan inisialisasi sesi media saat diperlukan, seperti metode siklus proses onStart()
atau
onResume()
dari Activity
atau Fragment
, atau metode onCreate()
dari Service
yang memiliki sesi media dan pemutar terkaitnya.
Untuk membuat sesi media, lakukan inisialisasi Player
dan berikan ke
MediaSession.Builder
seperti ini:
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();
Penanganan status otomatis
Library Media3 otomatis memperbarui sesi media menggunakan status pemutar. Dengan demikian, Anda tidak perlu menangani pemetaan dari pemain ke sesi secara manual.
Ini adalah perubahan dari pendekatan lama yang mengharuskan Anda membuat dan mengelola
PlaybackStateCompat
secara terpisah dari pemutar itu sendiri, misalnya untuk
menunjukkan error.
ID sesi unik
Secara default, MediaSession.Builder
membuat sesi dengan string kosong sebagai ID sesi. Hal ini cukup jika aplikasi hanya ingin membuat satu
instance sesi, yang merupakan kasus paling umum.
Jika aplikasi ingin mengelola beberapa instance sesi secara bersamaan, aplikasi
harus memastikan bahwa ID sesi setiap sesi bersifat unik. ID sesi dapat ditetapkan saat mem-build sesi dengan MediaSession.Builder.setId(String id)
.
Jika Anda melihat IllegalStateException
yang membuat aplikasi error dengan pesan error
IllegalStateException: Session ID must be unique. ID=
, kemungkinan
sesi telah dibuat secara tidak terduga sebelum instance yang dibuat sebelumnya
dengan ID yang sama telah dirilis. Untuk menghindari kebocoran sesi oleh
error pemrograman, kasus tersebut akan terdeteksi dan diberi tahu dengan menampilkan
pengecualian.
Memberikan kontrol kepada klien lain
Sesi media adalah kunci untuk mengontrol pemutaran. Dengan begitu, Anda dapat merutekan perintah dari sumber eksternal ke pemutar yang melakukan tugas memutar media. Sumber ini dapat berupa tombol fisik seperti tombol putar di headset atau remote control TV, atau perintah tidak langsung seperti memberi perintah "jeda" ke Asisten Google. Demikian pula, Anda dapat memberikan akses ke sistem Android untuk memfasilitasi kontrol notifikasi dan layar kunci, atau ke smartwatch Wear OS sehingga Anda dapat mengontrol pemutaran dari tampilan jam. Klien eksternal dapat menggunakan pengontrol media untuk mengeluarkan perintah pemutaran ke aplikasi media Anda. Perintah ini diterima oleh sesi media Anda, yang pada akhirnya mendelegasikan perintah ke pemutar media.
Saat pengontrol akan terhubung ke sesi media Anda, metode
onConnect()
akan dipanggil. Anda dapat menggunakan ControllerInfo
yang disediakan
untuk memutuskan apakah akan menerima
atau menolak
permintaan. Lihat contoh penerimaan permintaan koneksi di bagian Mendeklarasikan
perintah yang tersedia.
Setelah terhubung, pengontrol dapat mengirim perintah pemutaran ke sesi. Kemudian,
sesi mendelegasikan perintah tersebut ke pemutar. Perintah pemutaran dan playlist
yang ditentukan di antarmuka Player
akan 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 mengubah
cara merespons setiap permintaan berdasarkan per pengontrol.
Mengubah playlist
Sesi media dapat langsung mengubah playlist pemutarnya seperti yang dijelaskan dalam
panduan ExoPlayer untuk playlist.
Pengontrol juga dapat mengubah playlist jika
COMMAND_SET_MEDIA_ITEM
atau COMMAND_CHANGE_MEDIA_ITEMS
tersedia untuk pengontrol.
Saat menambahkan item baru ke playlist, pemutar biasanya memerlukan instance MediaItem
dengan
URI yang ditentukan
agar dapat diputar. Secara default, item yang baru ditambahkan akan otomatis diteruskan
ke metode pemutar seperti player.addMediaItem
jika memiliki URI yang ditentukan.
Jika ingin menyesuaikan instance MediaItem
yang ditambahkan ke pemutar, Anda dapat
mengganti
onAddMediaItems()
.
Langkah ini diperlukan jika Anda ingin mendukung pengontrol yang meminta media
tanpa URI yang ditentukan. Sebagai gantinya, MediaItem
biasanya memiliki
satu atau beberapa kolom berikut yang ditetapkan untuk menjelaskan media yang diminta:
MediaItem.id
: ID generik yang mengidentifikasi media.MediaItem.RequestMetadata.mediaUri
: URI permintaan yang dapat menggunakan skema kustom dan tidak harus dapat diputar langsung oleh pemutar.MediaItem.RequestMetadata.searchQuery
: Kueri penelusuran tekstual, misalnya dari Asisten Google.MediaItem.MediaMetadata
: Metadata terstruktur seperti 'judul' atau 'artis'.
Untuk opsi penyesuaian lainnya bagi playlist yang benar-benar baru, Anda juga dapat mengganti
onSetMediaItems()
yang memungkinkan Anda menentukan item dan posisi awal dalam playlist. Misalnya,
Anda dapat memperluas satu item yang diminta ke seluruh playlist dan menginstruksikan
pemutar untuk memulai dari indeks item yang awalnya diminta. Contoh implementasi onSetMediaItems()
dengan fitur ini dapat ditemukan di aplikasi demo sesi.
Mengelola tata letak kustom dan perintah kustom
Bagian berikut menjelaskan cara mengiklankan tata letak kustom tombol perintah kustom ke aplikasi klien dan memberi otorisasi pengontrol untuk mengirim perintah kustom.
Menentukan tata letak kustom sesi
Untuk menunjukkan kepada aplikasi klien kontrol pemutaran yang ingin Anda tampilkan kepada
pengguna, tetapkan tata letak sesi kustom
saat mem-build MediaSession
dalam metode onCreate()
layanan Anda.
Kotlin
override fun onCreate() { super.onCreate() val likeButton = CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build() val favoriteButton = CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(SessionCommand(SAVE_TO_FAVORITES, Bundle())) .build() session = MediaSession.Builder(this, player) .setCallback(CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build() }
Java
@Override public void onCreate() { super.onCreate(); CommandButton likeButton = new CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build(); CommandButton favoriteButton = new CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); Player player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player) .setCallback(new CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build(); }
Menyatakan pemutar dan perintah kustom yang tersedia
Aplikasi media dapat menentukan perintah kustom yang misalnya dapat digunakan dalam
tata letak kustom. Misalnya, Anda mungkin ingin menerapkan tombol yang memungkinkan
pengguna menyimpan item media ke daftar item favorit. MediaController
mengirimkan perintah kustom dan MediaSession.Callback
menerimanya.
Anda dapat menentukan perintah sesi kustom yang tersedia untuk
MediaController
saat terhubung ke sesi media Anda. Anda dapat melakukannya dengan
mengganti MediaSession.Callback.onConnect()
. Konfigurasikan dan tampilkan
kumpulan perintah yang tersedia saat menerima permintaan koneksi dari
MediaController
dalam metode callback onConnect
:
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
Untuk menerima permintaan perintah kustom dari MediaController
, ganti
metode onCustomCommand()
di Callback
.
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture( SessionResult(SessionResult.RESULT_SUCCESS) ) } ... } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args ) { if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture( new SessionResult(SessionResult.RESULT_SUCCESS) ); } ... } }
Anda dapat melacak pengontrol media mana yang membuat permintaan menggunakan
properti packageName
dari objek MediaSession.ControllerInfo
yang
diteruskan ke metode Callback
. Dengan demikian, Anda dapat menyesuaikan perilaku
aplikasi sebagai respons terhadap perintah tertentu jika berasal dari sistem,
aplikasi Anda sendiri, atau aplikasi klien lainnya.
Memperbarui tata letak kustom setelah interaksi pengguna
Setelah menangani perintah kustom atau interaksi lainnya dengan pemutar, Anda
mungkin ingin memperbarui tata letak yang ditampilkan di UI pengontrol. Contoh umum
adalah tombol tombol yang mengubah ikonnya setelah memicu tindakan yang terkait
dengan tombol ini. Untuk memperbarui tata letak, Anda dapat menggunakan
MediaSession.setCustomLayout
:
Kotlin
val removeFromFavoritesButton = CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(SessionCommand(REMOVE_FROM_FAVORITES, Bundle())) .build() mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
CommandButton removeFromFavoritesButton = new CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(new SessionCommand(REMOVE_FROM_FAVORITES, new Bundle())) .build(); mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton));
Menyesuaikan perilaku perintah pemutaran
Untuk menyesuaikan perilaku perintah yang ditentukan di antarmuka Player
, seperti
play()
atau seekToNext()
, gabungkan Player
dalam ForwardingPlayer
.
Kotlin
val player = ExoPlayer.Builder(context).build() val forwardingPlayer = object : ForwardingPlayer(player) { override fun play() { // Add custom logic super.play() } override fun setPlayWhenReady(playWhenReady: Boolean) { // Add custom logic super.setPlayWhenReady(playWhenReady) } } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); ForwardingPlayer forwardingPlayer = new ForwardingPlayer(player) { @Override public void play() { // Add custom logic super.play(); } @Override public void setPlayWhenReady(boolean playWhenReady) { // Add custom logic super.setPlayWhenReady(playWhenReady); } }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
Untuk informasi selengkapnya tentang ForwardingPlayer
, lihat panduan ExoPlayer tentang
Penyesuaian.
Mengidentifikasi pengontrol yang meminta perintah pemain
Saat panggilan ke metode Player
berasal dari MediaController
, Anda dapat
mengidentifikasi sumber asal dengan MediaSession.controllerForCurrentRequest
dan memperoleh ControllerInfo
untuk permintaan saat ini:
Kotlin
class CallerAwareForwardingPlayer(player: Player) : ForwardingPlayer(player) { override fun seekToNext() { Log.d( "caller", "seekToNext called from package ${session.controllerForCurrentRequest?.packageName}" ) super.seekToNext() } }
Java
public class CallerAwareForwardingPlayer extends ForwardingPlayer { public CallerAwareForwardingPlayer(Player player) { super(player); } @Override public void seekToNext() { Log.d( "caller", "seekToNext called from package: " + session.getControllerForCurrentRequest().getPackageName()); super.seekToNext(); } }
Merespons tombol media
Tombol media adalah tombol hardware yang ada di perangkat Android dan perangkat periferal
lainnya, seperti tombol putar/jeda di headset Bluetooth. Media3 menangani
peristiwa tombol media untuk Anda saat tiba di sesi dan memanggil
metode Player
yang sesuai di pemutar sesi.
Aplikasi dapat mengganti perilaku default dengan mengganti
MediaSession.Callback.onMediaButtonEvent(Intent)
. Dalam hal ini, aplikasi
dapat/perlu menangani semua spesifikasi API sendiri.
Penanganan dan pelaporan error
Ada dua jenis error yang dikeluarkan dan dilaporkan sesi ke pengontrol. Error fatal melaporkan kegagalan pemutaran teknis pemutar sesi yang mengganggu pemutaran. Error fatal dilaporkan ke pengontrol secara otomatis saat terjadi. Error tidak fatal adalah error non-teknis atau kebijakan yang tidak mengganggu pemutaran dan dikirim ke pengontrol oleh aplikasi secara manual.
Error pemutaran fatal
Error pemutaran fatal dilaporkan ke sesi oleh pemutar, lalu
dilaporkan ke pengontrol untuk memanggil melalui
Player.Listener.onPlayerError(PlaybackException)
dan
Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
Dalam kasus seperti itu, status pemutaran akan ditransisikan ke STATE_IDLE
dan
MediaController.getPlaybackError()
menampilkan PlaybackException
yang menyebabkan
transisi. Pengontrol dapat memeriksa PlayerException.errorCode
untuk mendapatkan
informasi tentang alasan error.
Untuk interoperabilitas, error fatal direplikasi ke PlaybackStateCompat
sesi platform dengan mentransisikan statusnya ke STATE_ERROR
dan menetapkan
kode dan pesan error sesuai dengan PlaybackException
.
Penyesuaian error fatal
Untuk memberikan informasi yang dilokalkan dan bermakna kepada pengguna, kode error,
pesan error, dan tambahan error dari error pemutaran fatal dapat disesuaikan dengan
menggunakan ForwardingPlayer
saat mem-build sesi:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
Pemutar penerusan mendaftarkan Player.Listener
ke pemutar sebenarnya
dan mencegat callback yang melaporkan error. PlaybackException
yang disesuaikan kemudian didelegasikan ke pemroses yang
terdaftar di pemutar penerusan. Agar hal ini berfungsi, pemutar penerusan
akan mengganti Player.addListener
dan Player.removeListener
agar memiliki akses ke
pemroses yang digunakan untuk mengirim kode error, pesan, atau tambahan yang disesuaikan:
Kotlin
class ErrorForwardingPlayer(private val context: Context, player: Player) : ForwardingPlayer(player) { private val listeners: MutableList<Player.Listener> = mutableListOf() private var customizedPlaybackException: PlaybackException? = null init { player.addListener(ErrorCustomizationListener()) } override fun addListener(listener: Player.Listener) { listeners.add(listener) } override fun removeListener(listener: Player.Listener) { listeners.remove(listener) } override fun getPlayerError(): PlaybackException? { return customizedPlaybackException } private inner class ErrorCustomizationListener : Player.Listener { override fun onPlayerErrorChanged(error: PlaybackException?) { customizedPlaybackException = error?.let { customizePlaybackException(it) } listeners.forEach { it.onPlayerErrorChanged(customizedPlaybackException) } } override fun onPlayerError(error: PlaybackException) { listeners.forEach { it.onPlayerError(customizedPlaybackException!!) } } private fun customizePlaybackException( error: PlaybackException, ): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } // Apps can customize further error messages by adding more branches. else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } override fun onEvents(player: Player, events: Player.Events) { listeners.forEach { it.onEvents(player, events) } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Java
private static class ErrorForwardingPlayer extends ForwardingPlayer { private final Context context; private List<Player.Listener> listeners; @Nullable private PlaybackException customizedPlaybackException; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; listeners = new ArrayList<>(); player.addListener(new ErrorCustomizationListener()); } @Override public void addListener(Player.Listener listener) { listeners.add(listener); } @Override public void removeListener(Player.Listener listener) { listeners.remove(listener); } @Nullable @Override public PlaybackException getPlayerError() { return customizedPlaybackException; } private class ErrorCustomizationListener implements Listener { @Override public void onPlayerErrorChanged(@Nullable PlaybackException error) { customizedPlaybackException = error != null ? customizePlaybackException(error, context) : null; for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerErrorChanged(customizedPlaybackException); } } @Override public void onPlayerError(PlaybackException error) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerError(checkNotNull(customizedPlaybackException)); } } private PlaybackException customizePlaybackException( PlaybackException error, Context context) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; // Apps can customize further error messages by adding more case statements. default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } @Override public void onEvents(Player player, Events events) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onEvents(player, events); } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Error non-fatal
Error non-fatal yang tidak berasal dari pengecualian teknis dapat dikirim oleh aplikasi ke semua atau ke pengontrol tertentu:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Interoperability: Sending a nonfatal error to the media notification controller to set the // error code and error message in the playback state of the platform media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Interoperability: Sending a nonfatal error to the media notification controller to set the // error code and error message in the playback state of the platform media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
Error non-fatal yang dikirim ke pengontrol notifikasi media direplikasi ke
PlaybackStateCompat
sesi platform. Dengan demikian, hanya kode error dan
pesan error yang ditetapkan ke PlaybackStateCompat
, sedangkan
PlaybackStateCompat.state
tidak diubah menjadi STATE_ERROR
.
Menerima error non-fatal
MediaController
menerima error non-fatal dengan menerapkan
MediaController.Listener.onError
:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener(object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } }) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });