Sesi media memberikan cara universal untuk berinteraksi dengan audio atau video
web. Di Media3, pemutar default adalah class ExoPlayer
, yang mengimplementasikan
antarmuka Player
. Menghubungkan sesi media ke pemutar memungkinkan aplikasi
untuk mengiklankan pemutaran media secara eksternal dan untuk menerima perintah pemutaran dari
sumber eksternal.
Perintah dapat berasal dari tombol fisik seperti tombol putar pada headset atau remote control TV. Sumber data tersebut mungkin juga berasal dari aplikasi klien yang memiliki pengontrol media, seperti memerintahkan "jeda" ke Asisten Google. Media mendelegasikan perintah ini ke pemutar aplikasi media.
Kapan harus memilih sesi media
Saat mengimplementasikan MediaSession
, Anda mengizinkan pengguna mengontrol pemutaran:
- Melalui headphone mereka. Sering kali ada tombol atau interaksi sentuh yang yang dapat dijalankan di headphone untuk memutar, menjeda media, atau membuka atau lagu sebelumnya.
- Dengan berbicara ke Asisten Google. Pola yang 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 yang paling kontrol pemutaran yang umum saat memutar media di ponsel mereka.
- Melalui Kontrol media. Carousel ini menampilkan kontrol untuk setiap sesi media yang berjalan.
- Di TV. Memungkinkan tindakan dengan tombol pemutaran fisik, pemutaran platform kontrol, dan pengelolaan daya (misalnya, jika TV, soundbar, atau penerima A/V akan nonaktif atau input dialihkan, pemutaran akan berhenti di aplikasi).
- Serta proses eksternal lainnya yang perlu memengaruhi pemutaran.
Ini bagus untuk banyak kasus penggunaan. Secara khusus, Anda harus mempertimbangkan
menggunakan MediaSession
saat:
- Anda melakukan streaming konten video panjang, seperti film atau TV live.
- Anda melakukan streaming konten audio berdurasi panjang, seperti podcast atau musik playlist.
- Anda sedang membuat aplikasi TV.
Namun, tidak semua kasus penggunaan cocok dengan MediaSession
. Anda mungkin ingin
hanya gunakan Player
dalam kasus berikut:
- Anda menampilkan konten video pendek, tempat interaksi dan engagement pengguna sangatlah penting.
- Tidak ada satu video pun yang aktif, seperti pengguna sedang men-scroll daftar dan beberapa video ditampilkan di layar secara bersamaan.
- Anda memutar video pengantar atau penjelasan satu kali, yang Anda harapkan akan terus ditonton pengguna Anda.
- Konten Anda sensitif 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
tidak masalah jika aplikasi melanjutkan pemutaran saat pengguna tidak berinteraksi secara aktif
dengan kontennya. Jika jawabannya ya, Anda
mungkin ingin memilih
MediaSession
. Jika jawabannya tidak, Anda mungkin ingin menggunakan Player
sebagai gantinya.
Membuat sesi media
Sesi media berdampingan dengan pemutar yang dikelolanya. Anda dapat membangun
sesi media dengan objek Context
dan Player
. Anda harus membuat dan
melakukan inisialisasi sesi media saat diperlukan, seperti onStart()
atau
Metode siklus proses onResume()
dari Activity
atau Fragment
, atau onCreate()
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 secara otomatis memperbarui sesi media menggunakan status pemutar. Dengan demikian, Anda tidak perlu menangani pemetaan secara manual dari pemain ke sesi panggilan.
Hal ini merupakan jeda dari pendekatan lama, yang mengharuskan Anda membuat dan mengelola project
PlaybackStateCompat
secara terpisah dari pemutar itu sendiri, misalnya untuk
menunjukkan {i>error<i}.
ID sesi unik
Secara default, MediaSession.Builder
membuat sesi dengan string kosong sebagai
ID sesi. Tindakan ini sudah cukup jika aplikasi hanya bermaksud membuat satu
instance sesi, yang merupakan kasus paling umum.
Jika sebuah aplikasi ingin mengelola beberapa instance sesi secara bersamaan,
harus memastikan bahwa ID sesi
dari setiap sesi adalah unik. ID sesi dapat
ditetapkan saat membuat sesi dengan MediaSession.Builder.setId(String id)
.
Jika Anda melihat IllegalStateException
membuat aplikasi Anda error dan mengalami error
kirim pesan IllegalStateException: Session ID must be unique. ID=
maka
kemungkinan bahwa sesi telah dibuat secara tidak terduga sebelum sesi dibuat
instance dengan ID yang sama telah dirilis. Untuk menghindari sesi
dibocorkan oleh
{i>error <i}pemrograman, kasus tersebut terdeteksi dan
diberi tahu dengan melemparkan
pengecualian.
Memberikan kontrol ke klien lain
Sesi media adalah kunci untuk mengontrol pemutaran. Ini memungkinkan Anda untuk merutekan perintah dari sumber eksternal ke pemutar yang bertugas memutar lainnya. Sumber ini dapat berupa tombol fisik seperti tombol putar di headset atau remote control TV, atau perintah tidak langsung seperti memerintahkan "jeda" ke Asisten Google. Demikian juga, Anda mungkin ingin memberikan akses ke antarmuka untuk memfasilitasi kontrol notifikasi dan layar kunci, atau ke Wear OS menonton sehingga Anda dapat mengontrol pemutaran dari tampilan jam. Klien eksternal dapat menggunakan pengontrol media untuk mengeluarkan perintah pemutaran ke aplikasi media Anda. Berikut adalah yang diterima oleh sesi media Anda, yang pada akhirnya mendelegasikan perintah ke pemutar media.
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 contoh penerimaan permintaan koneksi dalam dokumentasi Deklarasi
perintah yang tersedia.
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 khusus dan
mengubah playlist).
Callback ini juga menyertakan objek ControllerInfo
sehingga Anda dapat memodifikasi
cara Anda merespons setiap permintaan per pengontrol.
Mengubah playlist
Sesi media dapat langsung memodifikasi playlist pemutarnya seperti yang dijelaskan dalam
tindakan
Panduan ExoPlayer untuk playlist.
Pengontrol juga dapat memodifikasi
playlist jika salah satu
COMMAND_SET_MEDIA_ITEM
atau COMMAND_CHANGE_MEDIA_ITEMS
tersedia untuk pengontrol.
Saat menambahkan item baru ke playlist, pemutar biasanya memerlukan MediaItem
dengan instance
URI yang ditentukan
untuk membuat video tersebut dapat diputar. Secara default, item yang baru ditambahkan akan otomatis diteruskan
ke metode pemutar seperti player.addMediaItem
jika mereka telah menentukan URI.
Jika ingin menyesuaikan instance MediaItem
yang ditambahkan ke pemutar, Anda dapat
abaikan
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 ditetapkan untuk mendeskripsikan media yang diminta:
MediaItem.id
: ID umum yang mengidentifikasi media.MediaItem.RequestMetadata.mediaUri
: URI permintaan yang mungkin menggunakan URL kustom skema dan belum tentu dapat dimainkan secara langsung oleh pemain.MediaItem.RequestMetadata.searchQuery
: Kueri penelusuran tekstual, misalnya dari Asisten Google.MediaItem.MediaMetadata
: Metadata terstruktur seperti 'title' atau 'artis'.
Untuk opsi penyesuaian lainnya untuk daftar putar yang benar-benar baru, Anda dapat
juga mengganti
onSetMediaItems()
yang memungkinkan Anda menentukan item awal
dan posisi dalam playlist. Misalnya,
Anda dapat memperluas satu item yang diminta ke seluruh playlist dan memerintahkan
mulai dari indeks item yang diminta sebelumnya. J
contoh implementasi onSetMediaItems()
dengan fitur ini dapat ditemukan
di aplikasi demo sesi.
Mengelola tata letak khusus dan perintah khusus
Bagian berikut menjelaskan cara mengiklankan tata letak kustom ke aplikasi klien dan memberi otorisasi kepada pengontrol untuk mengirim perintah.
Menentukan tata letak kustom sesi
Untuk menunjukkan kepada aplikasi klien kontrol pemutaran mana yang ingin Anda tampilkan
pengguna, setel tata letak kustom sesi
saat membuat MediaSession
dalam metode onCreate()
dari
layanan.
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(); }
Mendeklarasikan pemutar yang tersedia dan perintah kustom
Aplikasi media dapat menentukan perintah khusus yang, misalnya, dapat digunakan dalam
tata letak khusus. Misalnya, Anda mungkin ingin mengimplementasikan tombol yang memungkinkan
pengguna untuk menyimpan item media
ke daftar item favorit. MediaController
mengirimkan perintah kustom dan MediaSession.Callback
menerimanya.
Anda dapat menentukan perintah sesi khusus mana yang tersedia untuk
MediaController
saat terhubung ke sesi media Anda. Anda mencapainya dengan
menggantikan MediaSession.Callback.onConnect()
. Konfigurasi dan tampilkan
seperangkat 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
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 dengan menggunakan
Properti packageName
dari objek MediaSession.ControllerInfo
yang
diteruskan ke metode Callback
. Hal ini memungkinkan Anda menyesuaikan
perilaku 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 khusus atau
interaksi lain dengan pemutar, Anda
mungkin ingin memperbarui tata letak yang ditampilkan di UI pengontrol. Contoh umum
adalah 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
sebagai play()
atau seekToNext()
, gabungkan Player
Anda 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 di
Penyesuaian.
Mengidentifikasi pengontrol permintaan dari perintah pemutar
Saat panggilan ke metode Player
berasal dari MediaController
, Anda dapat
identifikasi sumber asal dengan MediaSession.controllerForCurrentRequest
dan mendapatkan 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 ditemukan di perangkat Android dan perangkat periferal lainnya
seperti tombol putar/jeda pada headset Bluetooth. Tuas Media3
peristiwa tombol media untuk Anda ketika mereka tiba di sesi dan memanggil
metode Player
yang sesuai pada pemain sesi.
Aplikasi dapat mengganti perilaku default dengan mengganti
MediaSession.Callback.onMediaButtonEvent(Intent)
. Dalam kasus semacam ini, aplikasi
dapat/perlu menangani sendiri semua spesifikasi API.
Penanganan dan pelaporan error
Ada dua jenis error yang dimunculkan sesi dan dilaporkan ke pengontrol. Error fatal melaporkan kegagalan pemutaran teknis sesi pemutar yang mengganggu pemutaran. Error fatal dilaporkan ke pengontrol secara otomatis saat terjadi. Error non-fatal adalah error non-teknis atau kebijakan yang tidak mengganggu pemutaran dan dikirim ke pengontrol oleh aplikasi secara manual.
Error saat pemutaran fatal
Error pemutaran yang fatal dilaporkan ke sesi oleh pemutar, lalu
dilaporkan ke {i>controller<i}
untuk memanggil
Player.Listener.onPlayerError(PlaybackException)
dan
Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
Dalam kasus semacam itu, status pemutaran dialihkan ke STATE_IDLE
dan
MediaController.getPlaybackError()
menampilkan PlaybackException
yang menyebabkan
dalam proses transisi. Pengontrol dapat memeriksa PlayerException.errorCode
untuk mendapatkan
informasi tentang alasan kesalahan.
Untuk interoperabilitas, error fatal direplikasi ke PlaybackStateCompat
sesi platform dengan mentransisikan statusnya ke STATE_ERROR
dan menyetelnya
kode error dan pesan sesuai dengan PlaybackException
.
Penyesuaian error fatal
Untuk memberikan informasi yang dilokalkan dan bermakna bagi pengguna, kode error,
pesan {i>error <i}dan tambahan {i>error <i}dari sebuah kesalahan
pemutaran fatal dapat disesuaikan dengan
menggunakan ForwardingPlayer
saat membangun 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 yang sebenarnya
dan mencegat callback yang melaporkan error. Solusi yang disesuaikan
PlaybackException
kemudian didelegasikan ke pemroses yang
terdaftar di pemutar penerusan. Agar berfungsi, pemutar yang diteruskan
menggantikan Player.addListener
dan Player.removeListener
untuk memiliki akses ke
pemroses yang akan dikirimi 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 nonfatal yang tidak berasal dari pengecualian teknis dapat dikirimkan 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); }
{i>Error<i} nonfatal yang dikirim ke {i>controller<i} notifikasi media direplikasi ke
PlaybackStateCompat
sesi platform. Dengan demikian, hanya kode {i>error<i} dan
pesan error disetel ke PlaybackStateCompat
sebagaimana mestinya, sementara
PlaybackStateCompat.state
tidak diubah menjadi STATE_ERROR
.
Menerima error nonfatal
MediaController
menerima error nonfatal 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. } });