Descripción general de MediaRouter

Para usar el framework de MediaRouter en tu app, debes obtener una instancia del objeto MediaRouter y adjunta un Un objeto MediaRouter.Callback para escuchar los eventos de enrutamiento. El contenido enviado a través de una ruta de contenido multimedia pasa por el MediaRouteProvider asociado (excepto en algunos casos especiales, como un dispositivo de salida Bluetooth). En la Figura 1, se proporciona una vista de alto nivel del que se usan para enrutar contenido entre dispositivos.

Figura 1: Descripción general de las clases clave de routers de contenido multimedia que utilizan las apps

Nota: Si quieres que tu app sea compatible Dispositivos Google Cast deberías usar el SDK de Cast y compilar tu app como remitente de Cast. Sigue las instrucciones de la Documentación de Cast en lugar de usar directamente el framework de MediaRouter.

El botón de ruta de contenido multimedia

Las apps para Android deben usar un botón de ruta de contenido multimedia para controlar el enrutamiento de este tipo de contenido. El framework de MediaRouter proporciona una interfaz estándar para el botón, que ayuda a los usuarios a reconocer y usar el enrutamiento cuando están disponibles. El botón de ruta de contenido multimedia generalmente se coloca en el lado derecho la barra de acciones de tu app, como se muestra en la Figura 2.

Figura 2: Botón Ruta de contenido multimedia en el barra de acciones.

Cuando el usuario presiona el botón de ruta de contenido multimedia, las rutas disponibles aparecen en una lista, como se muestra en la figura 3.

Figura 3: Una lista de las rutas de contenido multimedia disponibles, que se muestra después de presionar el botón de ruta de contenido multimedia

Sigue estos pasos para crear un botón de ruta de contenido multimedia:

  1. Usa una AppCompatActivity
  2. Define el elemento de menú del botón de la ruta de contenido multimedia.
  3. Crea un MediaRouteSelector.
  4. Agrega el botón de ruta de contenido multimedia a la barra de acciones.
  5. Crea y administra los métodos de MediaRouter.Callback en el ciclo de vida de tu actividad.

En esta sección, se describen los primeros cuatro pasos. En la siguiente sección, se describen los métodos de devolución de llamada.

Usa una AppCompatActivity

Cuando usas el marco de trabajo del enrutador de contenido multimedia en una actividad, debes extender la actividad de AppCompatActivity y, luego, importa el paquete androidx.appcompat.app. Debes agregar androidx.appcompat:appcompat. y androidx.mediarouter:mediarouter. bibliotecas de compatibilidad al proyecto de desarrollo de tu app. Para obtener más información sobre cómo agregar bibliotecas de compatibilidad para tu proyecto, consulta Cómo comenzar a usar Android Jetpack.

Precaución: Asegúrate de usar el androidx implementación del router de contenido multimedia. No uses el paquete android.media más antiguo.

Crea un archivo xml en el que se defina un elemento de menú para el botón de la ruta de contenido multimedia. La acción del elemento debería ser de la clase MediaRouteActionProvider. A continuación, se muestra un archivo de ejemplo:

// 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

Las rutas que aparecen en el menú del botón de la ruta de contenido multimedia están determinadas por un MediaRouteSelector. Extiende tu actividad de AppCompatActivity y compila el selector cuando se cree la actividad llamando a MediaRouteSelector.Builder. del método onCreate() como se muestra en la siguiente muestra de código. Ten en cuenta que el selector se guarda en una variable de clase y se especifican los tipos de rutas permitidos Para ello, agrega 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 la mayoría de las aplicaciones, la única el tipo de ruta necesario es CATEGORY_REMOTE_PLAYBACK. Este tipo de ruta trata el dispositivo que ejecuta tu app como un control remoto. El dispositivo receptor conectado controla toda la recuperación, la decodificación y la reproducción de datos de contenido. Así es como las apps compatibles con Google Cast, como Chromecast, trabajo.

Algunos fabricantes ofrecen compatibilidad con una opción de enrutamiento especial denominada "salida secundaria". Con este enrutamiento, La app de música recupera, procesa y transmite videos o música directamente a la pantalla o las bocinas del dispositivo receptor remoto seleccionado. Usa la salida secundaria para enviar contenido a sistemas de música o pantallas de video inalámbricos. Para habilitar el descubrimiento y algunos de estos dispositivos, debes agregar el CATEGORY_LIVE_AUDIO o CATEGORY_LIVE_VIDEO categorías de control al MediaRouteSelector. Además, debes crear y controlar tu propio diálogo de Presentation.

