MediaRouteProvider – Übersicht

Mit dem Android Media Router-Framework können Hersteller die Wiedergabe auf ihren Geräten über eine standardisierte Schnittstelle namens MediaRouteProvider aktivieren. Ein Routenanbieter definiert eine gemeinsame Schnittstelle für die Wiedergabe von Medien auf einem Empfängergerät. So ist es möglich, Medien über jede Android-App, die Medienrouten unterstützt, auf Ihrem Gerät abzuspielen.

In diesem Leitfaden wird erläutert, wie Sie einen Medienroutenanbieter für ein Empfängergerät erstellen und anderen Anwendungen zur Medienwiedergabe zur Verfügung stellen, die unter Android ausgeführt werden. Wenn Sie diese API verwenden möchten, sollten Sie mit den Schlüsselklassen MediaRouteProvider, MediaRouteProviderDescriptor und RouteController vertraut sein.

Übersicht

Mit dem Android Media Router Framework können Entwickler von Medien-Apps und Hersteller von Medienwiedergabegeräten eine Verbindung über eine gemeinsame API und eine gemeinsame Benutzeroberfläche herstellen. App-Entwickler, die eine MediaRouter-Schnittstelle implementieren, können dann eine Verbindung zum Framework herstellen und Inhalte auf Geräten wiedergeben, die Teil des Media Router-Frameworks sind. Hersteller von Medienwiedergabegeräten können am Framework teilnehmen, indem sie ein MediaRouteProvider veröffentlichen, mit dem sich andere Anwendungen mit den Empfängergeräten verbinden und Medien darauf abspielen können. Abbildung 1 zeigt, wie eine App über das Media Router-Framework eine Verbindung zu einem Empfängergerät herstellt.

Abbildung 1: Übersicht darüber, wie Klassen von Medienroutenanbietern die Kommunikation von einer Medien-App mit einem Empfängergerät ermöglichen.

Wenn Sie einen Medienroutenanbieter für Ihr Empfängergerät erstellen, erfüllt er die folgenden Zwecke:

  • Beschreibe und veröffentliche die Funktionen des Empfängergeräts, damit andere Apps es finden und seine Wiedergabefunktionen verwenden können.
  • Umschließen die Programmierschnittstelle des Empfängergeräts und seine Kommunikationstransportmechanismen, um das Gerät mit dem Media Router-Framework kompatibel zu machen.

Verteilung von Routenanbietern

Ein Medienroutenanbieter wird als Teil einer Android-App vertrieben. Sie können ihn für andere Apps verfügbar machen, indem Sie MediaRouteProviderService erweitern oder Ihre Implementierung von MediaRouteProvider mit Ihrem eigenen Dienst verknüpfen und einen Intent-Filter für den Medienroutenanbieter deklarieren. Mit diesen Schritten können andere Apps Ihre Medienroute ermitteln und nutzen.

Hinweis: Die App, die den Mediaroute-Anbieter enthält, kann auch eine MediaRouter-Schnittstelle zum Routenanbieter einbinden. Dies ist jedoch nicht erforderlich.

MediaRouter-Supportbibliothek

Die Media Router APIs sind in der AndroidX-MediaRouter-Bibliothek definiert. Sie müssen diese Bibliothek Ihrem App-Entwicklungsprojekt hinzufügen. Weitere Informationen zum Hinzufügen von Supportbibliotheken zu Ihrem Projekt finden Sie unter Supportbibliothek einrichten.

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

Anbieterdienst erstellen

Das Media Router-Framework muss Ihren Mediaroute-Anbieter erkennen und eine Verbindung dazu herstellen können, damit andere Anwendungen Ihre Route verwenden können. Dazu sucht das Media Router-Framework nach Apps, die eine Intent-Aktion des Mediaroute-Anbieters deklarieren. Wenn eine andere Anwendung eine Verbindung zu Ihrem Anbieter herstellen möchte, muss das Framework ihn aufrufen und eine Verbindung zu ihm herstellen können. Daher muss Ihr Anbieter in einem Service gekapselt sein.

