Cast Connect dengan Aplikasi ATV

googlecastnew500.png

Codelab ini akan mengajari Anda cara memodifikasi aplikasi Android TV yang sudah ada sehingga aplikasi pengirim Cast yang ada dapat mentransmisikan konten dan berkomunikasi dengan aplikasi Android TV.

Apa itu Google Cast dan Cast Connect?

Google Cast memungkinkan pengguna mentransmisikan konten dari perangkat seluler ke TV. Sesi Google Cast umumnya terdiri dari dua komponen — aplikasi pengirim dan penerima. Aplikasi pengirim, seperti aplikasi seluler atau situs web, seperti YouTube.com, memulai dan mengontrol pemutaran aplikasi penerima Cast. Aplikasi penerima Cast adalah aplikasi HTML 5 yang berjalan di perangkat Chromecast dan Android TV.

Hampir semua status dalam sesi Cast disimpan di aplikasi penerima. Saat status diperbarui, misalnya jika item media baru dimuat, status media akan disiarkan ke semua pengirim. Siaran ini berisi status sesi Cast saat ini. Aplikasi Pengirim menggunakan status media ini untuk menampilkan informasi pemutaran di UI-nya.

Cast Connect dibuat di atas infrastruktur ini, dengan aplikasi Android TV yang bertindak sebagai penerima. Library Cast Connect memungkinkan aplikasi Android TV Anda menerima pesan dan menyiarkan status media seolah-olah aplikasi penerima transmisi.

Apa yang akan kita buat?

Setelah menyelesaikan codelab ini, Anda dapat menggunakan aplikasi pengirim Cast untuk mentransmisikan video ke aplikasi Android TV. Aplikasi Android TV juga dapat berkomunikasi dengan aplikasi pengirim melalui protokol Cast.

Yang akan Anda pelajari

  • Cara menambahkan library Cast Connect ke contoh aplikasi ATV.
  • Cara menghubungkan pengirim Cast dan meluncurkan aplikasi ATV.
  • Cara memulai pemutaran media di aplikasi ATV dari aplikasi pengirim Cast.
  • Cara mengirim status media dari aplikasi ATV ke aplikasi pengirim Cast.

Yang Anda butuhkan

Anda bisa mendownload semua kode contoh ke komputer Anda...

Download Kode Sumber

dan mengekstrak file zip yang didownload.

Pertama, mari kita lihat bagaimana tampilan contoh aplikasi yang lengkap. Aplikasi Android TV menggunakan UI Leanback dan pemutar video dasar. Pengguna dapat memilih video dari daftar yang kemudian diputar di TV saat dipilih. Dengan aplikasi pengirim seluler yang menyertainya, pengguna juga dapat mentransmisikan video ke aplikasi Android TV.

f9f98aa234e84bae.png

Mendaftarkan perangkat developer

Guna mengaktifkan kemampuan Cast Connect untuk pengembangan aplikasi, Anda harus mendaftarkan nomor seri Chromecast bawaan perangkat Android TV yang akan digunakan di Konsol Developer Cast. Anda dapat menemukan nomor seri dengan membuka Settings > Device Preferences > Chromecast built-in > Serial number di Android TV. Perhatikan bahwa nomor ini berbeda dengan nomor seri perangkat fisik Anda dan harus diperoleh dari metode yang dijelaskan di atas.

f74dfe19bc459b76.png

Tanpa pendaftaran, Cast Connect hanya akan berfungsi untuk aplikasi yang diinstal dari Google Play Store karena alasan keamanan. Setelah 15 menit memulai proses pendaftaran, mulai ulang perangkat Anda.

Menginstal aplikasi pengirim Android

Untuk menguji permintaan kirim dari perangkat seluler, kami telah menyediakan aplikasi pengirim sederhana yang disebut Cast Video. Kami akan memanfaatkan ADB untuk menginstal APK. Jika Anda telah menginstal versi Cast Video yang berbeda, uninstal versi tersebut dari semua profil yang ada di perangkat sebelum melanjutkan.

  1. Aktifkan opsi developer dan proses debug USB di ponsel Android Anda.
  2. Colokkan kabel data USB untuk menghubungkan ponsel Android dengan komputer pengembangan.
  3. Instal mobile-sender.apk ke ponsel Android Anda.

