MediaRouter – Übersicht

Damit Sie das MediaRouter-Framework in Ihrer Anwendung verwenden können, müssen Sie eine Instanz des MediaRouter-Objekts abrufen und ein MediaRouter.Callback-Objekt anhängen, um Routingereignisse zu überwachen. Über eine Medienroute gesendete Inhalte werden über die mit der Route verknüpfte MediaRouteProvider weitergeleitet. Ausnahmen sind bestimmte Sonderfälle, z. B. ein Bluetooth-Ausgabegerät. Abbildung 1 bietet eine allgemeine Ansicht der Klassen, die zum Weiterleiten von Inhalten zwischen Geräten verwendet werden.

Abbildung 1: Übersicht über die wichtigsten von Apps verwendeten Media Router-Klassen.

Hinweis:Wenn deine App Google Cast-Geräte unterstützen soll, musst du das Cast SDK verwenden und deine App als Cast-Sender erstellen. Folgen Sie der Anleitung in der Cast-Dokumentation, anstatt das MediaRouter-Framework direkt zu verwenden.

Schaltfläche für die Medienroute

Android-Apps sollten eine Schaltfläche für die Medienroute verwenden, um die Medienweiterleitung zu steuern. Das MediaRouter-Framework stellt eine Standardschnittstelle für die Schaltfläche bereit, über die Nutzer das Routing erkennen und verwenden können, wenn es verfügbar ist. Die Schaltfläche für die Medienroute wird normalerweise rechts in der Aktionsleiste Ihrer App platziert, wie in Abbildung 2 dargestellt.

Abbildung 2: Mediaroute-Schaltfläche in der Aktionsleiste.

Wenn der Nutzer auf die Schaltfläche „Mediaroute“ drückt, werden die verfügbaren Medienrouten in einer Liste angezeigt (siehe Abbildung 3).

Abbildung 3: Eine Liste der verfügbaren Medienrouten, die nach Drücken der Schaltfläche „Medienroute“ angezeigt wird.

So erstellen Sie eine Schaltfläche für eine Medienroute:

  1. AppCompatActivity verwenden
  2. Menüpunkt der Schaltfläche für die Medienroute definieren
  3. MediaRouteSelector erstellen
  4. Schaltfläche für die Medienroute zur Aktionsleiste hinzufügen
  5. MediaRouter.Callback-Methoden im Lebenszyklus Ihrer Aktivität erstellen und verwalten

In diesem Abschnitt werden die ersten vier Schritte beschrieben. Im nächsten Abschnitt werden Callback-Methoden beschrieben.

AppCompatActivity verwenden

Wenn Sie das Media Router-Framework in einer Aktivität verwenden, sollten Sie die Aktivität aus AppCompatActivity erweitern und das Paket androidx.appcompat.app importieren. Sie müssen Ihrem App-Entwicklungsprojekt die Supportbibliotheken androidx.appcompat:appcompat und androidx.mediarouter:mediarouter hinzufügen. Weitere Informationen zum Hinzufügen von Supportbibliotheken zu Ihrem Projekt finden Sie unter Erste Schritte mit Android Jetpack.

Achtung:Verwenden Sie unbedingt die Implementierung androidx des Media Router-Frameworks. Verwende nicht das ältere android.media-Paket.

Erstellen Sie eine XML-Datei, in der ein Menüelement für die Schaltfläche für die Medienroute definiert ist. Die Aktion des Elements sollte die Klasse MediaRouteActionProvider sein. Hier ist eine Beispieldatei:

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

MediaRouteSelector erstellen

Die im Menü der Schaltfläche „Medienroute“ angezeigten Routen werden durch ein MediaRouteSelector festgelegt. Erweitern Sie die Aktivität über AppCompatActivity und erstellen Sie den Selektor, wenn die Aktivität erstellt wird. Rufen Sie dazu MediaRouteSelector.Builder über die Methode onCreate() auf, wie im folgenden Codebeispiel gezeigt. Die Auswahl wird in einer Klassenvariablen gespeichert und die zulässigen Routentypen werden durch Hinzufügen von MediaControlIntent-Objekten angegeben:

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

Für die meisten Anwendungen ist CATEGORY_REMOTE_PLAYBACK der einzige Routentyp. Bei diesem Routentyp wird das Gerät, auf dem deine App ausgeführt wird, als Fernbedienung behandelt. Das verbundene Empfängergerät übernimmt das Abrufen, Decodieren und Wiedergeben von Inhaltsdaten. So funktionieren Apps, die Google Cast unterstützen, z. B. Chromecast.

Einige Hersteller unterstützen eine spezielle Routingoption, die als "Sekundäre Ausgabe" bezeichnet wird. Mit diesem Routing ruft Ihre Medien-App Videos oder Musik ab und streamt sie direkt auf den Bildschirm und/oder die Lautsprecher auf dem ausgewählten Remote-Empfängergerät. Verwenden Sie Sekundärausgabe, um Inhalte an kabellose Musiksysteme oder Videoanzeigen zu senden. Damit diese Geräte erkannt und ausgewählt werden können, müssen Sie dem MediaRouteSelector die Steuerkategorien CATEGORY_LIVE_AUDIO oder CATEGORY_LIVE_VIDEO hinzufügen. Sie müssen außerdem ein eigenes Presentation-Dialogfeld erstellen und verwalten.

