Descripción general de MediaRouteProvider

El framework del router de contenido multimedia de Android permite que los fabricantes habiliten la reproducción en sus dispositivos. a través de una interfaz estandarizada llamada MediaRouteProvider. Un proveedor de rutas define una interfaz común para reproducir contenido multimedia en un dispositivo receptor, lo que hace que posible reproducir contenido multimedia en tu equipo desde cualquier aplicación de Android que admita archivos multimedia rutas.

En esta guía, se explica cómo crear un proveedor de rutas de contenido multimedia para un dispositivo receptor y cómo hacerlo que está disponible para otras aplicaciones de reproducción de contenido multimedia que se ejecutan en Android. Para usar esta API, debes conocer las clases clave MediaRouteProvider: MediaRouteProviderDescriptor y RouteController

Descripción general

El framework del router de contenido multimedia de Android permite que los desarrolladores de apps multimedia y los dispositivos de reproducción de contenido multimedia a los fabricantes conectarse a través de una API y una interfaz de usuario comunes. Desarrolladores de apps que implementarás una interfaz MediaRouter para conectarte al y reproducen contenido en dispositivos que participan en el marco de trabajo del router de contenido multimedia. Medios de comunicación Los fabricantes de dispositivos de reproducción pueden participar en el framework publicando un MediaRouteProvider que permita que otras apps se conecten y reproducir contenido multimedia en los dispositivos receptores. La figura 1 ilustra cómo se conecta una app con un receptor a través del router de contenido multimedia.

Figura 1: Descripción general de cómo las clases de proveedores de rutas de contenido multimedia proporcionan comunicación de una app multimedia a un dispositivo receptor.

Cuando creas un proveedor de rutas de contenido multimedia para tu dispositivo receptor, este entrega los siguientes propósitos:

  • Describir y publicar las capacidades del dispositivo receptor para que otras apps puedan descubrirlo y usar sus funciones de reproducción.
  • Unir la interfaz de programación del dispositivo receptor y su comunicación para que el dispositivo sea compatible con el marco del router de contenido multimedia.

Distribución de proveedores de rutas

Se distribuye un proveedor de rutas de contenido multimedia como parte de una app para Android. Tu proveedor de rutas puede ser se pusieron a disposición de otras apps extendiendo MediaRouteProviderService o unir tu implementación de MediaRouteProvider con tu propio servicio y cómo declarar un intent filtro del proveedor de rutas de contenido multimedia Estos pasos permiten que otras apps descubran y usen tu ruta de medios.

Nota: La app que contiene el proveedor de rutas de contenido multimedia también puede incluir una MediaRouter al proveedor de rutas, pero esto no es obligatorio.

Biblioteca de compatibilidad de MediaRouter

Las APIs del router de contenido multimedia se definen en el Biblioteca MediaRouter de AndroidX Debes agregar esta biblioteca a tu proyecto de desarrollo de apps. Para obtener más información sobre cómo agregar bibliotecas de compatibilidad a tu consulta Configuración de la biblioteca de compatibilidad.

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

Cómo crear un servicio de proveedor

El framework del router de contenido multimedia debe poder descubrir tu proveedor de rutas de contenido multimedia y conectarse a él. para permitir que otras aplicaciones usen tu ruta. Para ello, el framework del router de contenido multimedia Busca apps que declaran una acción de intent del proveedor de rutas de contenido multimedia. Cuando otra app quiere al proveedor, el framework debe ser capaz de invocarlo y conectarse a él debe encapsularse en un Service.

En el siguiente código de ejemplo, se muestra la declaración de un servicio de proveedor de rutas de contenido multimedia y el filtro de intents en un manifiesto, que permite que el router de contenido multimedia lo descubra y lo utilice en la nube:

<service android:name=".provider.SampleMediaRouteProviderService"
    android:label="@string/sample_media_route_provider_service"
    android:process=":mrp">
    <intent-filter>
        <action android:name="android.media.MediaRouteProviderService" />
    </intent-filter>
</service>

Este ejemplo de manifiesto declara un servicio que une las clases de proveedores de rutas de contenido multimedia reales. El framework del router de contenido multimedia de Android brinda la Clase MediaRouteProviderService para usar como wrapper de servicio en proveedores de rutas de contenido multimedia. En el siguiente código de ejemplo, se muestra cómo usar este wrapper clase:

Kotlin

class SampleMediaRouteProviderService : MediaRouteProviderService() {