93e35a0f0332f290.png

  1. Anda dapat menemukan aplikasi pengirim Cast Video di ponsel Android. e29d89df484d9661.png

d6a0435ec3bac0af.png

Menginstal aplikasi Android TV

Petunjuk berikut menjelaskan cara membuka dan menjalankan contoh aplikasi yang telah selesai di Android Studio:

  1. Pilih Import Project di layar sambutan atau opsi menu File > New > Import Project....
  2. Pilih direktori android_studio_folder.pngapp-done dari folder kode contoh dan klik OK.
  3. Klik File > 1791b5212a8947d.png Sync Project with Gradle Files.
  4. Aktifkan opsi developer dan proses debug USB di perangkat Android TV.
  5. ADB terhubung dengan perangkat Android TV Anda, perangkat akan ditampilkan di Android Studio. 7bcf00bfb6877ad5.png
  6. Klik tombol execute.pngRun, Anda akan melihat aplikasi ATV yang bernama Cast Connect Codelab muncul setelah beberapa detik.

Mari putar Cast Connect dengan aplikasi ATV

  1. Buka Layar Utama Android TV.
  2. Buka aplikasi pengirim Cast Video dari ponsel Android. Klik tombol Cast f77992b2cf0422a2.png dan pilih perangkat ATV.
  3. Aplikasi Cast Connect Codelab ATV akan diluncurkan di ATV Anda dan tombol Cast di pengirim akan menunjukkan bahwa aplikasi terhubung 303287388679d79b.png.
  4. Pilih video dari aplikasi ATV, dan video akan mulai diputar di ATV Anda.
  5. Di ponsel Anda, pengontrol mini kini terlihat di bagian bawah aplikasi pengirim. Anda dapat menggunakan tombol putar/jeda untuk mengontrol pemutaran.
  6. Pilih video dari ponsel dan putar. Video akan mulai diputar di ATV dan pengontrol yang diperluas akan ditampilkan pada pengirim seluler Anda.
  7. Kunci ponsel dan saat Anda membuka kuncinya, Anda akan melihat notifikasi di layar kunci untuk mengontrol pemutaran media atau menghentikan transmisi.

a20257e816c913a.png

Setelah memverifikasi integrasi Cast Connect aplikasi yang telah selesai, kita perlu menambahkan dukungan untuk Cast Connect ke aplikasi awal yang Anda download. Sekarang Anda siap untuk mengerjakan project awal menggunakan Android Studio:

  1. Pilih Import Project di layar sambutan atau opsi menu File > New > Import Project....
  2. Pilih direktori android_studio_folder.pngapp-start dari folder kode contoh dan klik OK.
  3. Klik File > 1791b5212a8947d.png Sync Project with Gradle Files.
  4. Pilih perangkat ATV dan klik tombol execute.pngRun untuk menjalankan aplikasi dan menjelajahi UI. 7bcf00bfb6877ad5.png

f9f98aa234e84bae.png

Desain aplikasi

Aplikasi ini menyediakan daftar video yang dapat dijelajahi pengguna. Pengguna dapat memilih video untuk diputar di Android TV. Aplikasi ini terdiri dari dua aktivitas utama: MainActivity dan PlaybackActivity.

MainActivity

Aktivitas ini berisi Fragmen (MainFragment). Daftar video dan metadata terkaitnya dikonfigurasi dalam class MovieList dan metode setupMovies() dipanggil untuk membuat daftar objek Movie.

Objek Movie mewakili entity video dengan judul, deskripsi, thumbnail gambar, dan url video. Setiap objek Movie terikat dengan CardPresenter untuk menampilkan thumbnail video dengan judul dan studio serta diteruskan ke ArrayObjectAdapter.

