Mulai menggunakan CastPlayer

CastPlayer adalah implementasi Player Jetpack Media3 yang mendukung pemutaran lokal dan transmisi ke perangkat jarak jauh yang kompatibel untuk Cast. CastPlayer menyederhanakan penambahan fungsi transmisi ke aplikasi Anda dan menyediakan fitur lengkap untuk beralih dengan lancar antara pemutaran lokal dan jarak jauh. Panduan ini menunjukkan cara mengintegrasikan CastPlayer ke dalam aplikasi media Anda.

Untuk mengintegrasikan Cast dengan platform lain, lihat Cast SDK.

Mendapatkan perangkat yang kompatibel untuk Cast

Untuk menguji CastPlayer, Anda memerlukan perangkat yang kompatibel dengan Cast. Pilihannya mencakup Android TV, Chromecast, speaker smart, dan layar smart. Pastikan perangkat Anda telah disiapkan dan terhubung ke jaringan Wi-Fi yang sama dengan perangkat seluler pengembangan Anda untuk penemuan.

Menambahkan dependensi build

Untuk mulai menggunakan CastPlayer, tambahkan dependensi AndroidX Media3 dan CastPlayer ke file build.gradle modul aplikasi Anda.

Kotlin

implementation("androidx.media3:media3-exoplayer:1.9.2")
implementation("androidx.media3:media3-ui:1.9.2")
implementation("androidx.media3:media3-session:1.9.2")
implementation("androidx.media3:media3-cast:1.9.2")

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.2"
implementation "androidx.media3:media3-ui:1.9.2"
implementation "androidx.media3:media3-session:1.9.2"
implementation "androidx.media3:media3-cast:1.9.2"

Mengonfigurasi CastPlayer

Untuk mengonfigurasi CastPlayer, perbarui file AndroidManifest.xml Anda dengan penyedia opsi.

Penyedia opsi

CastPlayer memerlukan penyedia opsi untuk mengonfigurasi perilakunya. Untuk penyiapan dasar, Anda dapat menggunakan DefaultCastOptionsProvider dengan menambahkannya ke file AndroidManifest.xml. Tindakan ini menggunakan setelan default, termasuk aplikasi penerima default.

<application>
  ...
  <meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
  ...
</application>

Untuk menyesuaikan konfigurasi, terapkan OptionsProvider kustom Anda sendiri. Lihat panduan CastOptions untuk mempelajari caranya.

Menambahkan penerima untuk transfer media

Menambahkan MediaTransferReceiver ke manifes memungkinkan UI Sistem menemukan perangkat yang kompatibel untuk Cast di jaringan dan mengalihkan media tanpa membuka aktivitas aplikasi. Misalnya, pengguna dapat mengubah perangkat yang memutar media aplikasi Anda dari notifikasi media.

<application>
  ...
  <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
  ...
</application>

Membangun CastPlayer

Untuk pemutaran jarak jauh dengan Cast, aplikasi Anda harus dapat mengelola pemutaran meskipun pengguna tidak berinteraksi dengan Aktivitas dari aplikasi Anda, seperti melalui notifikasi media sistem. Oleh karena itu, Anda harus membuat instance ExoPlayer (untuk pemutaran lokal) dan CastPlayer (untuk pemutaran jarak jauh) di layanan, seperti MediaSessionService atau MediaLibraryService. Pertama, buat instance ExoPlayer Anda, lalu saat mem-build instance CastPlayer, tetapkan ExoPlayer sebagai instance pemutar lokal. Anda kemudian dapat mengalihkan pemutaran media antara perangkat seluler dan perangkat yang kompatibel untuk Cast dari notifikasi media atau notifikasi layar kunci. Media3 menggunakan fitur Pengalih Output untuk menangani transfer pemutar saat rute output berubah dari lokal ke jarak jauh atau dari jarak jauh ke lokal.

Screenshot yang menampilkan UI Pengalih Output di notifikasi.
Gambar 1: (a) Chip perangkat di notifikasi Media (b) Perangkat yang kompatibel untuk Cast ditampilkan saat chip perangkat diketuk (c) Chip perangkat di notifikasi Layar kunci

Kotlin

override fun onCreate() {
  super.onCreate()

  val exoPlayer = ExoPlayer.Builder(context).build()
  val castPlayer = CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build()

  mediaSession = MediaSession.Builder(context, castPlayer).build()
}

Java

@Override
public void onCreate() {
  super.onCreate();

  ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build();
  CastPlayer castPlayer = new CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build();

  mediaSession = new MediaSession.Builder(
    /* context= */ context, /* player= */ castPlayer).build();
}

Menambahkan elemen UI

Tambahkan MediaRouteButton ke UI aplikasi Anda. Mengetuk MediaRouteButton akan membuka dialog yang menampilkan daftar perangkat yang kompatibel untuk Cast yang tersedia di jaringan. Saat pengguna memilih perangkat, pemutaran media akan ditransfer dari perangkat seluler ke perangkat penerima yang dipilih. Bagian ini menunjukkan cara menambahkan tombol dan memproses peristiwa untuk memperbarui UI saat pemutaran beralih antara perangkat lokal dan jarak jauh.

Menetapkan MediaRouteButton

Ada empat cara untuk menambahkan MediaRouteButton ke UI aktivitas Anda. Pilihan terbaik bergantung pada desain dan persyaratan aplikasi Anda.

  • Compose UI: Tambahkan composable tombol.
  • UI Penayangan:
    • Tambahkan tombol ke menu panel aplikasi.
    • Tambahkan tombol di dalam PlayerView.
    • Tambahkan tombol sebagai View standar.