Schaltfläche für die Medienroute zur Aktionsleiste hinzufügen

Nachdem Sie das Menü für Medienrouten und den MediaRouteSelector definiert haben, können Sie die Schaltfläche für die Medienroute jetzt zu einer Aktivität hinzufügen. Überschreiben Sie die Methode onCreateOptionsMenu() für jede Ihrer Aktivitäten, um ein Optionsmenü hinzuzufügen.

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

Weitere Informationen zum Implementieren der Aktionsleiste in deiner App findest du im Entwicklerleitfaden zu Aktionsleiste.

Sie können in jeder Ansicht auch eine Medienroute-Schaltfläche als MediaRouteButton hinzufügen. Sie müssen mithilfe der Methode setRouteSelector() einen MediaRouteSelector an die Schaltfläche anhängen. In der Checkliste für das Google Cast-Design finden Sie Richtlinien zum Integrieren der Mediaroute-Schaltfläche in Ihre App.

MediaRouter-Callbacks

Alle Apps, die auf demselben Gerät ausgeführt werden, teilen sich eine einzelne MediaRouter-Instanz und deren Routen (gefiltert pro App vom MediaRouteSelector der App). Jede Aktivität kommuniziert mit dem MediaRouter über ihre eigene Implementierung von MediaRouter.Callback-Methoden. Der MediaRouter ruft die Callback-Methoden immer dann auf, wenn der Nutzer eine Route auswählt, ändert oder die Verbindung trennt.

Es gibt mehrere Methoden im Callback, die Sie überschreiben können, um Informationen zu Routingereignissen zu erhalten. Die Implementierung der MediaRouter.Callback-Klasse sollte mindestens onRouteSelected() und onRouteUnselected() überschreiben.

Da der MediaRouter eine gemeinsam genutzte Ressource ist, muss Ihre Anwendung ihre MediaRouter-Callbacks als Reaktion auf die üblichen Callbacks für den Aktivitätslebenszyklus verwalten:

  • Wenn die Aktivität erstellt wurde (onCreate(Bundle)), setzen Sie einen Zeiger auf die MediaRouter und behalten Sie sie für die Lebensdauer der App bei.
  • Hängen Sie Callbacks an MediaRouter an, wenn die Aktivität sichtbar wird (onStart()), und trennen Sie sie, wenn sie ausgeblendet sind (onStop()).

Im folgenden Codebeispiel wird gezeigt, wie Sie das Callback-Objekt erstellen und speichern, eine Instanz von MediaRouter abrufen und Callbacks verwalten. Beachte, dass beim Anhängen der Callbacks in onStart() das Flag CALLBACK_FLAG_REQUEST_DISCOVERY verwendet wird. Dadurch kann der MediaRouteSelector die Liste der verfügbaren Routen für die Schaltfläche für die Medienroute aktualisieren.

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

Das Media Router-Framework bietet auch eine MediaRouteDiscoveryFragment-Klasse, die das Hinzufügen und Entfernen des Callbacks für eine Aktivität übernimmt.

Hinweis:Wenn Sie eine Musikwiedergabe-App schreiben und möchten, dass die App Musik im Hintergrund abspielt, müssen Sie eine Service für die Wiedergabe erstellen und das Media Router-Framework aus den Lebenszyklus-Callbacks des Dienstes aufrufen.

Route für die Remote-Wiedergabe steuern

Wenn Sie eine Route für die Remote-Wiedergabe auswählen, fungiert die App als Fernbedienung. Das Gerät am anderen Ende der Route übernimmt das Abrufen, Decodieren und Wiedergeben von Inhaltsdaten. Die Steuerelemente auf der Benutzeroberfläche deiner App kommunizieren über ein RemotePlaybackClient-Objekt mit dem Empfängergerät.

Die Klasse RemotePlaybackClient bietet zusätzliche Methoden zur Verwaltung der Wiedergabe von Inhalten. Hier sind einige der wichtigsten Wiedergabemethoden der RemotePlaybackClient-Klasse:

  • play(): gibt eine bestimmte Mediendatei ab, die durch ein Uri angegeben wird.
  • pause(): Die aktuell wiedergegebene Medienspur wird pausiert.
  • resume(): Setzt die Wiedergabe des aktuellen Titels nach einem Pausenbefehl fort.
  • seek(): Wechselt zu einer bestimmten Position im aktuellen Track.
  • release(): Trenne die Verbindung von deiner App zum Remote-Wiedergabegerät.

Mit diesen Methoden können Sie Aktionen an die Wiedergabesteuerungen anhängen, die Sie in Ihrer App bereitstellen. Bei den meisten dieser Methoden ist es auch möglich, ein Callback-Objekt anzugeben, mit dem Sie den Fortschritt der Wiedergabeaufgabe oder -steuerungsanfrage überwachen können.

Die Klasse RemotePlaybackClient unterstützt auch die Wiedergabeliste mehrerer Medienelemente zur Wiedergabe und Verwaltung der Medienwarteschlange.

Beispielcode

Die Beispiele für Android BasicMediaRouter und MediaRouter zeigen die Verwendung der MediaRouter API weiter.