Saat item dipilih, objek Movie yang sesuai diteruskan ke PlaybackActivity.

PlaybackActivity

Aktivitas ini berisi Fragmen (PlaybackVideoFragment) yang menghosting VideoView dengan ExoPlayer, beberapa kontrol media, dan area teks untuk menampilkan deskripsi video yang dipilih dan memungkinkan pengguna memutar video di Android TV. Pengguna dapat menggunakan remote control untuk memutar/menjeda atau mencari pemutaran video.

Prasyarat Cast Connect

Cast Connect menggunakan versi baru Layanan Google Play yang mengharuskan aplikasi ATV Anda diperbarui agar dapat menggunakan namespace AndroidX.

Untuk mendukung Cast Connect di aplikasi Android TV, Anda harus membuat dan mendukung peristiwa dari sesi media. Library Cast Connect menghasilkan status media berdasarkan status sesi media. Sesi media Anda juga digunakan oleh library Cast Connect untuk memberi tahu kapan pesan tertentu diterima dari pengirim, seperti jeda.

Dependensi

Perbarui file build.gradle aplikasi untuk menyertakan dependensi library yang diperlukan:

dependencies {
    ....

    // Cast Connect libraries and dependencies
    implementation 'com.google.android.gms:play-services-cast-tv:17.0.0'
    implementation 'com.google.android.gms:play-services-cast:19.0.0'
}

Sinkronkan project untuk mengonfirmasikan project dibuat tanpa error.

Inisialisasi

CastReceiverContext adalah objek singleton untuk mengoordinasikan semua interaksi Cast. Anda harus mengimplementasikan antarmuka ReceiverOptionsProvider untuk memberikan CastReceiverOptions saat CastReceiverContext diinisialisasi.

Buat file CastReceiverOptionsProvider.java dan tambahkan class berikut ke project:

package com.google.sample.cast.castconnect;

import android.content.Context;
import com.google.android.gms.cast.tv.CastReceiverOptions;
import com.google.android.gms.cast.tv.ReceiverOptionsProvider;

public class CastReceiverOptionsProvider implements ReceiverOptionsProvider {
    @Override
    public CastReceiverOptions getOptions(Context context) {
        return new CastReceiverOptions.Builder(context)
                .setStatusText("Cast Connect Codelab")
                .build();
    }
}

Kemudian tentukan penyedia opsi penerima dalam tag <application> dari file aplikasi AndroidManifest.xml:

<application>
  ...

  <meta-data
    android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.castconnect.CastReceiverOptionsProvider" />
</application>

Untuk terhubung dengan aplikasi ATV dari pengirim Cast, pilih aktivitas yang ingin Anda luncurkan. Dalam codelab ini, kami akan meluncurkan MainActivity aplikasi saat sesi Cast dimulai. Di file AndroidManifest.xml, tambahkan filter intent peluncuran di MainActivity.

<activity android:name=".MainActivity">
  ...
  <intent-filter>
    <action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Siklus Proses Konteks Penerima Cast

Anda harus memulai CastReceiverContext saat aplikasi diluncurkan dan menghentikan CastReceiverContext saat aplikasi Anda dipindahkan ke latar belakang. Sebaiknya gunakan LifecycleObserver dari library androidx.lifecycle untuk mengelola panggilan CastReceiverContext.start() dan CastReceiverContext.stop()

Buka MyApplication.java, inisialisasi konteks cast dengan memanggil initInstance() dalam metode onCreate aplikasi. Di class AppLifeCycleObserver, start() pada CastReceiverContext saat aplikasi dilanjutkan dan stop() saat aplikasi dijeda:

package com.google.sample.cast.castconnect;

...

import com.google.android.gms.cast.tv.CastReceiverContext;

public class MyApplication extends Application {

    private static final String LOG_TAG = "MyApplication";

