Ringkasan MediaRouteProvider

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 dapat memutar media di peralatan Anda dari aplikasi Android apa pun yang mendukung rute perjalanan.

Panduan ini membahas cara membuat penyedia rute media untuk perangkat penerima dan membuatnya yang tersedia untuk aplikasi pemutaran media lain yang berjalan di Android. Untuk menggunakan API ini, Anda harus terbiasa dengan class utama MediaRouteProvider, MediaRouteProviderDescriptor, dan RouteController.

Ringkasan

Framework router media Android memungkinkan developer aplikasi media dan perangkat pemutaran media produsen untuk terhubung melalui API umum dan antarmuka pengguna umum. Developer aplikasi yang mengimplementasikan antarmuka MediaRouter kemudian dapat terhubung ke dan memutar konten ke perangkat yang berpartisipasi dalam kerangka kerja {i>router<i} media. Media produsen perangkat pemutaran dapat berpartisipasi dalam framework dengan memublikasikan MediaRouteProvider yang memungkinkan aplikasi lain terhubung ke dan memutar media di perangkat penerima. Gambar 1 mengilustrasikan cara aplikasi terhubung ke jaringan penerima perangkat tertentu melalui framework router media.

Gambar 1. Ringkasan cara class penyedia rute media menyediakan komunikasi dari aplikasi media ke perangkat penerima.

Saat Anda membangun penyedia rute media untuk perangkat penerima, penyedia tersebut akan menyajikan untuk tujuan berikut:

  • Menjelaskan dan memublikasikan kemampuan perangkat penerima agar aplikasi lain dapat menemukannya dan menggunakan fitur pemutarannya.
  • Menggabungkan antarmuka pemrograman perangkat penerima dan komunikasinya mekanisme transportasi umum untuk membuat perangkat kompatibel dengan kerangka kerja {i>router<i} media.

Distribusi penyedia rute

Penyedia rute media didistribusikan sebagai bagian dari aplikasi Android. Penyedia rute Anda dapat berupa tersedia untuk aplikasi lain dengan memperluas MediaRouteProviderService atau menggabungkan penerapan MediaRouteProvider dengan layanan Anda sendiri dan mendeklarasikan 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 ini tidak wajib.

Support Library MediaRouter

API router media didefinisikan dalam Library MediaRouter AndroidX Anda harus menambahkan library ini ke project pengembangan aplikasi Anda. Untuk informasi selengkapnya tentang cara menambahkan support library ke project Anda, lihat Penyiapan Support Library.

Perhatian: Pastikan Anda menggunakan AndroidX dan implementasi 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 Anda untuk mengizinkan aplikasi lain menggunakan rute Anda. Untuk melakukannya, kerangka kerja {i>router<i} 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 dengannya, jadi harus dienkapsulasi dalam Service.

Kode contoh berikut menunjukkan deklarasi layanan penyedia rute media dan atribut filter intent dalam manifes, yang memungkinkannya ditemukan dan digunakan oleh router media kerangka kerja:

<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 untuk penyedia rute media. Kode contoh berikut menunjukkan cara menggunakan 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 melalui deklarasi manifes aplikasi, tetapi juga perlu mengetahui kemampuan rute media yang Anda yang Anda sediakan. Rute media dapat terdiri dari berbagai jenis dan memiliki fitur yang berbeda, serta aplikasi lainnya harus dapat menemukan detail ini untuk menentukan apakah mereka kompatibel dengan rute Anda.

Framework router media memungkinkan Anda mendefinisikan dan memublikasikan kemampuan media rute melalui objek IntentFilter, objek MediaRouteDescriptor, dan MediaRouteProviderDescriptor. Bagian ini menjelaskan cara menggunakan guna 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. Ini adalah rutenya yang disediakan oleh framework router media:

  • CATEGORY_LIVE_AUDIO — Output audio ke perangkat output sekunder, seperti sistem musik berkemampuan nirkabel.
  • CATEGORY_LIVE_VIDEO — Output video ke perangkat output sekunder, seperti perangkat Layar Nirkabel.
  • CATEGORY_REMOTE_PLAYBACK — Putar video atau audio di perangkat terpisah yang menangani media pengambilan, decoding, dan pemutaran, seperti Perangkat Chromecast.