Der folgende Beispielcode zeigt die Deklaration eines Medienroutenanbieters und des Intent-Filters in einem Manifest, wodurch der Dienst vom Media Router-Framework erkannt und verwendet werden kann:

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

In diesem Manifestbeispiel wird ein Dienst deklariert, der die tatsächlichen Klassen des Anbieters von Medienrouten enthält. Das Android Media Router-Framework stellt die MediaRouteProviderService-Klasse zur Verwendung als Dienst-Wrapper für Mediaroute-Anbieter bereit. Der folgende Beispielcode zeigt, wie diese Wrapper-Klasse verwendet wird:

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

Routenfunktionen angeben

Anwendungen, die eine Verbindung mit dem Media Router-Framework herstellen, können Ihre Medienroute über die Manifestdeklarationen Ihrer App erkennen. Sie müssen aber auch die Funktionen der von Ihnen bereitgestellten Medienrouten kennen. Medienrouten können unterschiedliche Typen haben und unterschiedliche Funktionen haben. Andere Anwendungen müssen diese Details erkennen können, um festzustellen, ob sie mit Ihrer Route kompatibel sind.

Mit dem Media Router-Framework können Sie die Funktionen Ihrer Medienroute über IntentFilter-Objekte, MediaRouteDescriptor-Objekte und eine MediaRouteProviderDescriptor definieren und veröffentlichen. In diesem Abschnitt wird erläutert, wie Sie mit diesen Klassen die Details Ihrer Mediaroute für andere Apps veröffentlichen.

Routenkategorien

In der programmatischen Beschreibung Ihres Anbieters von Medienrouten müssen Sie angeben, ob er die Remote-Wiedergabe, die Sekundärausgabe oder beides unterstützt. Dies sind die vom Media Router-Framework bereitgestellten Routenkategorien:

  • CATEGORY_LIVE_AUDIO – Ausgabe von Audiodaten an ein sekundäres Ausgabegerät, z. B. ein kabelloses Musiksystem.
  • CATEGORY_LIVE_VIDEO – Gibt das Video an ein sekundäres Ausgabegerät aus, beispielsweise an ein kabelloses Anzeigegerät.
  • CATEGORY_REMOTE_PLAYBACK: Spiele Video oder Audio auf einem separaten Gerät ab, das das Abrufen, Decodieren und Wiedergeben von Medien übernimmt, z. B. Chromecast.

Wenn Sie diese Einstellungen in eine Beschreibung Ihrer Mediaroute aufnehmen möchten, fügen Sie sie in ein IntentFilter-Objekt ein, das Sie später einem MediaRouteDescriptor-Objekt hinzufügen:

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

Wenn Sie den Intent CATEGORY_REMOTE_PLAYBACK angeben, müssen Sie auch definieren, welche Medientypen und Wiedergabesteuerungen von Ihrem Anbieter von Medienrouten unterstützt werden. Im nächsten Abschnitt wird beschrieben, wie Sie diese Einstellungen für Ihr Gerät festlegen.

Medientypen und -protokolle

Ein Medienroutenanbieter für ein Remote-Wiedergabegerät muss die unterstützten Medientypen und Übertragungsprotokolle angeben. Dazu verwenden Sie die Klasse IntentFilter und die Methoden addDataScheme() und addDataType() des Objekts. Im folgenden Code-Snippet wird gezeigt, wie ein Intent-Filter zur Unterstützung der Remote-Videowiedergabe mit HTTP, HTTPS und Real Time Streaming Protocol (RTSP) definiert wird:

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

Wiedergabesteuerung

Ein Anbieter von Medienrouten, der die Remote-Wiedergabe anbietet, muss angeben, welche Arten von Mediensteuerelementen unterstützt werden. Dies sind die allgemeinen Steuermöglichkeiten, die Medienrouten bieten können:

  • Wiedergabesteuerung, z. B. Wiedergabe, Pause, Zurückspulen und Vorspulen
  • Warteschlangenfunktionen, mit denen die sendende App Elemente einer Playlist, die vom Empfängergerät verwaltet wird, hinzufügen und daraus entfernen kann.
  • Sitzungsfeatures, die verhindern, dass sich das Senden von Apps gegenseitig stört, indem das Empfängergerät der anfragenden App eine Sitzungs-ID sendet und diese dann bei jeder nachfolgenden Anfrage zur Wiedergabesteuerung überprüft.