    @Override
    public void onCreate() {
        super.onCreate();
        CastReceiverContext.initInstance(this);
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleObserver());
    }

    public static class AppLifecycleObserver implements DefaultLifecycleObserver {
        @Override
        public void onResume(@NonNull LifecycleOwner owner) {
            Log.d(LOG_TAG, "onResume");
            CastReceiverContext.getInstance().start();
        }

        @Override
        public void onPause(@NonNull LifecycleOwner owner) {
            Log.d(LOG_TAG, "onPause");
            CastReceiverContext.getInstance().stop();
        }
    }
}

Menghubungkan MediaSession ke MediaManager

MediaManager adalah properti singleton CastReceiverContext, yang mengelola status media, menangani intent pemuatan, menerjemahkan pesan namespace media dari pengirim ke perintah media, dan mengirim status media kembali ke pengirim.

Saat membuat MediaSession, Anda juga perlu memberikan token MediaSession saat ini ke MediaManager agar ekstensi tersebut tahu ke mana harus mengirimkan perintah dan mengambil status pemutaran media. Pastikan MediaSession diinisialisasi sebelum menyetel token ke MediaManager.

import com.google.android.gms.cast.tv.CastReceiverContext;
...

public class PlaybackVideoFragment extends VideoSupportFragment {

    private CastReceiverContext castReceiverContext;
    ...

    private void initializePlayer() {
        if (mPlayer == null) {
            ...
            mMediaSession = new MediaSessionCompat(getContext(), LOG_TAG);
            ...

            castReceiverContext = CastReceiverContext.getInstance();
            if (castReceiverContext != null) {
                MediaManager mediaManager = castReceiverContext.getMediaManager();
                mediaManager.setSessionCompatToken(mMediaSession.getSessionToken());
            }
        }
    }
}

Saat merilis MediaSession karena pemutaran tidak aktif, Anda harus menyetel token null di MediaManager:

private void releasePlayer() {
    if (mMediaSession != null) {
        mMediaSession.release();
    }
    if (castReceiverContext != null) {
        MediaManager mediaManager = castReceiverContext.getMediaManager();
        mediaManager.setSessionCompatToken(null);
    }
    ...
}

Mari kita jalankan aplikasi contoh

Klik tombol execute.pngRun untuk men-deploy aplikasi di perangkat ATV, menutup aplikasi, dan kembali ke Layar Utama ATV. Dari pengirim, klik tombol Cast f77992b2cf0422a2.png dan pilih perangkat ATV. Anda akan melihat aplikasi ATV diluncurkan di perangkat ATV dan status tombol Cast terhubung.

Perintah pemuatan dikirim melalui intent dengan nama paket yang Anda tentukan di konsol developer. Anda perlu menambahkan filter intent berikut yang telah ditentukan sebelumnya di aplikasi Android TV untuk menentukan aktivitas target yang akan menerima intent ini. Dalam file AndroidManifest.xml, tambahkan filter intent pemuatan ke PlayerActivity:

<activity android:name="com.google.sample.cast.castconnect.PlaybackActivity"
          android:launchMode="singleTask">
  <intent-filter>
     <action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
     <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Menangani Permintaan Pemuatan di Android TV

Setelah aktivitas dikonfigurasikan untuk menerima intent ini yang berisi permintaan pemuatan, kita harus menanganinya.

Aplikasi ini memanggil metode pribadi yang disebut processIntent saat aktivitas dimulai. Metode ini berisi logika untuk memproses intent masuk. Untuk menangani permintaan pemuatan, kami akan mengubah metode ini dan mengirim intent agar diproses lebih lanjut dengan memanggil metode onNewIntent instance MediaManager. Jika MediaManager yang mendeteksi intent adalah permintaan pemuatan, objek MediaLoadRequestData diekstrak dari intent dan memanggil MediaLoadCommandCallback.onLoad(). Ubah metode processIntent di PlaybackVideoFragment untuk menangani intent yang berisi permintaan pemuatan:

public void processIntent(Intent intent) {
    MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager();
    // Pass intent to Cast SDK
    if (mediaManager.onNewIntent(intent)) {
        return;
    }

    // Clears all overrides in the modifier.
    mediaManager.getMediaStatusModifier().clear();

    // If the SDK doesn't recognize the intent, handle the intent with your own logic.
    ...
}