Untuk memasukkan setelan ini dalam deskripsi rute media Anda, masukkan setelan ini 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 dan jenis media kontrol pemutaran didukung oleh penyedia rute media Anda. Bagian selanjutnya 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 transfer protokol yang didukungnya. Anda menentukan setelan ini menggunakan IntentFilter addDataScheme(), dan Metode addDataType() objek tersebut. Tujuan cuplikan kode berikut menunjukkan cara menentukan filter intent untuk mendukung video jarak jauh pemutaran 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 daftar putar yang dikelola oleh perangkat penerima.
  • Fitur sesi, yang mencegah aplikasi pengirim mengganggu masing-masing sesi lainnya dengan meminta perangkat penerima memberikan ID sesi ke aplikasi yang meminta dan kemudian memeriksanya 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 Class MediaControlIntent.

MediaRouteProviderDescriptor

Setelah menentukan kemampuan rute media menggunakan objek IntentFilter, Anda kemudian dapat membuat objek deskriptor untuk dipublikasikan ke framework router media Android. Objek deskriptor ini berisi detail media Anda kemampuan rute agar aplikasi lain dapat menentukan cara berinteraksi dengan media Anda rute perjalanan.

Kode contoh berikut menunjukkan cara menambahkan filter intent yang dibuat sebelumnya ke MediaRouteProviderDescriptor dan tetapkan deskriptor 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 deskriptor yang tersedia, lihat dokumentasi referensi untuk MediaRouteDescriptor dan MediaRouteProviderDescriptor.

Mengontrol Rute

Jika aplikasi terhubung ke penyedia rute media Anda, penyedia akan menerima pemutaran perintah melalui framework router media yang dikirim ke rute Anda oleh aplikasi lain. Untuk menangani hal ini permintaan, Anda harus menyediakan implementasi class MediaRouteProvider.RouteController, yang memproses perintah dan menangani komunikasi aktual ke perangkat penerima Anda.

Framework router media memanggil onCreateRouteController() penyedia rute Anda untuk mendapatkan instance class ini, lalu merutekan permintaan ke instance tersebut. Ini adalah metode utama class MediaRouteProvider.RouteController, yang harus Anda implementasikan untuk penyedia rute media Anda:

  • onSelect() — Dipanggil bila aplikasi memilih rute Anda untuk pemutaran. Anda menggunakan metode ini untuk melakukan persiapan yang mungkin diperlukan sebelum pemutaran media dimulai.
  • onControlRequest() - Mengirimkan perintah pemutaran spesifik ke perangkat penerima.
  • onSetVolume() — Mengirim permintaan ke perangkat penerima untuk menyetel volume pemutaran ke nilai tertentu.
  • onUpdateVolume() — Mengirim permintaan ke perangkat penerima untuk mengubah pemutaran volume dengan besaran tertentu.
  • onUnselect() - Dipanggil ketika aplikasi batal memilih rute.
  • onRelease() — Dipanggil ketika rute tidak lagi dibutuhkan oleh framework, memungkinkannya untuk membebaskan Google Cloud Platform.

Semua permintaan kontrol pemutaran, kecuali untuk perubahan volume, diarahkan ke onControlRequest() . Implementasi Anda terhadap 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 untuk API ke peralatan pemutaran media Anda. Implementasi metode di class ini sepenuhnya bergantung pada antarmuka terprogram yang disediakan oleh perangkat penerima.

Contoh Kode

MediaRouter contoh ini menunjukkan cara membuat penyedia rute media kustom.