Cómo comenzar a usar CastPlayer

CastPlayer es una implementación de Player de Jetpack Media3 que admite la reproducción local y la transmisión a un dispositivo remoto compatible con Cast. CastPlayer simplifica la adición de la funcionalidad de transmisión a tu app y proporciona funciones enriquecidas para alternar sin problemas entre la reproducción local y la remota. En esta guía, se muestra cómo integrar CastPlayer en tu app de medios.

Para integrar Cast con otras plataformas, consulta el SDK de Cast.

Agrega CastPlayer como dependencia

Para comenzar a usar CastPlayer, agrega las dependencias de AndroidX Media3 y CastPlayer que necesites en el archivo build.gradle del módulo de tu app.

Kotlin

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

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.0-alpha01"
implementation "androidx.media3:media3-ui:1.9.0-alpha01"
implementation "androidx.media3:media3-session:1.9.0-alpha01"
implementation "androidx.media3:media3-cast:1.9.0-alpha01"

Consulta las notas de la versión de Jetpack Media para encontrar la versión alfa más reciente y poder integrar CastPlayer en tu app. Todos los módulos deben tener la misma versión.

Para obtener más información sobre los módulos de biblioteca disponibles, consulta la página de Google Maven AndroidX Media3.

Configura tu CastPlayer

Para configurar CastPlayer, actualiza tu archivo AndroidManifest.xml con un proveedor de opciones.

Proveedor de opciones

El CastPlayer requiere un proveedor de opciones para configurar su comportamiento. Para una configuración básica, puedes usar el proveedor de opciones predeterminado agregándolo a tu archivo AndroidManifest.xml. Esto usa la configuración predeterminada, incluida la aplicación del receptor predeterminada.

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

Para personalizar la configuración, implementa tu propio OptionsProvider personalizado. Consulta la guía de CastOptions para obtener más información.

Agrega un receptor para las transferencias de contenido multimedia

Agregar un MediaTransferReceiver a tu manifiesto permite que la IU del sistema redireccione el contenido multimedia sin abrir la actividad de la app. Por ejemplo, un usuario puede cambiar el dispositivo que reproduce el contenido multimedia de tu app desde la notificación de medios.

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

Compila un CastPlayer

Para la reproducción remota con Cast, tu app debe poder administrar la reproducción incluso cuando el usuario no interactúa con una actividad de tu app, por ejemplo, a través de la notificación de medios del sistema. Por este motivo, debes crear tus instancias de ExoPlayer (para la reproducción local) y CastPlayer (para la reproducción remota) en un servicio, como MediaSessionService o MediaLibraryService. Primero, crea tu instancia de ExoPlayer y, luego, cuando compiles tu instancia de CastPlayer, establece ExoPlayer como la instancia del reproductor local. Luego, Media3 podrá controlar las transferencias del reproductor cuando la ruta de salida cambie de local a remota o de remota a local.

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

Cómo agregar elementos de la IU

Agrega un MediaRouteButton a la IU de tu app para permitir que los usuarios seleccionen un dispositivo Cast. En esta sección, se muestra cómo agregar el botón y escuchar los eventos para actualizar tu IU cuando la reproducción cambia entre dispositivos locales y remotos.

Cómo configurar el MediaRouteButton

Existen cuatro métodos posibles para agregar el MediaRouteButton a la IU de tu actividad para que los usuarios interactúen con él. La elección dependerá de cómo quieras que se vea y funcione la IU de la actividad del reproductor.

Agrega un botón de ruta de contenido multimedia componible al reproductor

Puedes agregar el elemento MediaRouteButton componible a la IU del reproductor. Para obtener más información, consulta la guía de redacción.

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) {
  ...
}

Agrega el botón de ruta de contenido multimedia a PlayerView

Puedes agregar el MediaRouteButton directamente en los controles de la IU de PlayerView. Después de configurar el MediaController como el reproductor de tu PlayerView, proporciona un MediaRouteButtonViewProvider para mostrar el botón de Cast en el reproductor.

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

Agrega el botón de ruta de contenido multimedia al menú de la barra de la app

Este método configura un botón de ruta de contenido multimedia en el menú de la barra de la app. Se necesitan actualizaciones tanto en el archivo de manifiesto como en Activity para mostrar este estilo de botón.

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

Agrega el botón de ruta de contenido multimedia como una View

También puedes configurar un MediaRouteButton en tu archivo layout.xml de la actividad. Para completar la configuración de MediaRouteButton, usa MediaRouteButtonFactory de Media3 Cast en tu código de 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) {
    ...
    MediaRouteButton button = findViewById(R.id.media_route_button);
    ListenableFuture<Void> setUpFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

Activity Listener

Crea un Player.Listener en tu Activity para detectar cambios en la ubicación de reproducción de contenido multimedia. Cuando el playbackType cambia entre PLAYBACK_TYPE_LOCAL y PLAYBACK_TYPE_REMOTE, puedes ajustar la IU según sea necesario. Para evitar fugas de memoria y limitar la actividad del objeto de escucha solo cuando tu app esté visible, registra el objeto de escucha en onStart y anula su registro en 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);
}

Para obtener más información sobre cómo escuchar y responder a eventos de reproducción, consulta la guía de eventos del reproductor.