Selanjutnya, kita akan memperluas class abstrak MediaLoadCommandCallback yang akan mengganti metode onLoad() yang dipanggil oleh MediaManager. Metode ini menerima data permintaan pemuatan dan mengonversinya menjadi objek Movie. Setelah dikonversi, film akan diputar oleh pemutar lokal. MediaManager kemudian diperbarui dengan MediaLoadRequest dan menyiarkan MediaStatus ke pengirim yang terhubung. Buat class pribadi bertingkat yang disebut MyMediaLoadCommandCallback di PlaybackVideoFragment:

private class MyMediaLoadCommandCallback extends MediaLoadCommandCallback {
    @Override
    public Task<MediaLoadRequestData> onLoad(String senderId, MediaLoadRequestData mediaLoadRequestData) {
        Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show();

        if (mediaLoadRequestData == null) {
            // Throw MediaException to indicate load failure.
            return Tasks.forException(new MediaException(
                    new MediaError.Builder()
                            .setDetailedErrorCode(MediaError.DetailedErrorCode.LOAD_FAILED)
                            .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                            .build()));
        }

        return Tasks.call(() -> {
            play(convertLoadRequestToMovie(mediaLoadRequestData));

            // Update media metadata and state
            MediaManager mediaManager = castReceiverContext.getMediaManager();
            mediaManager.setDataFromLoad(mediaLoadRequestData);
            mediaManager.broadcastMediaStatus();

            // Return the resolved MediaLoadRequestData to indicate load success.
            return mediaLoadRequestData;
        });
    }
}

private Movie convertLoadRequestToMovie(MediaLoadRequestData mediaLoadRequestData) {
    if (mediaLoadRequestData == null) {
        return null;
    }
    MediaInfo mediaInfo = mediaLoadRequestData.getMediaInfo();
    if (mediaInfo == null) {
        return null;
    }

    String videoUrl = mediaInfo.getContentId();
    if (mediaInfo.getContentUrl() != null) {
        videoUrl = mediaInfo.getContentUrl();
    }

    MediaMetadata metadata = mediaInfo.getMetadata();
    Movie movie = new Movie();
    movie.setVideoUrl(videoUrl);
    if (metadata != null) {
        movie.setTitle(metadata.getString(MediaMetadata.KEY_TITLE));
        movie.setDescription(metadata.getString(MediaMetadata.KEY_SUBTITLE));
        movie.setCardImageUrl(metadata.getImages().get(0).getUrl().toString());
    }
    return movie;
}

Setelah Callback ditetapkan, kita perlu mendaftarkannya ke MediaManager. Callback harus terdaftar sebelum MediaManager.onNewIntent() dipanggil. Tambahkan setMediaLoadCommandCallback saat pemutar diinisialisasi:

private void initializePlayer() {
    if (mPlayer == null) {
        ...
        mMediaSession = new MediaSessionCompat(getContext(), LOG_TAG);
        ...

        castReceiverContext = CastReceiverContext.getInstance();
        if (castReceiverContext != null) {
            MediaManager mediaManager = castReceiverContext.getMediaManager();
            mediaManager.setSessionCompatToken(mMediaSession.getSessionToken());
            mediaManager.setMediaLoadCommandCallback(new MyMediaLoadCommandCallback());
        }
    }
}

Mari kita jalankan aplikasi contoh

Klik tombol execute.pngRun untuk men-deploy aplikasi pada perangkat ATV Anda. Dari pengirim, klik tombol Cast f77992b2cf0422a2.png dan pilih perangkat ATV. Aplikasi ATV akan diluncurkan di perangkat ATV. Pilih video di seluler, video akan mulai diputar di ATV. Periksa apakah Anda menerima notifikasi di ponsel yang berisi kontrol pemutaran. Coba gunakan kontrol seperti jeda, maka video di perangkat ATV akan dijeda.