Screenshot yang menampilkan MediaRouteButton di UI.
Gambar 2: (a) MediaRouteButton di menu bar, (b) sebagai View, (c) di PlayerView, dan (d) Dialog perangkat yang kompatibel untuk Cast.

Menambahkan Composable MediaRouteButton ke Pemain

Anda dapat menambahkan Composable MediaRouteButton ke UI pemutar. Untuk informasi selengkapnya, lihat panduan Compose.

Kotlin

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.media3.cast.MediaRouteButton

@Composable
fun PlayerComposeView(player: Player, modifier: Modifier = Modifier) {
  var controlsVisible by remember { mutableStateOf(false) }

  Box(
    modifier = modifier.clickable { controlsVisible = true },
    contentAlignment = Alignment.Center,
  ) {
    PlayerSurface(player = player, modifier = modifier)
    AnimatedVisibility(visible = controlsVisible, enter = fadeIn(), exit = fadeOut()) {
      Box(modifier = Modifier.fillMaxSize()) {
        MediaRouteButton(modifier = Modifier.align(Alignment.TopEnd))
        PrimaryControls(player = player, modifier = Modifier.align(Alignment.Center))
      }
    }
  }
}

@Composable
fun PrimaryControls(player: Player, modifier: Modifier = Modifier) {
  ...
}

Tambahkan MediaRouteButton ke PlayerView

Anda dapat menambahkan MediaRouteButton langsung dalam kontrol UI PlayerView. Setelah menyetel MediaController sebagai pemutar untuk PlayerView, berikan MediaRouteButtonViewProvider untuk menampilkan tombol Cast di Pemutar.

Kotlin

override fun onStart() {
  super.onStart()

  playerView.player = mediaController
  playerView.setMediaRouteButtonViewProvider(MediaRouteButtonViewProvider())
}

Java

@Override
public void onStart() {
  super.onStart();

  playerView.setPlayer(mediaController);
  playerView.setMediaRouteButtonViewProvider(new MediaRouteButtonViewProvider());
}

Tambahkan MediaRouteButton ke menu panel aplikasi

Untuk menyiapkan MediaRouteButton di menu panel aplikasi, buat menu XML dan ganti onCreateOptionsMenu di Activity Anda.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:showAsAction="always"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
</menu>

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    ...
    menuInflater.inflate(R.menu.sample_media_route_button_menu, menu)
    val menuItemFuture: ListenableFuture<MenuItem> =
        MediaRouteButtonFactory.setUpMediaRouteButton(
            context, menu, R.id.media_route_menu_item)
    Futures.addCallback(
        menuItemFuture,
        object : FutureCallback<MenuItem> {
            override fun onSuccess(menuItem: MenuItem?) {
                // Do something with the menu item.
            }

            override fun onFailure(t: Throwable) {
                // Handle the failure.
            }
        },
        executor)
    ...
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    ...
    getMenuInflater().inflate(R.menu.sample_media_route_button_menu, menu);
    ListenableFuture<MenuItem> menuItemFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(
          context, menu, R.id.media_route_menu_item);
    Futures.addCallback(
        menuItemFuture,
        new FutureCallback<MenuItem>() {
          @Override
          public void onSuccess(MenuItem menuItem) {
            // Do something with the menu item.
          }

          @Override
          public void onFailure(Throwable t) {
            // Handle the failure.
          }
        },
        executor);
    ...
}

Tambahkan MediaRouteButton sebagai Tampilan

Anda dapat menyiapkan MediaRouteButton di activity layout.xml.

  <androidx.mediarouter.app.MediaRouteButton
      android:id="@+id/media_route_button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:mediaRouteButtonTint="@android:color/white" />

Untuk menyelesaikan penyiapan MediaRouteButton, gunakan MediaRouteButtonFactory Media3 Cast di kode Activity Anda.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  findViewById<MediaRouteButton>(R.id.media_route_button)?.also {
    val unused = MediaRouteButtonFactory.setUpMediaRouteButton(context, it)
  }
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    MediaRouteButton button = findViewById(R.id.media_route_button);
    ListenableFuture<Void> setUpFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

Pemroses Aktivitas

Buat Player.Listener di Activity untuk memproses perubahan pada lokasi pemutaran media. Saat playbackType berubah antara PLAYBACK_TYPE_LOCAL dan PLAYBACK_TYPE_REMOTE, Anda dapat menyesuaikan UI sesuai kebutuhan. Untuk mencegah kebocoran memori dan membatasi aktivitas pemroses hanya saat aplikasi Anda terlihat, daftarkan pemroses di onStart dan batalkan pendaftarannya di onStop:

Kotlin

import androidx.media3.common.DeviceInfo
import androidx.media3.common.Player

private val playerListener: Player.Listener =
  object : Player.Listener {
    override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) {
      if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
        // Add UI changes for local playback.
      } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
        // Add UI changes for remote playback.
      }
    }
  }

override fun onStart() {
  super.onStart()
  mediaController.addListener(playerListener)
}

override fun onStop() {
  super.onStop()
  mediaController.removeListener(playerListener)
}

Java

import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Player;

private Player.Listener playerListener =
    new Player.Listener() {
      @Override
      public void onDeviceInfoChanged(DeviceInfo deviceInfo) {
        if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
          // Add UI changes for local playback.
        } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
          // Add UI changes for remote playback.
        }
      }
    };

@Override
protected void onStart() {
  super.onStart();
  mediaController.addListener(playerListener);
}

@Override
protected void onStop() {
  super.onStop();
  mediaController.removeListener(playerListener);
}

Untuk mengetahui informasi selengkapnya tentang cara memproses dan merespons peristiwa pemutaran, lihat panduan peristiwa pemutar.