Framework router media Android memungkinkan produsen mengaktifkan pemutaran di perangkat mereka
melalui antarmuka standar yang disebut MediaRouteProvider
.
Penyedia rute menentukan antarmuka umum untuk memutar media di perangkat penerima, sehingga
memungkinkan pemutaran media di peralatan Anda dari aplikasi Android apa pun yang mendukung rute
media.
Panduan ini membahas cara membuat penyedia rute media untuk perangkat penerima dan menyediakannya
untuk aplikasi pemutaran media lain yang berjalan di Android. Untuk menggunakan API ini, Anda
harus memahami class utama
MediaRouteProvider
,
MediaRouteProviderDescriptor
, dan
RouteController
.
Ringkasan
Framework router media Android memungkinkan developer aplikasi media dan produsen
perangkat pemutaran media untuk terhubung melalui API umum dan antarmuka pengguna umum. Developer aplikasi yang mengimplementasikan antarmuka MediaRouter
kemudian dapat terhubung ke framework tersebut dan memutar konten ke perangkat yang berpartisipasi dalam framework router media. Produsen
perangkat pemutaran media dapat berpartisipasi dalam framework dengan memublikasikan MediaRouteProvider
yang memungkinkan aplikasi lain terhubung dan
memutar media di perangkat penerima. Gambar 1 mengilustrasikan cara aplikasi terhubung ke perangkat
penerima melalui framework router media.
Saat Anda mem-build penyedia rute media untuk perangkat penerima, penyedia tersebut memiliki tujuan berikut:
- Mendeskripsikan dan memublikasikan kemampuan perangkat penerima sehingga aplikasi lain dapat menemukannya dan menggunakan fitur pemutarannya.
- Menggabungkan antarmuka pemrograman perangkat penerima dan mekanisme transpor komunikasinya agar perangkat tersebut kompatibel dengan framework router media.
Distribusi penyedia rute
Penyedia rute media didistribusikan sebagai bagian dari aplikasi Android. Penyedia rute Anda dapat
tersedia untuk aplikasi lain dengan memperluas
MediaRouteProviderService
atau menggabungkan implementasi
MediaRouteProvider
dengan layanan Anda sendiri dan mendeklarasikan filter
intent untuk penyedia rute media. Langkah-langkah ini memungkinkan aplikasi lain untuk menemukan dan memanfaatkan
rute media Anda.
Catatan: Aplikasi yang berisi penyedia rute media juga dapat menyertakan antarmuka MediaRouter ke penyedia rute, tetapi hal ini tidak wajib.
Support library MediaRouter
API router media ditentukan dalam library AndroidX MediaRouter Anda harus menambahkan library ini ke project pengembangan aplikasi Anda. Untuk mengetahui informasi selengkapnya tentang cara menambahkan support library ke project, lihat Penyiapan Support Library.
Perhatian: Pastikan untuk menggunakan implementasi AndroidX
framework router media.
Jangan gunakan paket android.media
yang lama.
Membuat Layanan Penyedia
Framework router media harus dapat menemukan dan terhubung ke penyedia rute media
agar aplikasi lain dapat menggunakan rute Anda. Untuk melakukannya, framework router media akan mencari aplikasi yang mendeklarasikan tindakan intent penyedia rute media. Saat aplikasi lain ingin terhubung ke penyedia Anda, framework harus dapat memanggil dan terhubung ke penyedia tersebut, sehingga penyedia harus dienkapsulasi dalam Service
.
Kode contoh berikut menunjukkan deklarasi layanan penyedia rute media dan filter intent dalam manifes, yang memungkinkannya ditemukan dan digunakan oleh framework router media:
<service android:name=".provider.SampleMediaRouteProviderService" android:label="@string/sample_media_route_provider_service" android:process=":mrp"> <intent-filter> <action android:name="android.media.MediaRouteProviderService" /> </intent-filter> </service>
Contoh manifes ini mendeklarasikan layanan yang menggabungkan class penyedia rute media yang sebenarnya.
Framework router media Android menyediakan
class MediaRouteProviderService
untuk digunakan sebagai wrapper layanan bagi
penyedia rute media. Kode contoh berikut menunjukkan cara menggunakan class wrapper ini:
Kotlin
class SampleMediaRouteProviderService : MediaRouteProviderService() { override fun onCreateMediaRouteProvider(): MediaRouteProvider { return SampleMediaRouteProvider(this) } }
Java
public class SampleMediaRouteProviderService extends MediaRouteProviderService { @Override public MediaRouteProvider onCreateMediaRouteProvider() { return new SampleMediaRouteProvider(this); } }
Menentukan Kemampuan Rute
Aplikasi yang terhubung ke framework router media dapat menemukan rute media Anda melalui deklarasi manifes aplikasi, tetapi aplikasi juga perlu mengetahui kemampuan rute media yang Anda sediakan. Rute media dapat terdiri dari berbagai jenis dan memiliki fitur yang berbeda, dan aplikasi lain harus dapat menemukan detail ini untuk menentukan apakah rute tersebut kompatibel dengan rute Anda.
Framework router media memungkinkan Anda menentukan dan memublikasikan kemampuan rute media melalui objek IntentFilter
, objek MediaRouteDescriptor
, dan MediaRouteProviderDescriptor
. Bagian ini menjelaskan cara menggunakan class ini untuk memublikasikan detail rute media Anda untuk aplikasi lain.
Kategori rute
Sebagai bagian dari deskripsi terprogram penyedia rute media, Anda harus menentukan apakah penyedia Anda mendukung pemutaran jarak jauh, output sekunder, atau keduanya. Berikut adalah kategori rute yang disediakan oleh framework router media:
CATEGORY_LIVE_AUDIO
— Output audio ke perangkat output sekunder, seperti sistem musik yang didukung secara nirkabel.CATEGORY_LIVE_VIDEO
— Output video ke perangkat output sekunder, seperti perangkat Layar Nirkabel.CATEGORY_REMOTE_PLAYBACK
— Memutar video atau audio di perangkat terpisah yang menangani pengambilan, dekode, dan pemutaran media, seperti perangkat Chromecast.
Untuk menyertakan setelan ini dalam deskripsi rute media Anda, sisipkan setelan ke dalam objek IntentFilter
, yang nantinya Anda tambahkan ke objek MediaRouteDescriptor
:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) arrayListOf(this) } } }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { IntentFilter videoPlayback = new IntentFilter(); videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); } }
Jika menentukan intent CATEGORY_REMOTE_PLAYBACK
, Anda juga harus menentukan jenis media dan
kontrol pemutaran yang didukung oleh penyedia rute media Anda. Bagian berikutnya menjelaskan cara
menentukan setelan ini untuk perangkat Anda.
Jenis media dan protokol
Penyedia rute media untuk perangkat pemutaran jarak jauh harus menentukan jenis media dan protokol
transfer yang didukungnya. Anda menentukan setelan ini menggunakan class IntentFilter
serta metode addDataScheme()
dan
addDataType()
objek tersebut. Cuplikan
kode berikut menunjukkan cara menentukan filter intent untuk mendukung pemutaran video
jarak jauh menggunakan http, https, dan Real Time Streaming Protocol (RTSP):
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { private fun IntentFilter.addDataTypeUnchecked(type: String) { try { addDataType(type) } catch (ex: IntentFilter.MalformedMimeTypeException) { throw RuntimeException(ex) } } private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) addAction(MediaControlIntent.ACTION_PLAY) addDataScheme("http") addDataScheme("https") addDataScheme("rtsp") addDataTypeUnchecked("video/*") arrayListOf(this) } } ... }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { IntentFilter videoPlayback = new IntentFilter(); videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); videoPlayback.addAction(MediaControlIntent.ACTION_PLAY); videoPlayback.addDataScheme("http"); videoPlayback.addDataScheme("https"); videoPlayback.addDataScheme("rtsp"); addDataTypeUnchecked(videoPlayback, "video/*"); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); } ... private static void addDataTypeUnchecked(IntentFilter filter, String type) { try { filter.addDataType(type); } catch (MalformedMimeTypeException ex) { throw new RuntimeException(ex); } } }
Kontrol pemutaran
Penyedia rute media yang menawarkan pemutaran jarak jauh harus menentukan jenis kontrol media yang didukungnya. Berikut adalah jenis kontrol umum yang dapat disediakan oleh rute media:
- Kontrol pemutaran, seperti putar, jeda, putar ulang, dan maju cepat.
- Fitur antrean, yang memungkinkan aplikasi pengirim menambahkan dan menghapus item dari playlist yang dikelola oleh perangkat penerima.
- Fitur sesi, yang mencegah aplikasi pengirim mengganggu satu sama lain dengan meminta perangkat penerima memberikan ID sesi ke aplikasi yang meminta, lalu memeriksa ID tersebut dengan setiap permintaan kontrol pemutaran berikutnya.
Contoh kode berikut menunjukkan cara membuat filter intent untuk mendukung kontrol pemutaran rute media dasar:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { ... private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = run { val videoPlayback: IntentFilter = ... ... val playControls = IntentFilter().apply { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) addAction(MediaControlIntent.ACTION_SEEK) addAction(MediaControlIntent.ACTION_GET_STATUS) addAction(MediaControlIntent.ACTION_PAUSE) addAction(MediaControlIntent.ACTION_RESUME) addAction(MediaControlIntent.ACTION_STOP) } arrayListOf(videoPlayback, playControls) } } ... }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { ... IntentFilter playControls = new IntentFilter(); playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); playControls.addAction(MediaControlIntent.ACTION_SEEK); playControls.addAction(MediaControlIntent.ACTION_GET_STATUS); playControls.addAction(MediaControlIntent.ACTION_PAUSE); playControls.addAction(MediaControlIntent.ACTION_RESUME); playControls.addAction(MediaControlIntent.ACTION_STOP); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); CONTROL_FILTERS_BASIC.add(playControls); } ... }
Untuk informasi selengkapnya tentang intent kontrol pemutaran yang tersedia, lihat class MediaControlIntent
.
MediaRouteProviderDescriptor
Setelah menentukan kemampuan rute media menggunakan objek IntentFilter
, Anda dapat membuat objek deskriptor untuk dipublikasikan ke
framework router media Android. Objek deskripsi ini berisi spesifikasi kemampuan rute media Anda agar aplikasi lain dapat menentukan cara berinteraksi dengan rute media Anda.
Kode contoh berikut menunjukkan cara menambahkan filter intent yang telah dibuat sebelumnya ke
MediaRouteProviderDescriptor
dan menetapkan deskripsi untuk digunakan oleh
framework router media:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { init { publishRoutes() } private fun publishRoutes() { val resources = context.resources val routeName: String = resources.getString(R.string.variable_volume_basic_route_name) val routeDescription: String = resources.getString(R.string.sample_route_description) // Create a route descriptor using previously created IntentFilters val routeDescriptor: MediaRouteDescriptor = MediaRouteDescriptor.Builder(VARIABLE_VOLUME_BASIC_ROUTE_ID, routeName) .setDescription(routeDescription) .addControlFilters(CONTROL_FILTERS_BASIC) .setPlaybackStream(AudioManager.STREAM_MUSIC) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .setVolume(mVolume) .build() // Add the route descriptor to the provider descriptor val providerDescriptor: MediaRouteProviderDescriptor = MediaRouteProviderDescriptor.Builder() .addRoute(routeDescriptor) .build() // Publish the descriptor to the framework descriptor = providerDescriptor } ... }
Java
public SampleMediaRouteProvider(Context context) { super(context); publishRoutes(); } private void publishRoutes() { Resources r = getContext().getResources(); // Create a route descriptor using previously created IntentFilters MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder( VARIABLE_VOLUME_BASIC_ROUTE_ID, r.getString(R.string.variable_volume_basic_route_name)) .setDescription(r.getString(R.string.sample_route_description)) .addControlFilters(CONTROL_FILTERS_BASIC) .setPlaybackStream(AudioManager.STREAM_MUSIC) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .setVolume(mVolume) .build(); // Add the route descriptor to the provider descriptor MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder() .addRoute(routeDescriptor) .build(); // Publish the descriptor to the framework setDescriptor(providerDescriptor); }
Untuk informasi selengkapnya tentang setelan deskripsi yang tersedia, lihat dokumentasi referensi untuk MediaRouteDescriptor
dan MediaRouteProviderDescriptor
.
Mengontrol Rute
Saat aplikasi terhubung ke penyedia rute media Anda, penyedia tersebut akan menerima perintah pemutaran melalui framework router media yang dikirim ke rute Anda oleh aplikasi lain. Untuk menangani
permintaan ini, Anda harus menyediakan implementasi class MediaRouteProvider.RouteController
, yang memproses perintah
dan menangani komunikasi aktual ke perangkat penerima.
Framework router media memanggil metode onCreateRouteController()
penyedia rute Anda untuk mendapatkan instance class ini, lalu merutekan permintaan ke instance tersebut.
Metode ini adalah metode utama class MediaRouteProvider.RouteController
, yang harus Anda implementasikan untuk
penyedia rute media Anda:
onSelect()
— Dipanggil saat aplikasi memilih rute Anda untuk pemutaran. Gunakan metode ini untuk melakukan tugas persiapan yang mungkin diperlukan sebelum pemutaran media dimulai.onControlRequest()
- Mengirimkan perintah pemutaran spesifik ke perangkat penerima.onSetVolume()
— Mengirim permintaan ke perangkat penerima untuk menetapkan volume pemutaran ke nilai tertentu.onUpdateVolume()
— Mengirim permintaan ke perangkat penerima untuk mengubah volume pemutaran dengan jumlah yang ditentukan.onUnselect()
- Dipanggil ketika aplikasi batal memilih rute.onRelease()
— Dipanggil saat rute tidak lagi diperlukan oleh framework, sehingga rute tersebut dapat membebaskan resource-nya.
Semua permintaan kontrol pemutaran, kecuali untuk perubahan volume, akan diarahkan ke metode onControlRequest()
. Penerapan metode ini harus mengurai permintaan kontrol dan meresponsnya
dengan tepat. Berikut adalah contoh implementasi metode ini yang memproses perintah untuk rute media pemutaran jarak jauh:
Kotlin
private class SampleRouteController : MediaRouteProvider.RouteController() { ... override fun onControlRequest( intent: Intent, callback: MediaRouter.ControlRequestCallback? ): Boolean { return if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { val action = intent.action when (action) { MediaControlIntent.ACTION_PLAY -> handlePlay(intent, callback) MediaControlIntent.ACTION_ENQUEUE -> handleEnqueue(intent, callback) MediaControlIntent.ACTION_REMOVE -> handleRemove(intent, callback) MediaControlIntent.ACTION_SEEK -> handleSeek(intent, callback) MediaControlIntent.ACTION_GET_STATUS -> handleGetStatus(intent, callback) MediaControlIntent.ACTION_PAUSE -> handlePause(intent, callback) MediaControlIntent.ACTION_RESUME -> handleResume(intent, callback) MediaControlIntent.ACTION_STOP -> handleStop(intent, callback) MediaControlIntent.ACTION_START_SESSION -> handleStartSession(intent, callback) MediaControlIntent.ACTION_GET_SESSION_STATUS -> handleGetSessionStatus(intent, callback) MediaControlIntent.ACTION_END_SESSION -> handleEndSession(intent, callback) else -> false }.also { Log.d(TAG, sessionManager.toString()) } } else { false } } ... }
Java
private final class SampleRouteController extends MediaRouteProvider.RouteController { ... @Override public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { String action = intent.getAction(); if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { boolean success = false; if (action.equals(MediaControlIntent.ACTION_PLAY)) { success = handlePlay(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) { success = handleEnqueue(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) { success = handleRemove(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_SEEK)) { success = handleSeek(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) { success = handleGetStatus(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) { success = handlePause(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_RESUME)) { success = handleResume(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_STOP)) { success = handleStop(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) { success = handleStartSession(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) { success = handleGetSessionStatus(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) { success = handleEndSession(intent, callback); } Log.d(TAG, sessionManager.toString()); return success; } return false; } ... }
Penting untuk dipahami bahwa class MediaRouteProvider.RouteController
dimaksudkan untuk bertindak sebagai wrapper bagi API ke peralatan pemutaran media Anda. Implementasi metode dalam class ini sepenuhnya bergantung pada antarmuka terprogram yang disediakan oleh perangkat penerima Anda.
Contoh Kode
Contoh MediaRouter menunjukkan cara membuat penyedia rute media kustom.