Présentation de MediaRouter

Pour utiliser le framework MediaRouter dans votre application, vous devez obtenir une instance de l'objet MediaRouter et associez une MediaRouter.Callback pour écouter les événements de routage. Le contenu envoyé via une route multimédia passe par le MediaRouteProvider associé (sauf dans quelques cas particuliers, comme un périphérique de sortie Bluetooth). La figure 1 offre une vue d'ensemble de la utilisées pour acheminer le contenu entre des appareils.

Figure 1 : Présentation des principales classes de routeurs multimédias utilisées par les applications.

Remarque:Si vous souhaitez que votre application soit compatible les appareils Google Cast, vous devez utiliser le SDK Cast et créer votre application en tant qu'émetteur Cast. Suivez les instructions du Documentation Cast au lieu d'utiliser directement le framework MediaRouter.

Bouton "Routage multimédia"

Les applications Android doivent utiliser un bouton de routage multimédia pour contrôler le routage multimédia. Framework MediaRouter fournit une interface standard pour le bouton, qui aide les utilisateurs à reconnaître et à utiliser le routage lorsqu'elles seront disponibles. Le bouton de routage multimédia est généralement placé sur le côté droit de la barre d'action de votre application, comme illustré dans la figure 2.

Figure 2. Bouton "Routage multimédia" dans barre d'action.

Lorsque l'utilisateur appuie sur le bouton d'itinéraire multimédia, les routages multimédias disponibles apparaissent dans une liste, comme illustré dans la figure 3.

Figure 3. Liste des routages multimédias disponibles, qui s'affiche lorsque vous appuyez sur le bouton "Routage multimédia".

Pour créer un bouton d'itinéraire multimédia, procédez comme suit:

  1. Utiliser un AppCompatActivity
  2. Définir l'élément de menu du bouton "Route multimédia"
  3. Créer un MediaRouteSelector
  4. Ajouter le bouton "Route multimédia" à la barre d'action
  5. Créer et gérer les méthodes MediaRouter.Callback dans le cycle de vie de votre activité

Cette section décrit les quatre premières étapes. La section suivante décrit les méthodes de rappel.

Utiliser un AppCompatActivity

Lorsque vous utilisez le framework de routeur multimédia dans une activité, vous devez étendre l'activité depuis AppCompatActivity et importez le package androidx.appcompat.app. Vous devez ajouter le paramètre androidx.appcompat:appcompat. et androidx.mediarouter:mediarouter prendre en charge les bibliothèques pour votre projet de développement d'applications. Pour en savoir plus sur l'ajout de bibliothèques Support à votre projet, consultez la section Premiers pas avec Android Jetpack.

Attention:Veillez à utiliser l'androidx la mise en œuvre du cadre du routeur multimédia. N'utilisez pas l'ancien package android.media.

Créez un fichier XML qui définit un élément de menu pour le bouton de routage multimédia. L'action de l'élément doit être la classe MediaRouteActionProvider. Voici un exemple de fichier:

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

Créer un MediaRouteSelector

Les itinéraires qui s'affichent dans le menu du bouton "Route multimédia" sont déterminés par un MediaRouteSelector. Étendez votre activité depuis AppCompatActivity et créez le sélecteur lorsque l'activité est créée en appelant MediaRouteSelector.Builder à partir de la méthode onCreate(), comme indiqué dans l'exemple de code suivant. Notez que le sélecteur est enregistré dans une variable de classe et que les types d'itinéraires autorisés sont spécifiés. en ajoutant des objets MediaControlIntent:

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

Pour la plupart des applications, le type d'itinéraire requis est CATEGORY_REMOTE_PLAYBACK. Ce type d'itinéraire considère l'appareil qui exécute votre application comme une télécommande. Le récepteur connecté gère la récupération, le décodage et la lecture de toutes les données de contenu. C'est ainsi que les applications compatibles avec Google Cast, comme Chromecast, au travail.

Quelques fabricants proposent une option de routage spéciale appelée "sortie secondaire". Avec ce routage, votre L'application multimédia récupère, affiche et diffuse des vidéos ou de la musique directement sur l'écran et/ou les haut-parleurs du récepteur distant sélectionné. Utilisez la sortie secondaire pour envoyer des contenus vers des systèmes musicaux ou des écrans vidéo compatibles sans fil. Pour permettre la découverte et de ces appareils, vous devez ajouter CATEGORY_LIVE_AUDIO ou CATEGORY_LIVE_VIDEO les catégories de contrôle sur MediaRouteSelector. Vous devez également créer et gérer votre propre boîte de dialogue Presentation.