    override fun onCreateMediaRouteProvider(): MediaRouteProvider {
        return SampleMediaRouteProvider(this)
    }
}

Java

public class SampleMediaRouteProviderService extends MediaRouteProviderService {

    @Override
    public MediaRouteProvider onCreateMediaRouteProvider() {
        return new SampleMediaRouteProvider(this);
    }
}

Cómo especificar las capacidades de las rutas

Las apps que se conectan al marco del router de contenido multimedia pueden descubrir la ruta de contenido multimedia a través de tu las declaraciones del manifiesto de tu app, pero también debes conocer las capacidades de las rutas de contenido multimedia proporcionan. Las rutas de contenido multimedia pueden ser de diferentes tipos y tener diferentes funciones, además de otras apps necesitas saber esos detalles para determinar si son compatibles con tu ruta.

El marco de trabajo del router de contenido multimedia te permite definir y publicar las capacidades de tu contenido multimedia. se enruta a través de objetos IntentFilter, objetos MediaRouteDescriptor y un MediaRouteProviderDescriptor. En esta sección, se explica cómo usar para publicar los detalles de tu ruta de contenido multimedia para otras apps.

Categorías de rutas

Como parte de la descripción programática de tu proveedor de rutas de contenido multimedia, debes especificar si tu proveedor admite la reproducción remota, la salida secundaria o ambas. Estas son las rutas categorías proporcionadas por el marco de trabajo del router de contenido multimedia:

  • CATEGORY_LIVE_AUDIO — Salida de audio a un dispositivo de salida secundario, como un sistema de música inalámbrico.
  • CATEGORY_LIVE_VIDEO — La salida de video para un dispositivo de salida secundario, como dispositivos de pantalla inalámbrica.
  • CATEGORY_REMOTE_PLAYBACK: Reproduce video o audio en otro dispositivo que controla contenido multimedia. recuperación, decodificación y reproducción, como Dispositivos Chromecast.

Para incluir estos parámetros de configuración en una descripción de tu ruta de contenido multimedia, debes insertarlos en un objeto IntentFilter, que luego agregarás a un Objeto MediaRouteDescriptor:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {
        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run {
            addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            arrayListOf(this)
        }
    }
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {
    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
    static {
        IntentFilter videoPlayback = new IntentFilter();
        videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
    }
}

Si especificas el intent CATEGORY_REMOTE_PLAYBACK, también debes definir qué tipos de contenido multimedia y los controles de reproducción son compatibles con tu proveedor de rutas de contenido multimedia. En la siguiente sección, se describe cómo especificar estas opciones para tu dispositivo.

Tipos de contenido multimedia y protocolos

