Para usar o framework do MediaRouter no seu app, é preciso ter uma instância
do objeto MediaRouter
e anexar um
MediaRouter.Callback
para detectar eventos de roteamento.
O conteúdo enviado por um roteamento de mídia passa pelo
associado MediaRouteProvider
(exceto em alguns casos especiais,
como um dispositivo de saída Bluetooth). A Figura 1 mostra uma visualização de alto nível da
classes usadas para rotear conteúdo entre dispositivos.
Observação:se você quiser que seu app seja compatível Dispositivos com Google Cast, use o SDK do Cast e crie seu app como um remetente do Cast. Siga as instruções no Documentação do Google Cast em vez de usar o framework do MediaRouter diretamente.
Botão de roteamento de mídia
Apps para Android devem usar um botão de roteamento de mídia para fins de controle. O framework do MediaRouter fornece uma interface padrão para o botão, o que ajuda os usuários a reconhecer e usar o roteamento quando estão disponíveis. O botão de roteamento de mídia geralmente é colocado no lado direito a barra de ações do app, como mostrado na Figura 2.
Quando o usuário pressiona o botão de roteamento de mídia, os roteamentos disponíveis aparecem em uma lista, como mostrado na Figura 3.
Siga estas etapas para criar um botão de roteamento de mídia:
- Use uma AppCompatActivity.
- Defina o item de menu do botão de roteamento de mídia.
- Crie um MediaRouteSelector.
- Adicione o botão de roteamento de mídia à barra de ações.
- Crie e processe os métodos MediaRouter.Callback no ciclo de vida da sua atividade.
Essa seção descreve as quatro primeiras etapas. A seção seguinte descreve os métodos de callback.
Use uma AppCompatActivity.
Ao usar o framework do roteador de mídia em uma atividade, estenda
a atividade do AppCompatActivity
e importar
pacote androidx.appcompat.app
. Você deve adicionar o parâmetro
androidx.appCompat:appcompatibilidade (link em inglês)
e androidx.mediarouter:mediarouter.
bibliotecas de suporte ao seu projeto de desenvolvimento de aplicativos. Para mais informações sobre como adicionar bibliotecas de suporte,
ao projeto, consulte Introdução ao Android Jetpack.
Cuidado:use o androidx
implementação do framework do roteador de mídia. Não use o pacote android.media
mais antigo.
Definir o item de menu do botão de roteamento de mídia
Crie um arquivo XML que defina um item menu para o botão de rota de mídia.
A ação do item deve ser a classe MediaRouteActionProvider
.
Veja um exemplo de arquivo:
// myMediaRouteButtonMenuItem.xml <?xml version="1.0" encoding="utf-8"?> <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:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider" app:showAsAction="always" /> </menu>
Criar um MediaRouteSelector
Os roteamentos que aparecem no menu do botão de roteamento de mídia são determinados por um MediaRouteSelector
.
Ampliar a atividade do app AppCompatActivity
e criar o seletor quando a atividade for criada, chamando MediaRouteSelector.Builder
do método onCreate(), como mostrado abaixo.
no exemplo de código a seguir. O seletor é salvo em uma variável de classe, e os tipos de trajeto permitidos são especificados
adicionando objetos MediaControlIntent
:
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mSelector: MediaRouteSelector? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create a route selector for the type of routes your app supports. mSelector = MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build() } }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouteSelector mSelector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a route selector for the type of routes your app supports. mSelector = new MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build(); } }
Para a maioria dos aplicativos, o único
o tipo de trajeto necessário é CATEGORY_REMOTE_PLAYBACK
. Esse tipo de roteamento trata o dispositivo que está executando seu app como um controle remoto.
O dispositivo receptor conectado processa toda a recuperação, decodificação e reprodução dos dados de conteúdo.
É assim que os apps compatíveis com o Google Cast, como
Chromecast, trabalho.
Alguns fabricantes oferecem compatibilidade com uma opção de roteamento especial conhecida como "saída secundária". Com esse roteamento,
O app de mídia recupera, renderiza e faz streaming de vídeo ou música diretamente na tela e/ou nos alto-falantes do dispositivo receptor remoto selecionado.
Use a saída secundária para enviar conteúdo para sistemas de música ou telas de vídeo sem fio. Para ativar a descoberta e
uma seleção desses dispositivos, você precisa adicionar o
CATEGORY_LIVE_AUDIO
ou
CATEGORY_LIVE_VIDEO
categorias de controle de acesso ao MediaRouteSelector. Também é necessário criar e processar a própria caixa de diálogo Presentation
.
Adicionar o botão de roteamento de mídia à barra de ações
Com o menu de roteamento de mídia e o MediaRouteSelector definidos, é possível adicionar o botão de roteamento de mídia a uma atividade.
Substitua o método onCreateOptionsMenu()
em cada uma das atividades para adicionar opções.
.
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) // Inflate the menu and configure the media router action provider. menuInflater.inflate(R.menu.sample_media_router_menu, menu) // Attach the MediaRouteSelector to the menu item val mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item) val mediaRouteActionProvider = MenuItemCompat.getActionProvider(mediaRouteMenuItem) as MediaRouteActionProvider // Attach the MediaRouteSelector that you built in onCreate() selector?.also(mediaRouteActionProvider::setRouteSelector) // Return true to show the menu. return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Inflate the menu and configure the media router action provider. getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); // Attach the MediaRouteSelector to the menu item MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider)MenuItemCompat.getActionProvider( mediaRouteMenuItem); // Attach the MediaRouteSelector that you built in onCreate() mediaRouteActionProvider.setRouteSelector(selector); // Return true to show the menu. return true; }
Para mais informações sobre como implementar a barra de ações no seu app, consulte a barra de ações guia para desenvolvedores.
Também é possível adicionar um botão de roteamento de mídia como um MediaRouteButton
em qualquer
visualização. Você precisa anexar um MediaRouteSelector ao botão por meio do método setRouteSelector()
. Consulte a
Lista de verificação de design do Google Cast
para orientações sobre como incorporar o botão de roteamento de mídia em seu aplicativo.
Callbacks do MediaRouter
Todos os apps em execução no mesmo dispositivo compartilham uma única instância do MediaRouter
e as rotas dela.
(filtrados por app pelo MediaRouteSeletor do app). Cada atividade se comunica com o MediaRouter.
usando a própria implementação de MediaRouter.Callback
métodos. O MediaRouter chama os métodos de callback sempre que o usuário seleciona, muda ou desconecta um roteamento.
Há vários métodos no callback que você pode modificar para receber informações sobre
eventos de roteamento. No mínimo, sua implementação da classe MediaRouter.Callback
precisa substituir
onRouteSelected()
e
onRouteUnselected()
Como o MediaRouter é um recurso compartilhado, o app precisa gerenciar os callbacks do MediaRouter. em resposta aos callbacks habituais do ciclo de vida da atividade:
- Quando a atividade for criada (
onCreate(Bundle)
), pegue um ponteiro paraMediaRouter
e segure-o por todo o ciclo de vida do app. - Anexar callbacks ao MediaRouter quando a atividade se tornar visível (
onStart()
) e desanexá-los quando ela estiver ocultaonStop()
).
O exemplo de código a seguir demonstra como
criar e salvar o objeto de callback, como
ver uma instância de MediaRouter
e como gerenciar callbacks.
Observe o uso da sinalização CALLBACK_FLAG_REQUEST_DISCOVERY
ao anexar os callbacks em onStart()
.
Isso permite que o MediaRouteSelector atualize o link do botão de roteamento de mídia
lista de rotas disponíveis.
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mediaRouter: MediaRouter? = null private var mSelector: MediaRouteSelector? = null // Variables to hold the currently selected route and its playback client private var mRoute: MediaRouter.RouteInfo? = null private var remotePlaybackClient: RemotePlaybackClient? = null // Define the Callback object and its methods, save the object in a class variable private val mediaRouterCallback = object : MediaRouter.Callback() { override fun onRouteSelected(router: MediaRouter, route: MediaRouter.RouteInfo) { Log.d(TAG, "onRouteSelected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Stop local playback (if necessary) // ... // Save the new route mRoute = route // Attach a new playback client remotePlaybackClient = RemotePlaybackClient(this@MediaRouterPlaybackActivity, mRoute) // Start remote playback (if necessary) // ... } } override fun onRouteUnselected( router: MediaRouter, route: MediaRouter.RouteInfo, reason: Int ) { Log.d(TAG, "onRouteUnselected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Changed route: tear down previous client mRoute?.also { remotePlaybackClient?.release() remotePlaybackClient = null } // Save the new route mRoute = route when (reason) { MediaRouter.UNSELECT_REASON_ROUTE_CHANGED -> { // Resume local playback (if necessary) // ... } } } } } // Retain a pointer to the MediaRouter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Get the media router service. mediaRouter = MediaRouter.getInstance(this) ... } // Use this callback to run your MediaRouteSelector to generate the // list of available media routes override fun onStart() { mSelector?.also { selector -> mediaRouter?.addCallback(selector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY) } super.onStart() } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. override fun onStop() { mediaRouter?.removeCallback(mediaRouterCallback) super.onStop() } ... }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouter mediaRouter; private MediaRouteSelector mSelector; // Variables to hold the currently selected route and its playback client private MediaRouter.RouteInfo mRoute; private RemotePlaybackClient remotePlaybackClient; // Define the Callback object and its methods, save the object in a class variable private final MediaRouter.Callback mediaRouterCallback = new MediaRouter.Callback() { @Override public void onRouteSelected(MediaRouter router, RouteInfo route) { Log.d(TAG, "onRouteSelected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Stop local playback (if necessary) // ... // Save the new route mRoute = route; // Attach a new playback client remotePlaybackClient = new RemotePlaybackClient(this, mRoute); // Start remote playback (if necessary) // ... } } @Override public void onRouteUnselected(MediaRouter router, RouteInfo route, int reason) { Log.d(TAG, "onRouteUnselected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Changed route: tear down previous client if (mRoute != null && remotePlaybackClient != null) { remotePlaybackClient.release(); remotePlaybackClient = null; } // Save the new route mRoute = route; if (reason != MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) { // Resume local playback (if necessary) // ... } } } } // Retain a pointer to the MediaRouter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the media router service. mediaRouter = MediaRouter.getInstance(this); ... } // Use this callback to run your MediaRouteSelector to generate the list of available media routes @Override public void onStart() { mediaRouter.addCallback(mSelector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); super.onStart(); } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. @Override public void onStop() { mediaRouter.removeCallback(mediaRouterCallback); super.onStop(); } ... }
O framework do roteador de mídia também oferece
classe MediaRouteDiscoveryFragment
, que cuida de adicionar e
removendo o callback de uma atividade.
Observação:se você estiver criando um app de reprodução de música e quiser que ele seja reproduzido
música em segundo plano, você precisa criar uma Service
para reprodução
e chamar o framework do roteador de mídia nos callbacks do ciclo de vida do serviço.
Controlar um roteamento de reprodução remota
Quando você seleciona um roteamento de reprodução remota, seu app funciona como um controle remoto. O dispositivo na outra extremidade do trajeto
lida com todas as funções de recuperação, decodificação e reprodução de dados de conteúdo. Os controles na IU do seu app se comunicam com o dispositivo receptor usando um
RemotePlaybackClient
.
A classe RemotePlaybackClient
fornece outros métodos
para gerenciar a reprodução de conteúdo. Veja alguns dos principais métodos de reprodução da classe RemotePlaybackClient
:
play()
: reproduz uma música específica arquivo de mídia, especificado por umUri
.pause()
: pause o faixa de mídia em reprodução no momento.resume()
— Continuar a reprodução da faixa atual após um comando de pausa.seek()
: mover para um local específico na faixa atual.release()
: elimine o conexão do seu app com o dispositivo de reprodução remota.
É possível usar esses métodos para anexar ações aos controles de mídia fornecidos no app. A maioria desses métodos também permite incluir um objeto de callback para que você possa monitorar o progresso da tarefa de reprodução ou solicitação de controle.
A classe RemotePlaybackClient
também aceita o enfileiramento de
vários itens de mídia para reprodução e gerenciamento da fila de mídia.
Exemplo de código
O BasicMediaRouter do Android e MediaRouter Os exemplos demonstram ainda mais o uso da API MediaRouter.