Premiers pas avec CastPlayer

CastPlayer est une implémentation de Player Jetpack Media3 qui prend en charge la lecture locale et la diffusion sur un appareil compatible Cast distant. CastPlayer simplifie l'ajout de la fonctionnalité Cast à votre application et fournit des fonctionnalités enrichies pour basculer facilement entre la lecture locale et la lecture à distance. Ce guide vous explique comment intégrer CastPlayer à votre application multimédia.

Pour intégrer Cast à d'autres plates-formes, consultez la page SDK Cast.

Se procurer un appareil compatible Cast

Pour tester CastPlayer, vous avez besoin d'un appareil compatible Cast. Les options incluent Android TV, Chromecast, les enceintes intelligentes et les écrans connectés. Vérifiez que votre appareil est configuré et connecté au même réseau Wi-Fi que votre mobile de développement pour la découverte.

Ajouter des dépendances de build

Pour commencer à utiliser CastPlayer, ajoutez les dépendances AndroidX Media3 et CastPlayer au fichier build.gradle de votre module d'application.

Kotlin

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

Groovy

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

Configurer votre CastPlayer

Pour configurer CastPlayer, mettez à jour votre fichier AndroidManifest.xml avec un fournisseur d'options.

Fournisseur d'options

CastPlayer nécessite un fournisseur d'options pour configurer son comportement. Pour une configuration de base, vous pouvez utiliser DefaultCastOptionsProvider en l'ajoutant à votre fichier AndroidManifest.xml. Cette option utilise les paramètres par défaut, y compris l'application réceptrice par défaut.

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

Pour personnaliser la configuration, implémentez votre propre OptionsProvider personnalisé. Pour savoir comment procéder, consultez le guide CastOptions.

Ajouter un récepteur pour les transferts de contenus multimédias

L'ajout d'un MediaTransferReceiver à votre fichier manifeste permet à l'UI du système de détecter les appareils compatibles Cast sur le réseau et de rediriger le contenu multimédia sans ouvrir l'activité de l'application. Par exemple, un utilisateur peut changer l'appareil qui lit le contenu multimédia de votre application à partir de la notification multimédia.

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

Créer un CastPlayer

Pour la lecture à distance avec Cast, votre application doit pouvoir gérer la lecture même lorsque l'utilisateur n'interagit pas avec une activité de votre application, par exemple via la notification multimédia du système. C'est pourquoi vous devez créer vos instances ExoPlayer (pour la lecture locale) et CastPlayer (pour la lecture à distance) dans un service, tel que MediaSessionService ou MediaLibraryService. Commencez par créer votre instance ExoPlayer, puis, lors de la compilation de votre instance CastPlayer, définissez ExoPlayer comme instance de lecteur local. Vous pouvez ensuite basculer la lecture multimédia entre votre mobile et l'appareil compatible Cast depuis la notification multimédia ou la notification sur l'écran de verrouillage. Media3 utilise la fonctionnalité Sélecteur de sortie pour gérer les transferts de lecteur lorsque la route de sortie passe de locale à distante ou de distante à locale.

Capture d'écran montrant l'interface utilisateur du sélecteur de sortie dans les notifications.
Figure 1 : (a) Chip de l'appareil sur la notification multimédia (b) Appareils compatibles Cast affichés lorsque vous appuyez sur le chip de l'appareil (c) Chip de l'appareil sur la notification de l'écran de verrouillage

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();
}

Ajouter des éléments d'interface utilisateur

Ajoutez un MediaRouteButton à l'UI de votre application. Appuyer sur MediaRouteButton ouvre une boîte de dialogue affichant la liste des appareils compatibles Cast disponibles sur le réseau. Lorsque l'utilisateur sélectionne un appareil, la lecture du contenu multimédia est transférée du mobile vers l'appareil récepteur sélectionné. Cette section explique comment ajouter le bouton et écouter les événements pour mettre à jour votre UI lorsque la lecture bascule entre les appareils locaux et distants.

Définir le MediaRouteButton

Il existe quatre façons d'ajouter MediaRouteButton à l'interface utilisateur de votre activité. Le meilleur choix dépend de la conception et des exigences de votre application.

  • UI Compose : ajoutez un composable de bouton.
  • UI de Views :
    • Ajoutez le bouton au menu de la barre d'application.
    • Ajoutez le bouton dans PlayerView.
    • Ajoutez le bouton en tant que View standard.
Capture d'écran montrant le MediaRouteButton dans l'UI.
Figure 2 : (a) MediaRouteButton dans la barre de menu, (b) en tant que vue, (c) dans PlayerView et (d) boîte de dialogue des appareils compatibles Cast.

Ajouter un composable MediaRouteButton au player

Vous pouvez ajouter le composable MediaRouteButton à l'UI de votre lecteur. Pour en savoir plus, consultez le guide 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) {
  // ...
}

Ajouter le MediaRouteButton à la PlayerView

Vous pouvez ajouter le MediaRouteButton directement dans les commandes d'interface utilisateur de PlayerView. Après avoir défini le MediaController comme lecteur pour votre PlayerView, fournissez un MediaRouteButtonViewProvider pour afficher l'icône Cast sur le lecteur.

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());
}

Ajouter MediaRouteButton au menu de la barre d'application

Pour configurer un MediaRouteButton dans le menu de la barre d'application, créez un menu XML et remplacez onCreateOptionsMenu dans votre 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;
}

Ajoutez MediaRouteButton en tant que vue.

Vous pouvez configurer un MediaRouteButton dans le fichier layout.xml de votre activité.

  <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" />

Pour terminer la configuration de MediaRouteButton, utilisez le MediaRouteButtonFactory Media3 Cast dans votre code Activity.

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);
}

Écouteur d'activité

Créez un Player.Listener dans votre Activity pour écouter les modifications apportées à l'emplacement de lecture du contenu multimédia. Lorsque la valeur de playbackType passe de PLAYBACK_TYPE_LOCAL à PLAYBACK_TYPE_REMOTE, vous pouvez ajuster votre UI si nécessaire. Pour éviter les fuites de mémoire et limiter l'activité de l'écouteur uniquement lorsque votre application est visible, enregistrez l'écouteur dans onStart et annulez son enregistrement dans 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);
}

Pour en savoir plus sur l'écoute et la réponse aux événements de lecture, consultez le guide sur les événements du lecteur.