Agrega el botón de ruta de contenido multimedia a la barra de acciones

Si ya definiste el menú de ruta de contenido multimedia y MediaRouteSelector, puedes agregar el botón de ruta de contenido multimedia a una actividad. Anula el método onCreateOptionsMenu() en cada una de tus actividades para agregar opciones. .

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 obtener más información sobre la implementación de la barra de acciones en tu app, consulta la barra de acciones. de la guía para desarrolladores.

También puedes agregar un botón de ruta de contenido multimedia como MediaRouteButton en cualquier vista. Debes adjuntar un MediaRouteSelector al botón usando el método setRouteSelector(). Consulta la Lista de tareas de diseño de Google Cast para obtener pautas sobre cómo incorporar el botón de la ruta de contenido multimedia en tu aplicación.

Devoluciones de llamada de MediaRouter

Todas las apps que se ejecutan en el mismo dispositivo comparten una sola instancia de MediaRouter y sus rutas. (filtrados por app mediante el MediaRouteSelector de la app). Cada actividad se comunica con el MediaRouter con su propia implementación de MediaRouter.Callback . El MediaRouter llama a los métodos de devolución de llamada cada vez que el usuario selecciona, cambia o desconecta una ruta.

En la devolución de llamada, hay varios métodos que puedes anular para recibir información sobre de enrutamiento de correo. Como mínimo, tu implementación de la clase MediaRouter.Callback debe anular onRouteSelected() y onRouteUnselected()

Dado que el MediaRouter es un recurso compartido, tu app debe administrar sus devoluciones de llamada de MediaRouter. en respuesta a las devoluciones de llamada habituales del ciclo de vida de la actividad:

  • Cuando se crea la actividad (onCreate(Bundle)), toma un puntero al MediaRouter y mantenlo durante todo el ciclo de vida de la app.
  • Adjunta devoluciones de llamada a MediaRouter cuando la actividad se vuelva visible (onStart()) y sepáralas cuando esté oculta. (onStop())

La siguiente muestra de código demuestra cómo crear y guardar el objeto de devolución de llamada, cómo obtener una instancia de MediaRouter y administrar las devoluciones de llamada Ten en cuenta el uso de la marca CALLBACK_FLAG_REQUEST_DISCOVERY cuando adjuntes las devoluciones de llamada en onStart(). Esto permite que tu MediaRouteSelector actualice el botón de la ruta de contenido multimedia lista de rutas disponibles.

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();
    }
    ...
}

El framework del router de contenido multimedia también proporciona un MediaRouteDiscoveryFragment, que se encarga de agregar y quitar la devolución de llamada de una actividad.

Nota: Si escribes una app de reproducción de música y quieres que esta reproduzca contenido música mientras está en segundo plano, debes crear un Service para la reproducción y llamar al marco de trabajo del router de contenido multimedia desde las devoluciones de llamada de ciclo de vida del servicio.

Cómo controlar una ruta de reproducción remota

Cuando seleccionas una ruta de reproducción remota, tu app funciona como un control remoto. El dispositivo que está al otro extremo de la ruta se encarga de todas las funciones de recuperación, decodificación y reproducción de datos de contenido. Los controles de la IU de tu app se comunican con el dispositivo receptor mediante un RemotePlaybackClient.

La clase RemotePlaybackClient proporciona métodos adicionales para administrar la reproducción de contenido. A continuación, se incluyen algunos de los métodos de reproducción clave de la clase RemotePlaybackClient:

  • play(): Reproduce un título específico. archivo multimedia, especificado por Uri.
  • pause(): Pausa el reproduciendo actualmente la pista multimedia.
  • resume() — Continuar la reproducción de la pista actual después de un comando de pausa.
  • seek(): Mover a un nombre específico posición en la pista actual.
  • release(): Elimina de tu app al dispositivo de reproducción remota.

Puedes usar estos métodos para adjuntar acciones a los controles de reproducción que proporciones en tu . La mayoría de estos métodos también te permiten incluir un objeto de devolución de llamada para que puedas supervisar el progreso de la tarea de reproducción o la solicitud de control.

La clase RemotePlaybackClient también admite poner en cola Varios elementos multimedia para reproducir y administrar la fila de contenido multimedia.

Código de muestra

Android BasicMediaRouter y MediaRouter Además, estas muestras demuestran el uso de la API de MediaRouter.