El 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.
Obtén un dispositivo compatible con Cast
Para probar CastPlayer, necesitas un dispositivo compatible con Cast. Entre las opciones, se incluyen Android TV, Chromecast, bocinas inteligentes y pantallas inteligentes. Verifica que tu dispositivo esté configurado y conectado a la misma red Wi-Fi que tu dispositivo móvil de desarrollo para la detección.
Cómo agregar dependencias de compilación
Para comenzar a usar CastPlayer, agrega las dependencias de AndroidX Media3 y CastPlayer al archivo build.gradle del módulo de tu app.
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"
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 DefaultCastOptionsProvider agregándolo a tu archivo AndroidManifest.xml. Se 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 descubra dispositivos compatibles con Cast en la red y redireccione 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 jugador local. Luego, puedes cambiar la reproducción de contenido multimedia entre tu dispositivo móvil y el dispositivo compatible con Cast desde la notificación de contenido multimedia o la notificación de la pantalla de bloqueo. Media3 usa la función Output Switcher para controlar las transferencias del reproductor cuando la ruta de salida cambia 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. Si presionas MediaRouteButton, se abrirá un diálogo en el que se mostrará una lista de los dispositivos disponibles compatibles con Cast en la red. Cuando el usuario selecciona un dispositivo, la reproducción de contenido multimedia se transfiere del dispositivo móvil al receptor seleccionado. En esta sección, se muestra cómo agregar el botón y escuchar los eventos para actualizar la IU cuando la reproducción cambia entre dispositivos locales y remotos.
Cómo configurar el MediaRouteButton
Existen cuatro formas de agregar MediaRouteButton a la IU de tu actividad. La mejor opción depende del diseño y los requisitos de tu app.
- IU de Compose: Agrega un elemento componible de botón.
- IU de Views:
- Agrega el botón al menú de la barra de la app.
- Agrega el botón dentro de
PlayerView. - Agrega el botón como un
Viewestándar.
Agrega un elemento MediaRouteButton 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 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) { ... }
Agrega MediaRouteButton 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 MediaRouteButton al menú de la barra de la aplicación
Para configurar un MediaRouteButton en el menú de la barra de la app, crea un menú XML y anula onCreateOptionsMenu en tu 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) ... }
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 MediaRouteButton como vista
Puedes configurar un MediaRouteButton en tu archivo layout.xml de la actividad.
<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" />
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); }
Objeto de escucha de actividad
Crea un Player.Listener en tu Activity para detectar cambios en la ubicación de reproducción de medios. 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 los eventos de reproducción, consulta la guía de eventos del reproductor.