Per utilizzare il framework MediaRouter all'interno della tua app, devi ottenere un'istanza
dell'oggetto MediaRouter
e collegare un
oggetto MediaRouter.Callback
per l'ascolto degli eventi di routing.
I contenuti inviati attraverso un percorso multimediale passano attraverso il
MediaRouteProvider
associato al percorso (tranne in alcuni casi speciali,
ad esempio un dispositivo di output Bluetooth). La figura 1 offre una visione generale delle classi utilizzate per il routing dei contenuti tra dispositivi.
Nota: se vuoi che la tua app supporti i dispositivi Google Cast, devi utilizzare l'SDK Cast e creare l'app come mittente di trasmissione. Segui le istruzioni nella documentazione di Cast anziché utilizzare direttamente il framework MediaRouter.
Il pulsante Route multimediale
Le app per Android devono utilizzare un pulsante Percorso multimediale per controllare il routing multimediale. Il framework MediaRouter fornisce un'interfaccia standard per il pulsante, che consente agli utenti di riconoscere e utilizzare il routing quando è disponibile. Il pulsante del percorso multimediale si trova in genere sul lato destro della barra delle azioni dell'app, come mostrato nella Figura 2.
Quando l'utente preme il pulsante Percorso multimediale, i percorsi multimediali disponibili vengono visualizzati in un elenco, come mostrato nella figura 3.
Per creare un pulsante Percorso multimediale:
- Utilizzo di AppCompatActivity
- Definisci la voce di menu del pulsante Percorso multimediale
- Creazione di un MediaRouteSelector
- Aggiungere il pulsante Percorso multimediale alla barra delle azioni
- Crea e gestisci i metodi MediaRouter.Callback nel ciclo di vita dell'attività
In questa sezione vengono descritti i primi quattro passaggi. La sezione successiva descrive i metodi di callback.
Utilizzo di AppCompatActivity
Quando utilizzi il framework del router multimediale in un'attività, devi estendere l'attività da AppCompatActivity
e importare il pacchetto androidx.appcompat.app
. Devi aggiungere le librerie di supporto androidx.appcompat:appcompat e androidx.mediarouter:mediarouter al progetto di sviluppo dell'app. Per ulteriori informazioni sull'aggiunta di librerie di supporto al progetto, consulta la guida introduttiva ad Android Jetpack.
Attenzione: assicurati di utilizzare l'implementazione androidx
del framework del router multimediale. Non utilizzare il pacchetto android.media
precedente.
Definisci la voce di menu del pulsante Percorso multimediale
Crea un file XML che definisca una voce di menu per il pulsante del percorso multimediale.
L'azione dell'elemento deve essere la classe MediaRouteActionProvider
.
Ecco un file di esempio:
// 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>
Creazione di un MediaRouteSelector
I percorsi visualizzati nel menu del pulsante Percorso multimediale sono determinati da un MediaRouteSelector
.
Estendi l'attività da AppCompatActivity
e crea il selettore quando viene creata l'attività chiamando MediaRouteSelector.Builder
dal metodo onCreate() come mostrato
nel seguente esempio di codice. Tieni presente che il selettore viene salvato in una variabile di classe e i tipi di route consentiti vengono specificati aggiungendo oggetti 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(); } }
Per la maggior parte delle applicazioni, l'unico
tipo di route necessario è CATEGORY_REMOTE_PLAYBACK
. Questo tipo di percorso considera il dispositivo che esegue la tua app come un telecomando.
Il dispositivo ricevitore connesso gestisce il recupero, la decodifica e la riproduzione di tutti i dati dei contenuti.
Ecco come funzionano le app che supportano Google Cast, come
Chromecast.
Alcuni produttori supportano una speciale opzione di routing denominata "output secondario". Con questo routing, l'app multimediale recupera, esegue il rendering e trasmette in streaming video o musica direttamente sullo schermo e/o sugli altoparlanti sul dispositivo ricevitore remoto selezionato.
Utilizza l'uscita secondaria per inviare contenuti a display video o sistemi musicali wireless. Per consentire il rilevamento e la selezione di questi dispositivi, devi aggiungere le categorie di controllo CATEGORY_LIVE_AUDIO
o CATEGORY_LIVE_VIDEO
a MediaRouteSelector. Devi anche creare e gestire la tua finestra di dialogo Presentation
.
Aggiungere il pulsante Percorso multimediale alla barra delle azioni
Dopo aver definito il menu Percorso multimediale e MediaRouteSelector, ora puoi aggiungere il pulsante Percorso multimediale a un'attività.
Esegui l'override del metodo onCreateOptionsMenu()
per ogni tua attività per aggiungere un menu opzioni.
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; }
Per ulteriori informazioni sull'implementazione della barra delle azioni nella tua app, consulta la guida per gli sviluppatori relativa alla barra delle azioni.
Puoi anche aggiungere un pulsante di route multimediale come MediaRouteButton
in qualsiasi vista. Devi collegare un MediaRouteSelector al pulsante utilizzando il metodo setRouteSelector()
. Consulta l'elenco di controllo per la progettazione di Google Cast per le linee guida sull'incorporamento del pulsante Percorso multimediale nell'applicazione.
Callback di MediaRouter
Tutte le app in esecuzione sullo stesso dispositivo condividono una singola istanza MediaRouter
e le relative route (filtrate per app dal MediaRouteSelector dell'app). Ogni attività comunica con MediaRouter
utilizzando la propria implementazione di metodi MediaRouter.Callback
. MediaRouter chiama i metodi di callback ogni volta che l'utente seleziona, modifica o disconnette un percorso.
Nel callback sono disponibili diversi metodi che puoi ignorare per ricevere informazioni sugli
eventi di routing. Come minimo, l'implementazione della classe MediaRouter.Callback
deve sostituire
onRouteSelected()
e
onRouteUnselected()
.
Poiché MediaRouter è una risorsa condivisa, la tua app deve gestire i propri callback MediaRouter in risposta ai normali callback del ciclo di vita delle attività:
- Una volta creata l'attività (
onCreate(Bundle)
), seleziona un puntatore sulMediaRouter
e tienilo premuto per l'intera durata dell'app. - Associa i callback a MediaRouter quando l'attività diventa visibile (
onStart()
) e scollegali quando è nascosta (onStop()
).
Il seguente esempio di codice mostra come creare e salvare l'oggetto callback, ottenere un'istanza di MediaRouter
e gestire i callback.
Tieni presente l'utilizzo del flag CALLBACK_FLAG_REQUEST_DISCOVERY
quando alleghi i callback in onStart()
.
Ciò consente a MediaRouteSelector di aggiornare l'elenco di route disponibili del pulsante del percorso multimediale.
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(); } ... }
Il framework del router multimediale fornisce anche una classe MediaRouteDiscoveryFragment
, che si occupa di aggiungere e rimuovere il callback per un'attività.
Nota: se stai scrivendo un'app per la riproduzione di musica e vuoi che riproduca musica in background, devi creare un Service
per la riproduzione e chiamare il framework del router multimediale dai callback del ciclo di vita del servizio.
Controllo di un percorso di riproduzione remoto
Quando selezioni un percorso di riproduzione da remoto, l'app funge da telecomando. Il dispositivo all'estremità opposta del percorso
gestisce tutte le funzioni di recupero, decodifica e riproduzione dei dati dei contenuti. I controlli nella UI della tua app comunicano con il dispositivo ricevitore tramite un
oggetto RemotePlaybackClient
.
La classe RemotePlaybackClient
fornisce metodi aggiuntivi per gestire la riproduzione dei contenuti. Ecco alcuni dei metodi di riproduzione dei tasti della classe RemotePlaybackClient
:
play()
: riproduci un file multimediale specifico, specificato daUri
.pause()
: metti in pausa la traccia multimediale attualmente in riproduzione.resume()
: continua la riproduzione della traccia corrente dopo un comando di pausa.seek()
: passa a una posizione specifica nella traccia corrente.release()
: elimina la connessione dall'app al dispositivo di riproduzione remoto.
Puoi utilizzare questi metodi per associare le azioni ai controlli di riproduzione forniti nella tua app. La maggior parte di questi metodi consente anche di includere un oggetto callback in modo da poter monitorare l'avanzamento dell'attività di riproduzione o della richiesta di controllo.
La classe RemotePlaybackClient
supporta anche l'inserimento in coda di
più elementi multimediali per la riproduzione e la gestione della coda di contenuti multimediali.
Codice di esempio
Gli esempi Android BasicMediaRouter e MediaRouter dimostrano ulteriormente l'uso dell'API MediaRouter.