CastPlayer は、ローカル再生とリモートの Cast 対応デバイスへのキャストの両方をサポートする Jetpack Media3 プレーヤー の実装です。CastPlayer
を使用すると、キャスト機能をアプリに簡単に追加でき、ローカル再生とリモート再生をシームレスに切り替えるための豊富な機能を利用できます。このガイドでは、メディアアプリに
CastPlayer を統合する方法について説明します。
Cast を他のプラットフォームと統合するには、Cast SDK をご覧ください。
Cast 対応デバイスを入手する
CastPlayer をテストするには、Cast 対応デバイスが必要です。Android TV、Chromecast、スマート
スピーカー、スマート ディスプレイなどがあります。デバイスが設定され、検出のために開発用モバイルと同じ Wi-Fi
ネットワークに接続されていることを確認します。
ビルド依存関係を追加する
CastPlayer の使用を開始するには、AndroidX Media3 と CastPlayer の依存関係をアプリ モジュールの
build.gradle ファイルに追加します。
Kotlin
implementation("androidx.media3:media3-exoplayer:1.10.0")
implementation("androidx.media3:media3-ui:1.10.0")
implementation("androidx.media3:media3-session:1.10.0")
implementation("androidx.media3:media3-cast:1.10.0")
Groovy
implementation "androidx.media3:media3-exoplayer:1.10.0"
implementation "androidx.media3:media3-ui:1.10.0"
implementation "androidx.media3:media3-session:1.10.0"
implementation "androidx.media3:media3-cast:1.10.0"
CastPlayer を構成する
CastPlayer を構成するには、AndroidManifest.xml ファイルを
オプション プロバイダを使用して更新します。
オプション プロバイダ
CastPlayer は、動作を構成するためにオプション プロバイダを必要とします。基本的な設定では、DefaultCastOptionsProviderファイルに追加して
AndroidManifest.xmlを使用できます。これにより、デフォルトのレシーバー アプリケーションなど、デフォルトの設定が使用されます。
<application>
...
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
...
</application>
構成をカスタマイズするには、独自のカスタム OptionsProvider を実装します。方法については、CastOptionsガイドをご覧ください。
メディア転送用のレシーバーを追加する
MediaTransferReceiver をマニフェストに追加すると、システム UI はネットワーク上の Cast 対応デバイスを検出し、アプリのアクティビティを開かずにメディアを再ルーティングできます。たとえば、ユーザーはアプリの
メディアを再生するデバイスをメディア通知から変更できます。
<application>
...
<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
...
</application>
CastPlayer をビルドする
Cast を使用したリモート再生の場合、アプリは、ユーザーがシステム メディア通知などからアプリのアクティビティを操作していない場合でも、再生を管理できる必要があります。そのため、
ExoPlayer(ローカル再生用)インスタンスとCastPlayer(リモート再生用)
インスタンスは、MediaSessionService や MediaLibraryServiceなどのサービスで作成する必要があります。
まず、ExoPlayer インスタンスを作成し、
CastPlayer インスタンスをビルドするときに、ExoPlayer をローカル プレーヤー インスタンスとして設定します。これにより、メディア通知またはロック画面通知から、モバイルと
Cast 対応デバイスの間でメディア再生を切り替えることができます。出力ルートがローカルからリモート、またはリモートからローカルに変更された場合、Media3
は 出力スイッチャー 機能を使用してプレーヤーの転送を処理します。
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(); }
UI 要素を追加する
アプリの UI に MediaRouteButton を追加します。MediaRouteButton
をタップすると、
ネットワーク上の利用可能な Cast 対応デバイスのリストが表示されるダイアログが開きます。ユーザーがデバイスを選択すると、メディア再生がモバイルから選択したレシーバー
デバイスに転送されます。このセクションでは、ボタンを追加し、再生がローカル デバイスとリモート
デバイスの間で切り替わるときにイベントをリッスンして UI を更新する方法について説明します。
MediaRouteButton を設定する
アクティビティの UI に MediaRouteButton を追加する方法は 4 つあります。最適な選択肢は、アプリのデザインと要件によって異なります。
- Compose UI: ボタン コンポーザブルを追加します。
- Views UI:
- アプリバー メニューにボタンを追加します。
PlayerView内にボタンを追加します。- ボタンを標準の
Viewとして追加します。
コンポーザブル MediaRouteButton をプレーヤーに追加する
MediaRouteButton コンポーザブルをプレーヤーの UI に追加できます。詳しくは、Compose
ガイドをご覧ください。
@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) { // ... }
MediaRouteButton を PlayerView に追加する
MediaRouteButton は、PlayerView の UI
コントロール内に直接追加できます。MediaController を
PlayerView のプレーヤーとして設定したら、MediaRouteButtonViewProvider を指定して、プレーヤーにキャスト
ボタンを表示します。
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()); }
MediaRouteButton をアプリバー メニューに追加する
アプリバー メニューに MediaRouteButton を設定するには、XML メニューを作成し、
onCreateOptionsMenu で Activity をオーバーライドします。
<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, ) // ... return true }
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); // ... return true; }
MediaRouteButton を View として追加する
MediaRouteButton は、アクティビティの 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" />
MediaRouteButton の設定を完了するには、Activity コードで Media3 Cast
MediaRouteButtonFactory を使用します。
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) { super.onCreate(savedInstanceState); // ... MediaRouteButton button = findViewById(R.id.media_route_button); ListenableFuture<Void> setUpFuture = MediaRouteButtonFactory.setUpMediaRouteButton(context, button); }
アクティビティ リスナー
Activity で Player.Listener
を作成して、メディア再生場所の変更をリッスンします。playbackType が PLAYBACK_TYPE_LOCAL と
PLAYBACK_TYPE_REMOTE の間で変化する場合は、必要に応じて UI
を調整できます。メモリリークを防ぎ、リスナー アクティビティをアプリが表示されている場合にのみ制限するには、onStart
でリスナーを登録し、onStop で登録を解除します。
Kotlin
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
private final 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); }
再生イベントのリッスンと応答について詳しくは、 プレーヤー イベント ガイドをご覧ください。