Panoramica di MediaRouter

Per utilizzare il framework MediaRouter nella tua app, devi ottenere un'istanza dell'oggetto MediaRouter e collega un Oggetto MediaRouter.Callback per ascoltare gli eventi di routing. I contenuti inviati su un percorso multimediale passano attraverso il percorso associato a MediaRouteProvider (tranne in alcuni casi speciali, come un dispositivo di output Bluetooth). La Figura 1 fornisce una panoramica generale dello utilizzate per indirizzare i contenuti tra dispositivi.

Figura 1. Panoramica delle principali classi di media router utilizzate dalle app.

Nota: se vuoi che la tua app supporti Dispositivi Google Cast dovresti utilizzare l'SDK Cast e creare l'app come mittente di trasmissione. Segui le istruzioni nella Documentazione relativa a Cast anziché usare direttamente il framework MediaRouter.

Il pulsante Percorso multimediale

Le app Android devono utilizzare un pulsante Percorso multimediale per controllare il routing dei contenuti multimediali. Il framework MediaRouter Fornisce un'interfaccia standard per il pulsante, che consente agli utenti di riconoscere e utilizzare il routing quando sono disponibili. Il pulsante del percorso multimediale si trova in genere sul lato destro di barra delle azioni dell'app, come mostrato nella Figura 2.

Figura 2. Pulsante Route multimediale in barra delle azioni.

Quando l'utente preme il pulsante del percorso multimediale, i percorsi multimediali disponibili vengono visualizzati in un elenco come mostrato nella figura 3.

Figura 3. Un elenco di percorsi multimediali disponibili, mostrato dopo aver premuto il pulsante relativo al percorso multimediale.

Per creare un pulsante del percorso multimediale:

  1. Utilizzo di un'attività AppCompatActivity
  2. Definisci la voce di menu del pulsante di route multimediale
  3. Crea un MediaRouteSelector
  4. Aggiungi il pulsante del percorso multimediale alla barra delle azioni
  5. Creare e gestire i metodi MediaRouter.Callback nel ciclo di vita della tua attività

In questa sezione vengono descritti i primi quattro passaggi. La sezione successiva descrive i metodi di callback.

Utilizzo di un'attività AppCompatActivity

Quando utilizzi il framework Media router in un'attività, devi estendere l'attività da AppCompatActivity e importa pacchetto androidx.appcompat.app. Devi aggiungere il parametro androidx.appcompat:appcompat e androidx.mediarouter:mediarouter e supportare le librerie nel progetto di sviluppo dell'app. Per ulteriori informazioni sull'aggiunta di librerie di supporto al tuo progetto, consulta la Guida introduttiva ad Android Jetpack.

Attenzione: assicurati di utilizzare androidx dell'implementazione del framework Media router. Non utilizzare il pacchetto android.media precedente.

Crea un file XML che definisce una voce di menu per il pulsante di routing 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>

Crea un MediaRouteSelector

I percorsi visualizzati nel menu dei pulsanti del 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 sono specificati i tipi di route consentiti aggiungendo MediaControlIntent oggetti:

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, il tipo di percorso richiesto è CATEGORY_REMOTE_PLAYBACK. Questo tipo di percorso considera il dispositivo su cui è in esecuzione la tua app come un telecomando. Il dispositivo ricevitore connesso gestisce il recupero, la decodifica e la riproduzione di tutti i dati sui contenuti. Ecco come le app che supportano Google Cast, ad esempio Chromecast, al lavoro.

Alcuni produttori supportano una speciale opzione di routing chiamata "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 del dispositivo ricevitore remoto selezionato. Utilizza l'uscita secondaria per inviare contenuti a sistemi musicali wireless o display video. Per abilitare il rilevamento e dispositivi selezionati, devi aggiungere CATEGORY_LIVE_AUDIO o CATEGORY_LIVE_VIDEO categorie di controllo a MediaRouteSelector. Devi anche creare e gestire la tua finestra di dialogo Presentation.

Aggiungi il pulsante del percorso multimediale alla barra delle azioni