Das folgende Codebeispiel zeigt, wie ein Intent-Filter zur Unterstützung grundlegender Wiedergabesteuerungen für Medienrouten erstellt wird:

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

Weitere Informationen zu den verfügbaren Intents für die Wiedergabesteuerung findest du in der Klasse MediaControlIntent.

MediaRouteProviderDescriptor

Nachdem Sie die Funktionen Ihrer Medienroute mithilfe von IntentFilter-Objekten definiert haben, können Sie ein Deskriptorobjekt für die Veröffentlichung im Android Media Router-Framework erstellen. Dieses Deskriptorobjekt enthält die Besonderheiten der Funktionen Ihrer Medienroute, damit andere Anwendungen bestimmen können, wie sie mit Ihrer Medienroute interagieren sollen.

Der folgende Beispielcode zeigt, wie Sie die zuvor erstellten Intent-Filter einem MediaRouteProviderDescriptor hinzufügen und den Deskriptor zur Verwendung durch das Media Router-Framework festlegen:

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

Weitere Informationen zu den verfügbaren Deskriptoreinstellungen finden Sie in der Referenzdokumentation zu MediaRouteDescriptor und MediaRouteProviderDescriptor.

Routen steuern

Wenn eine Anwendung eine Verbindung zu Ihrem Medienroutenanbieter herstellt, empfängt der Anbieter Wiedergabebefehle über das Media Router-Framework, das von anderen Apps an Ihre Route gesendet wird. Zur Verarbeitung dieser Anfragen musst du eine Implementierung einer MediaRouteProvider.RouteController-Klasse bereitstellen, die die Befehle verarbeitet und die eigentliche Kommunikation mit dem Empfängergerät übernimmt.

Das Media Router-Framework ruft die Methode onCreateRouteController() Ihres Routenanbieters auf, um eine Instanz dieser Klasse abzurufen, und leitet dann Anfragen an diese weiter. Dies sind die wichtigsten Methoden der MediaRouteProvider.RouteController-Klasse, die Sie für Ihren Medienroutenanbieter implementieren müssen:

  • onSelect() – Wird aufgerufen, wenn eine Anwendung Ihre Route für die Wiedergabe auswählt. Diese Methode eignet sich für alle Vorbereitungsarbeiten, die vor Beginn der Medienwiedergabe erforderlich sind.
  • onControlRequest(): sendet bestimmte Wiedergabebefehle an das empfangende Gerät.
  • onSetVolume(): Sendet eine Anfrage an das Empfängergerät, um die Wiedergabelautstärke auf einen bestimmten Wert einzustellen.
  • onUpdateVolume(): sendet eine Anfrage an das empfangende Gerät, die Wiedergabelautstärke um einen bestimmten Wert zu ändern.
  • onUnselect(): Wird aufgerufen, wenn eine Anwendung die Auswahl einer Route aufhebt.
  • onRelease(): Wird aufgerufen, wenn die Route vom Framework nicht mehr benötigt wird, um ihre Ressourcen freizugeben.

Alle Anfragen zur Wiedergabesteuerung, mit Ausnahme von Lautstärkeänderungen, werden an die Methode onControlRequest() weitergeleitet. Ihre Implementierung dieser Methode muss die Kontrollanfragen parsen und entsprechend antworten. Hier ist eine Beispielimplementierung dieser Methode, mit der Befehle für eine Medienroute für die Remote-Wiedergabe verarbeitet werden:

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

Die Klasse MediaRouteProvider.RouteController dient als Wrapper für die API für die Geräte zur Medienwiedergabe. Die Implementierung der Methoden in dieser Klasse hängt vollständig von der programmatischen Schnittstelle ab, die von deinem Empfängergerät bereitgestellt wird.

Beispielcode

Das Beispiel MediaRouter zeigt, wie ein benutzerdefinierter Mediaroute-Anbieter erstellt wird.