Platforma routera multimediów z Androidem umożliwia producentom odtwarzanie treści na urządzeniach za pomocą ujednoliconego interfejsu o nazwie MediaRouteProvider
.
Dostawca trasy definiuje wspólny interfejs do odtwarzania multimediów na urządzeniu odbierającym, co umożliwia odtwarzanie multimediów na sprzęcie z dowolnej aplikacji na Androida, która obsługuje trasy multimediów.
W tym przewodniku omawiamy, jak utworzyć dostawcę trasy multimediów dla urządzenia odbierającego i udostępnić go innym aplikacjom do odtwarzania multimediów, które działają na Androidzie. Aby korzystać z tego interfejsu API, musisz znać klasy kluczy MediaRouteProvider
, MediaRouteProviderDescriptor
i RouteController
.
Przegląd
Platforma routera multimediów na Androidzie umożliwia deweloperom aplikacji multimedialnych i producentom urządzeń do odtwarzania multimediów połączenie się za pomocą wspólnego interfejsu API i wspólnego interfejsu. Deweloperzy aplikacji, którzy implementują interfejs MediaRouter
, mogą następnie połączyć się z tą platformą i odtwarzać treści na urządzeniach należących do platformy routera multimediów. Producenci urządzeń do odtwarzania multimediów mogą uczestniczyć w platformie, publikując MediaRouteProvider
, który umożliwia innym aplikacjom łączenie się z urządzeniami odbiorczymi i ich odtwarzanie. Rysunek 1 pokazuje, jak aplikacja łączy się z urządzeniem odbierającym za pomocą platformy routera multimediów.
Gdy tworzysz dostawcę trasy multimediów dla urządzenia odbierającego, dostawca służy do tych celów:
- Opisz i opublikuj możliwości urządzenia odbierającego, aby inne aplikacje mogły je wykryć i korzystać z funkcji odtwarzania.
- Opakuj interfejs programowania urządzenia odbierającego i jego mechanizmy transportu komunikacyjnego, aby urządzenie było zgodne ze strukturą routera multimediów.
Rozmieszczenie dostawców tras
Dostawca trasy multimediów jest rozpowszechniany w ramach aplikacji na Androida. Możesz udostępnić dostawcę trasy innym aplikacjom, rozszerzając MediaRouteProviderService
lub dodając implementację MediaRouteProvider
do własnej usługi i deklarując filtr intencji dla dostawcy trasy multimediów. Te czynności umożliwiają innym aplikacjom wykrywanie Twoich tras multimedialnych i korzystanie z nich.
Uwaga: aplikacja zawierająca dostawcę trasy multimediów może też udostępniać dostawcy trasy interfejs MediaRouter, ale nie jest to wymagane.
Biblioteka obsługi MediaRouter
Interfejsy API routera multimediów są zdefiniowane w bibliotece MediaRouter w AndroidzieX Musisz dodać tę bibliotekę do projektu, w którym tworzysz aplikację. Więcej informacji o dodawaniu bibliotek pomocniczych do projektu znajdziesz w artykule o konfigurowaniu bibliotek pomocy.
Uwaga: pamiętaj, aby użyć implementacji platformy routera multimediów AndroidX
.
Nie używaj starszego pakietu android.media
.
Tworzenie usługi dostawcy
Platforma routera multimediów musi mieć możliwość wykrywania Twojego dostawcy tras multimediów i łączenia się z nim, aby umożliwić innym aplikacjom użycie Twojej trasy. W tym celu platforma routera multimediów szuka aplikacji, które deklarują działanie intencji dostawcy trasy multimediów. Gdy inna aplikacja chce połączyć się z Twoim dostawcą, platforma musi mieć możliwość jej wywołania i połączenia, dlatego dostawca musi być ujęty w Service
.
Ten przykładowy kod zawiera deklarację usługi dostawcy trasy multimediów i filtr intencji w pliku manifestu, który umożliwia wykrywanie i używanie tej usługi przez platformę routera multimediów:
<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>
Ten przykładowy plik manifestu deklaruje usługę, która pakuje rzeczywiste klasy dostawcy trasy multimediów.
Platforma routera multimediów na Androidzie udostępnia klasę MediaRouteProviderService
, która może być używana jako kod usługi dla dostawców tras multimediów. Poniższy przykładowy kod pokazuje, jak używać tej klasy otoki:
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); } }
Określanie możliwości tras
Aplikacje łączące się z platformą routera multimediów mogą wykrywać trasę multimediów za pomocą deklaracji w pliku manifestu aplikacji, ale muszą też znać możliwości zapewnianych tras multimediów. Trasy multimediów mogą być różnego typu i mieć różne funkcje. Inne aplikacje muszą mieć możliwość wykrycia tych szczegółów, aby określić, czy są zgodne z Twoją trasą.
Platforma routera multimediów umożliwia definiowanie i publikowanie możliwości trasy multimediów przez obiekty IntentFilter
, obiekty MediaRouteDescriptor
i MediaRouteProviderDescriptor
. Z tej sekcji dowiesz się, jak używać tych klas do publikowania szczegółów trasy multimediów dla innych aplikacji.
Kategorie trasy
W automatycznym opisie dostawcy trasy multimediów musisz określić, czy obsługuje on odtwarzanie zdalne, dodatkowe urządzenie czy obie te funkcje. Oto kategorie tras udostępniane przez platformę routera multimediów:
CATEGORY_LIVE_AUDIO
– Wyjście dźwięku na dodatkowe urządzenie wyjściowe, np. na bezprzewodowy system muzyczny.CATEGORY_LIVE_VIDEO
– Dane wyjściowe wideo na dodatkowe urządzenie wyjściowe, takie jak wyświetlacze bezprzewodowe.CATEGORY_REMOTE_PLAYBACK
– odtwarzaj filmy lub dźwięk na osobnym urządzeniu, które obsługuje pobieranie, dekodowanie i odtwarzanie multimediów, np. na urządzeniach Chromecast.
Aby uwzględnić te ustawienia w opisie trasy multimediów, musisz je wstawić do obiektu IntentFilter
, który możesz później dodać do obiektu 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); } }
Jeśli określisz intencję CATEGORY_REMOTE_PLAYBACK
, musisz też określić, jakie typy multimediów i elementy sterujące odtwarzaniem są obsługiwane przez dostawcę trasy multimediów. W następnej sekcji opisujemy, jak określić te ustawienia na swoim urządzeniu.
Typy multimediów i protokoły
Dostawca trasy multimediów dla zdalnego urządzenia odtwarzającego musi określać typy multimediów i protokoły przesyłania obsługiwane. Określasz te ustawienia za pomocą klasy IntentFilter
oraz metod addDataScheme()
i addDataType()
tego obiektu. Ten fragment kodu pokazuje, jak zdefiniować filtr intencji na potrzeby zdalnego odtwarzania filmów przy użyciu protokołów http, https i protokołu Real Time Streaming Protocol (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); } } }
Sterowanie odtwarzaniem
Dostawca trasy multimediów, który oferuje zdalne odtwarzanie, musi określić typy elementów sterujących obsługiwanych przez niego. Oto ogólne typy ustawień, które zapewniają trasy multimediów:
- Elementy sterujące odtwarzaniem, takie jak odtwarzanie, wstrzymywanie, przewijanie do tyłu i do przodu.
- Funkcje kolejki, które umożliwiają aplikacji wysyłającej dodawanie i usuwanie elementów z playlisty zarządzanej przez urządzenie odbierające.
- Funkcje sesji, które uniemożliwiają wysyłanie aplikacji do siebie nawzajem, ponieważ urządzenie odbierające przekazuje identyfikator sesji aplikacji żądającej i sprawdza ten identyfikator przy każdym kolejnym żądaniu sterowania odtwarzaniem.
Poniższy przykładowy kod pokazuje, jak utworzyć filtr intencji do obsługi podstawowych elementów sterujących odtwarzaniem trasy multimediów:
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); } ... }
Więcej informacji o dostępnych intencjach sterowania odtwarzaniem znajdziesz w klasie MediaControlIntent
.
MediaRouteProviderDescriptor
Po zdefiniowaniu możliwości trasy multimediów przy użyciu obiektów IntentFilter
możesz utworzyć obiekt deskryptora do opublikowania w platformie routera multimediów Android. Ten obiekt deskryptora zawiera specyfikę funkcji trasy multimediów, tak aby inne aplikacje mogły określić sposób interakcji z tą trasą multimediów.
Ten przykładowy kod pokazuje, jak dodać wcześniej utworzone filtry intencji do obiektu MediaRouteProviderDescriptor
i ustawić deskryptor do użycia przez platformę routera multimediów:
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); }
Więcej informacji o dostępnych ustawieniach deskryptorów znajdziesz w dokumentacji referencyjnej MediaRouteDescriptor
i MediaRouteProviderDescriptor
.
Kontrolowanie tras
Gdy aplikacja łączy się z dostawcą trasy multimediów, otrzymuje polecenia odtwarzania za pomocą platformy routera multimediów wysyłane na Twoją trasę przez inne aplikacje. Aby obsługiwać te żądania, musisz udostępnić implementację klasy MediaRouteProvider.RouteController
, która przetwarza polecenia i obsługuje rzeczywistą komunikację z urządzeniem odbierającym.
Platforma routera multimediów wywołuje metodę onCreateRouteController()
dostawcy tras, aby uzyskać instancję tej klasy, a następnie kieruje do niej żądania.
Oto główne metody klasy MediaRouteProvider.RouteController
, które musisz wdrożyć na potrzeby dostawcy trasy multimediów:
onSelect()
– wywoływane, gdy aplikacja wybiera trasę do odtwarzania. Korzystasz z tej metody do wykonywania wszelkich czynności przygotowawczych, które mogą być wymagane przed rozpoczęciem odtwarzania multimediów.onControlRequest()
– wysyła określone polecenia odtwarzania do urządzenia odbierającego.onSetVolume()
– wysyła do urządzenia odbierającego żądanie ustawienia głośności odtwarzania na określoną wartość.onUpdateVolume()
– wysyła do urządzenia odbierającego żądanie zmiany głośności odtwarzania o określoną wartość.onUnselect()
– wywoływane, gdy aplikacja odznacza trasę.onRelease()
– wywoływane, gdy trasa nie jest już potrzebna przez platformę, co pozwala zwolnić jej zasoby.
Wszystkie żądania sterowania odtwarzaniem, z wyjątkiem zmiany głośności, są kierowane do metody onControlRequest()
. Twoja implementacja tej metody musi analizować żądania kontrolne i odpowiednio na nie odpowiadać. Oto przykładowa implementacja tej metody, która przetwarza polecenia do zdalnego odtwarzania multimediów:
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; } ... }
Pamiętaj, że klasa MediaRouteProvider.RouteController
służy do działania jako kod interfejsu API dla sprzętu do odtwarzania multimediów. Implementacja metod z tej klasy zależy całkowicie od interfejsu programowego udostępnianego przez urządzenie odbierające.
Kod demonstracyjny
Przykład MediaRouter pokazuje, jak utworzyć dostawcę niestandardowej trasy multimediów.