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