Dopo aver definito il menu del percorso multimediale e MediaRouteSelector, ora puoi aggiungere il pulsante del percorso multimediale a un'attività. Sostituisci il metodo onCreateOptionsMenu() per ogni attività per aggiungere opzioni o dal menu Fogli Google.

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 nell'app, Visualizza la barra delle azioni guida per gli sviluppatori.

Puoi anche aggiungere un pulsante del percorso multimediale come MediaRouteButton in qualsiasi vista. Devi collegare un MediaRouteSelector al pulsante utilizzando il metodo setRouteSelector(). Consulta le Elenco di controllo per la progettazione di Google Cast per le linee guida sull'incorporamento del pulsante relativo al percorso multimediale nella tua applicazione.

Callback di MediaRouter

Tutte le app in esecuzione sullo stesso dispositivo condividono una singola istanza MediaRouter e i relativi percorsi (filtrato per app in base al MediaRouteSelector dell'app). Ogni attività comunica con MediaRouter utilizzando la propria implementazione di MediaRouter.Callback di machine learning. MediaRouter chiama i metodi di callback ogni volta che l'utente seleziona, modifica o disconnette una route.

Esistono diversi metodi nel callback su cui puoi eseguire l'override per ricevere informazioni eventi di routing. Come minimo, l'implementazione della classe MediaRouter.Callback dovrebbe sostituire onRouteSelected() e onRouteUnselected().

Poiché MediaRouter è una risorsa condivisa, la tua app deve gestire i callback MediaRouter in risposta ai consueti callback del ciclo di vita delle attività:

  • Quando viene creata l'attività (onCreate(Bundle)), recupera un puntatore alla MediaRouter e tienilo premuto per tutta la durata dell'app.
  • Collega callback a MediaRouter quando l'attività diventa visibile (onStart()) e scollegali quando è nascosta (onStop()).

Il seguente esempio di codice mostra come crea e salva l'oggetto callback, come ottenere un'istanza di MediaRouter e come gestire i callback. Nota l'utilizzo del flag CALLBACK_FLAG_REQUEST_DISCOVERY quando si allegano i callback in onStart(). In questo modo, MediaRouteSelector può aggiornare la posizione del pulsante delle route disponibili.

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 Media router offre anche MediaRouteDiscoveryFragment corso, che si occupa di aggiungere e rimuovendo il callback per un'attività.

Nota: se stai scrivendo un'app per la riproduzione di musica e vuoi riprodurre l'app musica in background, devi creare un Service per la riproduzione e richiamare 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 remoto, l'app funge da telecomando. Il dispositivo all'altra estremità del percorso. gestisce tutte le funzioni di recupero, decodifica e riproduzione dei dati sui contenuti. I controlli nell'UI dell'app comunicano con il dispositivo destinatario tramite un RemotePlaybackClient oggetto.

Il corso RemotePlaybackClient fornisce metodi aggiuntivi per gestire la riproduzione dei contenuti. Ecco alcuni dei principali metodi di riproduzione della classe RemotePlaybackClient:

  • play(): riproduci un contenuto specifico file multimediale, specificato da un Uri.
  • pause(): metti in pausa traccia multimediale in riproduzione.
  • resume() - Continua la traccia corrente dopo un comando di pausa.
  • seek(): passa a una sezione specifica posizione nella traccia corrente.
  • release(): elimina connessione dalla tua app al dispositivo di riproduzione remoto.

Puoi utilizzare questi metodi per collegare azioni ai controlli di riproduzione che fornisci nei tuoi dell'app. La maggior parte di questi metodi consente anche di includere un oggetto di callback in modo da poter monitorare l'avanzamento dell'attività di riproduzione o della richiesta di controllo.

La classe RemotePlaybackClient supporta anche l'accodamento di più elementi multimediali per la riproduzione e la gestione della coda multimediale.

Codice di esempio

L'app Android BasicMediaRouter e MediaRouter esempi dimostrano ulteriormente l'uso dell'API MediaRouter.