Iniziare a utilizzare CastPlayer

CastPlayer è un'implementazione di Player di Jetpack Media3 che supporta sia la riproduzione locale che la trasmissione a un dispositivo compatibile con Google Cast remoto. CastPlayer semplifica l'aggiunta della funzionalità Cast alla tua app e offre funzionalità avanzate per cambio fluido tra riproduzione locale e remota. Questa guida mostra come integrare CastPlayer nella tua app multimediale.

Per integrare Cast con altre piattaforme, consulta l'SDK Cast.

Acquista un dispositivo compatibile con Google Cast

Per testare CastPlayer, devi disporre di un dispositivo compatibile con Google Cast. Le opzioni includono Android TV, Chromecast, smart speaker e smart display. Verifica che il dispositivo sia configurato e connesso alla stessa rete Wi-Fi del dispositivo mobile di sviluppo per il rilevamento.

Aggiungi dipendenze build

Per iniziare a utilizzare CastPlayer, aggiungi le dipendenze AndroidX Media3 e CastPlayer al file build.gradle del modulo dell'app.

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

Alla moda

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"

Configura CastPlayer

Per configurare CastPlayer, aggiorna il file AndroidManifest.xml con un provider di opzioni.

Provider di opzioni

CastPlayer richiede un provider di opzioni per configurare il suo comportamento. Per una configurazione di base, puoi utilizzare DefaultCastOptionsProvider aggiungendolo al file AndroidManifest.xml. Vengono utilizzate le impostazioni predefinite, inclusa l'applicazione ricevitore predefinita.

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

Per personalizzare la configurazione, implementa il tuo OptionsProvider personalizzato. Per scoprire come fare, consulta la guida CastOptions.

Aggiungi un ricevitore per i trasferimenti di contenuti multimediali

L'aggiunta di un MediaTransferReceiver al manifest consente alla UI di sistema di rilevare i dispositivi compatibili con Google Cast sulla rete e di cambiare percorso dei contenuti multimediali senza aprire l'attività dell'app. Ad esempio, un utente può cambiare il dispositivo che riproduce i contenuti multimediali della tua app dalla notifica dei contenuti multimediali.

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

Crea un CastPlayer

Per la riproduzione remota con Cast, l'app deve essere in grado di gestire la riproduzione anche quando l'utente non interagisce con un'attività dell'app, ad esempio tramite la notifica dei contenuti multimediali di sistema. Per questo motivo, devi creare le istanze di ExoPlayer (per la riproduzione locale) e CastPlayer (per la riproduzione remota) in un servizio, ad esempio MediaSessionService o MediaLibraryService. Innanzitutto, crea l'istanza ExoPlayer, quindi, quando crei l'istanza CastPlayer, imposta ExoPlayer come istanza del player locale. Puoi quindi passare dalla riproduzione di contenuti multimediali sul tuo dispositivo mobile a quella sul dispositivo compatibile con Google Cast dalla notifica dei contenuti multimediali o dalla notifica della schermata di blocco. Media3 utilizza la funzionalità Selettore di output per gestire i trasferimenti del player quando il percorso di output cambia da locale a remoto o da remoto a locale.

Screenshot che mostra l'interfaccia utente del selettore di output nelle notifiche.
Figura 1: (a) Chip del dispositivo nella notifica multimediale (b) Dispositivi compatibili con Google Cast mostrati quando si tocca il chip del dispositivo (c) Chip del dispositivo nella notifica della schermata di blocco

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

Aggiungi elementi UI

Aggiungi un MediaRouteButton alla UI della tua app. Se tocchi MediaRouteButton, si apre una finestra di dialogo che mostra un elenco di dispositivi compatibili con Google Cast disponibili sulla rete. Quando l'utente seleziona un dispositivo, la riproduzione dei contenuti multimediali viene trasferita dal dispositivo mobile al dispositivo ricevitore selezionato. Questa sezione mostra come aggiungere il pulsante e rimanere in ascolto degli eventi per aggiornare la UI quando la riproduzione passa da un dispositivo locale a un dispositivo remoto e viceversa.

Imposta MediaRouteButton

Esistono quattro modi per aggiungere MediaRouteButton alla UI dell'attività. La scelta migliore dipende dal design e dai requisiti della tua app.

  • UI di Compose: aggiungi un pulsante componibile.
  • UI di Views:
    • Aggiungi il pulsante al menu della barra dell'app.
    • Aggiungi il pulsante all'interno di PlayerView.
    • Aggiungi il pulsante come View standard.
Screenshot che mostra il pulsante MediaRouteButton nell'interfaccia utente.
Figura 2: (a) MediaRouteButton nella barra dei menu, (b) come View, (c) in PlayerView e (d) finestra di dialogo dei dispositivi compatibili con Google Cast.

Aggiungi un Composable MediaRouteButton al Player

Puoi aggiungere il componibile MediaRouteButton alla UI del player. Per saperne di più, consulta la guida di 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) {
  // ...
}

Aggiungi MediaRouteButton a PlayerView

Puoi aggiungere MediaRouteButton direttamente nei controlli UI di PlayerView. Dopo aver impostato MediaController come player per PlayerView, fornisci un MediaRouteButtonViewProvider per visualizzare il pulsante Trasmetti sul player.

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

Aggiungi MediaRouteButton al menu della barra delle app

Per configurare un MediaRouteButton nel menu della barra dell'app, crea un menu XML ed esegui l'override di onCreateOptionsMenu in 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;
}

Aggiungi MediaRouteButton come visualizzazione

Puoi configurare un MediaRouteButton nel file layout.xml dell'attività.

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

Per completare la configurazione di MediaRouteButton, utilizza Media3 Cast MediaRouteButtonFactory nel codice 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);
}

Listener di attività

Crea un Player.Listener nel tuo Activity per ascoltare le modifiche alla posizione di riproduzione dei contenuti multimediali. Quando il valore di playbackType cambia tra PLAYBACK_TYPE_LOCAL e PLAYBACK_TYPE_REMOTE, puoi regolare la UI in base alle tue esigenze. Per evitare perdite di memoria e limitare l'attività del listener solo quando l'app è visibile, registra il listener in onStart e annulla la registrazione in 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);
}

Per saperne di più sull'ascolto e sulla risposta agli eventi di riproduzione, consulta la guida agli eventi del player.