O CastPlayer é uma implementação do Player do Jetpack Media3 que oferece suporte à
reprodução local e à transmissão para um dispositivo remoto compatível com Cast. O CastPlayer
simplifica a adição da funcionalidade de transmissão ao seu app e oferece recursos avançados para
alternar entre a reprodução local e remota sem problemas. Este guia mostra como integrar CastPlayer ao seu app de mídia.
Para integrar o Cast a outras plataformas, consulte o SDK do Cast.
Ter um dispositivo compatível com Cast
Para testar o CastPlayer, você precisa de um dispositivo compatível com Cast. As opções incluem Android TV, Chromecast, alto-falantes e smart displays. Verifique se o dispositivo está configurado e conectado à mesma rede Wi-Fi que o dispositivo móvel de desenvolvimento para descoberta.
Adicionar dependências de compilação
Para começar a usar CastPlayer, adicione as dependências do AndroidX Media3 e CastPlayer
ao arquivo build.gradle do módulo do 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"
Configurar o CastPlayer
Para configurar o CastPlayer, atualize o arquivo AndroidManifest.xml com um
provedor de opções.
Provedor de opções
O CastPlayer exige um provedor de opções para configurar o comportamento dele. Para uma
configuração básica, use o DefaultCastOptionsProvider adicionando-o ao arquivo
AndroidManifest.xml. Isso usa as configurações padrão, incluindo o aplicativo
receptor padrão.
<application>
...
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
...
</application>
Para personalizar a configuração, implemente seu próprio OptionsProvider personalizado. Consulte o guia CastOptions para saber como.
Adicionar um receptor para transferências de mídia
Adicionar um MediaTransferReceiver ao manifesto permite que a interface do sistema
descubra dispositivos compatíveis com Cast na rede e redirecione a mídia sem abrir
a atividade do app. Por exemplo, um usuário pode mudar o dispositivo que está reproduzindo a mídia do seu app na notificação de mídia.
<application>
...
<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
...
</application>
Criar um CastPlayer
Para reprodução remota com o Cast, o app precisa gerenciar a reprodução mesmo
quando o usuário não está interagindo com uma atividade do app, como por
meio da notificação de mídia do sistema. Por isso, crie suas instâncias
ExoPlayer (para reprodução local) e CastPlayer (para reprodução remota)
em um serviço, como MediaSessionService ou MediaLibraryService.
Primeiro, crie a instância ExoPlayer e, ao criar a instância CastPlayer, defina ExoPlayer como a instância do jogador local. Depois, é possível alternar a reprodução de mídia entre o dispositivo móvel e o dispositivo compatível com Cast na notificação de mídia ou na tela de bloqueio. A Media3 usa o recurso Output
Switcher para processar transferências de player quando a rota de saída muda de
local para remota ou de remota para 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(); }
Adicionar elementos da interface
Adicione um MediaRouteButton à interface do app. Ao tocar em MediaRouteButton, uma caixa de diálogo será aberta com uma lista de dispositivos compatíveis com Cast disponíveis na rede. Quando o usuário seleciona um dispositivo, a reprodução de mídia é transferida do
dispositivo móvel para o receptor selecionado. Esta seção mostra como adicionar
o botão e detectar eventos para atualizar a interface quando a reprodução muda
entre dispositivos locais e remotos.
Definir o MediaRouteButton
Há quatro maneiras de adicionar o MediaRouteButton à interface da sua atividade. A melhor escolha depende do design e dos requisitos do seu app.
- Compose UI: adicione um elemento combinável de botão.
- Interface de visualizações:
- Adicione o botão ao menu da barra de apps.
- Adicione o botão dentro de
PlayerView. - Adicione o botão como um
Viewpadrão.
Adicionar um elemento combinável MediaRouteButton ao jogador
Você pode adicionar o elemento combinável MediaRouteButton à interface do player. Para mais informações, consulte o guia do 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) { ... }
Adicionar o MediaRouteButton ao PlayerView
Você pode adicionar o MediaRouteButton diretamente nos controles da interface do PlayerView. Depois de definir o MediaController como o player do seu
PlayerView, forneça um MediaRouteButtonViewProvider para mostrar o botão
Cast no 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()); }
Adicionar o MediaRouteButton ao menu da barra de apps
Para configurar um MediaRouteButton no menu da barra de apps, crie um menu XML e
substitua onCreateOptionsMenu no seu 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); ... }
Adicione MediaRouteButton como uma visualização
Você pode configurar um MediaRouteButton no layout.xml da sua atividade.
<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 concluir a configuração do MediaRouteButton, use o MediaRouteButtonFactory do Media3 Cast no seu código 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); }
Listener de atividade
Crie um Player.Listener no seu Activity para detectar mudanças no local de
reprodução de mídia. Quando o playbackType muda entre PLAYBACK_TYPE_LOCAL
e PLAYBACK_TYPE_REMOTE, você pode ajustar a interface conforme necessário. Para evitar vazamentos de memória e restringir a atividade do listener apenas quando o app estiver visível, registre o listener em onStart e cancele o registro em 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 mais informações sobre como detectar e responder a eventos de reprodução, consulte o guia de eventos do player.