Aplikasi saat ini kini mendukung perintah dasar yang kompatibel dengan sesi media, seperti putar, jeda, dan cari. Namun, ada beberapa perintah kontrol Cast yang tidak tersedia di sesi media. Anda perlu mendaftarkan MediaCommandCallback untuk mendukung perintah kontrol Cast tersebut.

Tambahkan MyMediaCommandCallback ke instance MediaManager menggunakan setMediaCommandCallback saat pemutar diinisialisasi:

private void initializePlayer() {
        ...

        castReceiverContext = CastReceiverContext.getInstance();
        if (castReceiverContext != null) {
            MediaManager mediaManager = castReceiverContext.getMediaManager();
            ...
            mediaManager.setMediaCommandCallback(new MyMediaCommandCallback());
        }
}

Buat class MyMediaCommandCallback untuk mengganti metode, seperti onQueueUpdate() untuk mendukung perintah kontrol Cast tersebut:

private class MyMediaCommandCallback extends MediaCommandCallback {
        @Override
        public Task<Void> onQueueUpdate(String senderId, QueueUpdateRequestData queueUpdateRequestData) {
            Toast.makeText(getActivity(), "onQueueUpdate()", Toast.LENGTH_SHORT).show();

            // Queue Prev / Next
            if (queueUpdateRequestData.getJump() != null) {
                Toast.makeText(getActivity(),
                        "onQueueUpdate(): Jump = " + queueUpdateRequestData.getJump(),
                        Toast.LENGTH_SHORT).show();
            }

            return super.onQueueUpdate(senderId, queueUpdateRequestData);
        }
}

Memodifikasi Status Media

Cast Connect mendapatkan status media dasar dari sesi media. Untuk mendukung fitur lanjutan, aplikasi Android TV dapat menentukan dan mengganti properti status tambahan melalui MediaStatusModifier. MediaStatusModifier akan selalu beroperasi pada MediaSession yang telah Anda tetapkan di CastReceiverContext.

Misalnya, untuk menentukan setMediaCommandSupported saat onLoad callback dipicu:

private class MyMediaLoadCommandCallback extends MediaLoadCommandCallback {
    @Override
    public Task<MediaLoadRequestData> onLoad(String senderId, MediaLoadRequestData mediaLoadRequestData) {
        Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show();

        ...

        return Tasks.call(() -> {
            play(convertLoadRequestToMovie(mediaLoadRequestData));

            // Update media metadata and state
            MediaManager mediaManager = castReceiverContext.getMediaManager();
            mediaManager.setDataFromLoad(mediaLoadRequestData);

            // Use MediaStatusModifier to provide additional information for Cast senders.
            mediaManager.getMediaStatusModifier()
                        .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT, true)
                        .setIsPlayingAd(false);

            mediaManager.broadcastMediaStatus();

            // Return the resolved MediaLoadRequestData to indicate load success.
            return mediaLoadRequestData;
        });
    }
}

Mencegah MediaStatus Sebelum Mengirim

Serupa dengan MessageInterceptor SDK penerima Web, Anda dapat menentukan MediaStatusWriter di MediaManager untuk melakukan modifikasi tambahan pada MediaStatus sebelum disiarkan ke pengirim yang terhubung.

Misalnya, Anda dapat menyetel data khusus di MediaStatus sebelum mengirim ke pengirim seluler:

MediaManager mediaManager = castReceiverContext.getMediaManager();
...

// Use MediaStatusInterceptor to process the MediaStatus before sending out.
mediaManager.setMediaStatusInterceptor(mediaStatusWriter -> {
    try {
        mediaStatusWriter.setCustomData(new JSONObject("{myData: 'CustomData'}"));
    } catch (JSONException e) {
        e.printStackTrace();
    }
});

Kini Anda telah mengetahui cara mengaktifkan Cast aplikasi Android TV menggunakan Cast Connect Library.

Lihat panduan developer untuk keterangan selengkapnya: https://developers.google.com/cast/docs/android_tv_receiver