Un proveedor de rutas de contenido multimedia para un dispositivo de reproducción remota debe especificar los tipos de contenido multimedia y la transferencia los protocolos que admite. Debes especificar esta configuración con IntentFilter la clase addDataScheme() y addDataType() de ese objeto. El El siguiente fragmento de código demuestra cómo definir un filtro de intents para admitir videos remotos Reproducción con http, https y el Protocolo de transmisión en tiempo real (RTSP):

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {

        private fun IntentFilter.addDataTypeUnchecked(type: String) {
            try {
                addDataType(type)
            } catch (ex: IntentFilter.MalformedMimeTypeException) {
                throw RuntimeException(ex)
            }
        }

        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run {
            addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            addAction(MediaControlIntent.ACTION_PLAY)
            addDataScheme("http")
            addDataScheme("https")
            addDataScheme("rtsp")
            addDataTypeUnchecked("video/*")
            arrayListOf(this)
        }
    }
    ...
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {

    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;

    static {
        IntentFilter videoPlayback = new IntentFilter();
        videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
        videoPlayback.addDataScheme("http");
        videoPlayback.addDataScheme("https");
        videoPlayback.addDataScheme("rtsp");
        addDataTypeUnchecked(videoPlayback, "video/*");
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
    }
    ...

    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
        try {
            filter.addDataType(type);
        } catch (MalformedMimeTypeException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Controles de reproducción

Un proveedor de rutas de contenido multimedia que ofrezca reproducción remota debe especificar los tipos de controles de contenido multimedia que admite. A continuación, se enumeran los tipos generales de control que las rutas de contenido multimedia pueden proporcionar:

  • Controles de reproducción, como reproducción, pausa, retroceso y avance rápido.
  • Funciones de fila, que permiten que la app emisora agregue y quite elementos de una playlist mantenida por el dispositivo receptor.
  • Funciones de sesión, que evitan que las aplicaciones de envío interfieran en cada pidiéndole al dispositivo receptor que proporcione un ID de sesión a la app solicitante y, luego, que se identifica con cada solicitud posterior de control de reproducción.

El siguiente ejemplo de código demuestra cómo construir un filtro de intents para admitir controles básicos de reproducción de ruta de contenido multimedia:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {
        ...
        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = run {
            val videoPlayback: IntentFilter = ...
            ...
            val playControls = IntentFilter().apply {
                addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
                addAction(MediaControlIntent.ACTION_SEEK)
                addAction(MediaControlIntent.ACTION_GET_STATUS)
                addAction(MediaControlIntent.ACTION_PAUSE)
                addAction(MediaControlIntent.ACTION_RESUME)
                addAction(MediaControlIntent.ACTION_STOP)
            }
            arrayListOf(videoPlayback, playControls)
        }
    }
    ...
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {
    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
    static {
        ...
        IntentFilter playControls = new IntentFilter();
        playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        playControls.addAction(MediaControlIntent.ACTION_SEEK);
        playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
        playControls.addAction(MediaControlIntent.ACTION_PAUSE);
        playControls.addAction(MediaControlIntent.ACTION_RESUME);
        playControls.addAction(MediaControlIntent.ACTION_STOP);
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
        CONTROL_FILTERS_BASIC.add(playControls);
    }
    ...
}

Para obtener más información sobre los intents de control de reproducción disponibles, consulta el Clase MediaControlIntent.

MediaRouteProviderDescriptor

Después de definir las capacidades de tu ruta de contenido multimedia con objetos IntentFilter, puedes crear un objeto descriptor para publicar en el framework del router de contenido multimedia de Android. Este objeto descriptor contiene los detalles de tu contenido multimedia las capacidades de ruta para que otras aplicaciones puedan determinar cómo interactuar con tu contenido multimedia ruta.

El siguiente código de ejemplo demuestra cómo agregar los filtros de intents creados previamente a un MediaRouteProviderDescriptor y establece el descriptor para que lo use. marco de trabajo del router de contenido multimedia:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    init {
        publishRoutes()
    }

    private fun publishRoutes() {
        val resources = context.resources
        val routeName: String = resources.getString(R.string.variable_volume_basic_route_name)
        val routeDescription: String = resources.getString(R.string.sample_route_description)
        // Create a route descriptor using previously created IntentFilters
        val routeDescriptor: MediaRouteDescriptor =
                MediaRouteDescriptor.Builder(VARIABLE_VOLUME_BASIC_ROUTE_ID, routeName)
                        .setDescription(routeDescription)
                        .addControlFilters(CONTROL_FILTERS_BASIC)
                        .setPlaybackStream(AudioManager.STREAM_MUSIC)
                        .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
                        .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                        .setVolumeMax(VOLUME_MAX)
                        .setVolume(mVolume)
                        .build()
        // Add the route descriptor to the provider descriptor
        val providerDescriptor: MediaRouteProviderDescriptor =
                MediaRouteProviderDescriptor.Builder()
                        .addRoute(routeDescriptor)
                        .build()

        // Publish the descriptor to the framework
        descriptor = providerDescriptor
    }
    ...
}

Java

public SampleMediaRouteProvider(Context context) {
    super(context);
    publishRoutes();
}

private void publishRoutes() {
    Resources r = getContext().getResources();
    // Create a route descriptor using previously created IntentFilters
    MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
            VARIABLE_VOLUME_BASIC_ROUTE_ID,
            r.getString(R.string.variable_volume_basic_route_name))
            .setDescription(r.getString(R.string.sample_route_description))
            .addControlFilters(CONTROL_FILTERS_BASIC)
            .setPlaybackStream(AudioManager.STREAM_MUSIC)
            .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
            .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
            .setVolumeMax(VOLUME_MAX)
            .setVolume(mVolume)
            .build();
    // Add the route descriptor to the provider descriptor
    MediaRouteProviderDescriptor providerDescriptor =
            new MediaRouteProviderDescriptor.Builder()
            .addRoute(routeDescriptor)
            .build();

    // Publish the descriptor to the framework
    setDescriptor(providerDescriptor);
}

Para obtener más información sobre la configuración del descriptor disponible, consulta la documentación de referencia para MediaRouteDescriptor y MediaRouteProviderDescriptor.