Ajouter le bouton "Route multimédia" à la barre d'action

Une fois le menu de routage multimédia et le sélecteur MediaRouteSelector définis, vous pouvez désormais ajouter le bouton de routage multimédia à une activité. Remplacez la méthode onCreateOptionsMenu() pour chacune de vos activités afin d'ajouter une option. .

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
}
@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;
}

Pour en savoir plus sur l'implémentation de la barre d'action dans votre application, la barre d'action guide du développeur.

Vous pouvez également ajouter un bouton d'itinéraire multimédia en tant que MediaRouteButton dans n'importe quelle vue. Vous devez associer un MediaRouteSelector au bouton à l'aide de la méthode setRouteSelector(). Consultez le Checklist de conception de Google Cast pour obtenir des instructions sur l'intégration du bouton d'acheminement multimédia dans votre application.

Rappels MediaRouter

Toutes les applications exécutées sur le même appareil partagent une même instance MediaRouter et ses routes (filtré par application en fonction du MediaRouteSelector de l'application). Chaque activité communique avec le MediaRouter en utilisant sa propre implémentation de MediaRouter.Callback. méthodes. MediaRouter appelle les méthodes de rappel chaque fois que l'utilisateur sélectionne, modifie ou déconnecte un itinéraire.

Vous pouvez ignorer plusieurs méthodes du rappel pour recevoir des informations sur des événements de routage. Au minimum, votre implémentation de la classe MediaRouter.Callback doit remplacer onRouteSelected() et onRouteUnselected()

Étant donné que MediaRouter est une ressource partagée, votre application doit gérer ses rappels MediaRouter en réponse aux rappels habituels du cycle de vie d'une activité:

  • Une fois l'activité créée (onCreate(Bundle)), le pointeur vers MediaRouter est récupéré et le reste pendant toute la durée de vie de l'application.
  • Associer des rappels à MediaRouter lorsque l'activité devient visible (onStart()) et les dissocier lorsqu'elle est masquée (onStop()).

L'exemple de code suivant montre comment créer et enregistrer l'objet de rappel, obtenir une instance de MediaRouter et apprendre à gérer les rappels. Notez l'utilisation de l'indicateur CALLBACK_FLAG_REQUEST_DISCOVERY lors de l'association des rappels dans onStart(). Cela permet à votre MediaRouteSelector d'actualiser le bouton liste des routes disponibles.

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

Le framework du routeur multimédia fournit également un MediaRouteDiscoveryFragment, qui se charge d'ajouter et supprimer le rappel d'une activité.

Remarque:Si vous développez une application de lecture de musique et souhaitez qu'elle lise de la musique en arrière-plan, vous devez créer un Service pour la lire. et appeler le framework du routeur multimédia à partir des rappels de cycle de vie du service.

Contrôler un itinéraire de lecture à distance

Lorsque vous sélectionnez un itinéraire de lecture à distance, votre application fait office de télécommande. L'appareil à l'autre extrémité de l'itinéraire gère toutes les fonctions de récupération, de décodage et de lecture des données de contenu. Les commandes de l'interface utilisateur de votre application communiquent avec l'appareil récepteur à l'aide d'un RemotePlaybackClient.

La classe RemotePlaybackClient fournit des méthodes supplémentaires pour gérer la lecture des contenus. Voici quelques-unes des principales méthodes de lecture de la classe RemotePlaybackClient:

  • play() : lire un titre spécifique fichier multimédia, spécifié par un Uri.
  • pause() : mettez en pause la la piste multimédia est en cours de lecture.
  • resume() – Continuer la lecture de la piste en cours après une commande de pause.
  • seek() : passer à un élément dans la piste actuelle.
  • release() : supprimer le de votre application à l'appareil de lecture à distance.

Vous pouvez utiliser ces méthodes pour associer des actions aux commandes de lecture définies dans votre l'application. La plupart de ces méthodes vous permettent également d'inclure un objet de rappel afin de surveiller la progression de la tâche de lecture ou de la demande de commande ;

La classe RemotePlaybackClient prend également en charge la mise en file d'attente de plusieurs éléments multimédias pour la lecture et la gestion de la file d'attente.

Exemple de code

BasicMediaRouter d'Android et MediaRouter exemples illustrant l'utilisation de l'API MediaRouter.