Cómo controlar rutas

Cuando una aplicación se conecta a tu proveedor de rutas de contenido multimedia, este recibe la reproducción a través del framework del router de contenido multimedia que otras apps envían a tu ruta. Para administrarlos solicitudes, debes proporcionar una implementación de una clase MediaRouteProvider.RouteController, que procesa los comandos y maneja la comunicación real con el dispositivo receptor.

El framework del router de contenido multimedia llama a onCreateRouteController(). de tu proveedor de rutas para obtener una instancia de esta clase y, luego, enrutar las solicitudes hacia ella. Estos son los métodos clave de la clase MediaRouteProvider.RouteController, que debes implementar para tu proveedor de rutas de contenido multimedia:

  • onSelect() — Se llama cuando una aplicación selecciona tu ruta para la reproducción. Usas este método para hacer cualquier trabajo de preparación que pueda ser necesario antes de que comience la reproducción de contenido multimedia
  • onControlRequest(): Envía comandos de reproducción específicos al dispositivo receptor.
  • onSetVolume(): Envía una solicitud al dispositivo receptor para establecer el volumen de reproducción en un un valor específico.
  • onUpdateVolume(): Envía una solicitud al dispositivo receptor para modificar la reproducción. volumen en una cantidad específica.
  • onUnselect(): Se llama cuando una app anula la selección de una ruta.
  • onRelease() — Se llama cuando el framework ya no necesita la ruta, lo que le permite liberar su de Google Cloud.

Todas las solicitudes de control de reproducción, excepto los cambios de volumen, se dirigen a onControlRequest(). . La implementación de este método debe analizar las solicitudes de control y responder a ellas apropiadamente. A continuación, se muestra un ejemplo de implementación de este método que procesa comandos para un Ruta de contenido multimedia de reproducción remota:

Kotlin

private class SampleRouteController : MediaRouteProvider.RouteController() {
    ...

    override fun onControlRequest(
            intent: Intent,
            callback: MediaRouter.ControlRequestCallback?
    ): Boolean {
        return if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
            val action = intent.action
            when (action) {
                MediaControlIntent.ACTION_PLAY -> handlePlay(intent, callback)
                MediaControlIntent.ACTION_ENQUEUE -> handleEnqueue(intent, callback)
                MediaControlIntent.ACTION_REMOVE -> handleRemove(intent, callback)
                MediaControlIntent.ACTION_SEEK -> handleSeek(intent, callback)
                MediaControlIntent.ACTION_GET_STATUS -> handleGetStatus(intent, callback)
                MediaControlIntent.ACTION_PAUSE -> handlePause(intent, callback)
                MediaControlIntent.ACTION_RESUME -> handleResume(intent, callback)
                MediaControlIntent.ACTION_STOP -> handleStop(intent, callback)
                MediaControlIntent.ACTION_START_SESSION -> handleStartSession(intent, callback)
                MediaControlIntent.ACTION_GET_SESSION_STATUS ->
                    handleGetSessionStatus(intent, callback)
                MediaControlIntent.ACTION_END_SESSION -> handleEndSession(intent, callback)
                else -> false
            }.also {
                Log.d(TAG, sessionManager.toString())
            }
        } else {
            false
        }
    }
    ...
}

Java

private final class SampleRouteController extends
        MediaRouteProvider.RouteController {
    ...

    @Override
    public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {

        String action = intent.getAction();

        if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
            boolean success = false;
            if (action.equals(MediaControlIntent.ACTION_PLAY)) {
                success = handlePlay(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
                success = handleEnqueue(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
                success = handleRemove(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
                success = handleSeek(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
                success = handleGetStatus(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
                success = handlePause(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
                success = handleResume(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
                success = handleStop(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
                success = handleStartSession(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
                success = handleGetSessionStatus(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
                success = handleEndSession(intent, callback);
            }

            Log.d(TAG, sessionManager.toString());
            return success;
        }
        return false;
    }
    ...
}

Es importante comprender que la clase MediaRouteProvider.RouteController está diseñada para funcionar como wrapper. para la API a tu equipo de reproducción de medios. La implementación de los métodos en esta clase es depende completamente de la interfaz programática proporcionada por el dispositivo receptor.

Código de ejemplo

El MediaRouter En este ejemplo, se muestra cómo crear un proveedor de rutas de contenido multimedia personalizado.