Omówienie MediaRouter

Aby używać platformy MediaRouter w aplikacji, musisz pobrać instancję MediaRouter i dołącz załącznik Obiekt MediaRouter.Callback, który ma nasłuchiwać zdarzeń routingu. Treści wysyłane trasą multimediów przechodzą przez trasę powiązane MediaRouteProvider (z wyjątkiem kilku szczególnych przypadków, takich jak urządzenie wyjściowe Bluetooth). Rysunek 1 przedstawia ogólny widok klas używanych do kierowania treści między urządzeniami.

Rysunek 1. Omówienie najważniejszych klas routerów multimediów używanych przez aplikacje.

Uwaga: jeśli chcesz, aby aplikacja obsługiwała tę funkcję. urządzeń Google Cast, użyj pakietu Cast SDK i utworzyć aplikację jako nadawca Cast. Postępuj zgodnie ze wskazówkami na Dokumentacja dotycząca przesyłania zamiast bezpośrednio korzystać z platformy MediaRouter.

Przycisk kierowania multimediów

Aplikacje na Androida powinny używać przycisku kierowania multimediów do sterowania routingiem multimediów. Platforma MediaRouter ma standardowy interfejs przycisku, który pomaga użytkownikom rozpoznawać i używać routingu gdy będzie dostępna. Przycisk trasy multimediów jest zwykle umieszczony po prawej stronie na pasku działań aplikacji, tak jak na rys. 2.

Rysunek 2. Przycisk Trasa multimediów w na pasku działań.

Gdy użytkownik naciśnie przycisk kierowania multimediów, na liście pojawią się dostępne trasy multimediów, tak jak na ilustracji 3.

Rysunek 3. Lista dostępnych tras multimediów wyświetlana po naciśnięciu przycisku kierowania multimediów.

Aby utworzyć przycisk trasy multimediów:

  1. Używanie klasy AppCompatActivity
  2. Zdefiniuj element menu przycisku kierowania multimediów
  3. Tworzenie obiektu MediaRouteSelector
  4. Dodawanie przycisku trasy multimediów do paska działań
  5. Tworzenie metod MediaRouter.Callback w cyklu życia aktywności i zarządzanie nimi

W tej sekcji opisano pierwsze cztery kroki. W następnej sekcji opisano metody wywołania zwrotnego.

Używanie klasy AppCompatActivity

Gdy w aktywności używasz platformy routera multimediów, rozszerz ją aktywność z AppCompatActivity i zaimportuj pakiet androidx.appcompat.app. Musisz dodać parametr androidx.appcompat:appcompat, oraz androidx.mediarouter:mediarouter do obsługi bibliotek w swoim projekcie programowania aplikacji. Więcej informacji o dodawaniu bibliotek pomocniczych projektu, zapoznaj się z artykułem Pierwsze kroki z Androidem Jetpack.

Uwaga: pamiętaj, aby użyć androidx i wdrożyć platformę routera multimediów. Nie używaj starszego pakietu android.media.

Utwórz plik XML, który definiuje pozycję menu dla przycisku trasy multimediów. Działaniem elementu powinna być klasa MediaRouteActionProvider. Oto przykładowy plik:

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

Tworzenie obiektu MediaRouteSelector

Trasy wyświetlane w menu przycisku trasy multimediów są określane przez MediaRouteSelector. Przedłuż swoją aktywność od AppCompatActivity i stworzysz selektor, gdy zostanie utworzona aktywność, wywołując funkcję MediaRouteSelector.Builder. z metody onCreate(), jak pokazano na ilustracji w poniższym przykładowym kodzie. Zwróć uwagę, że selektor jest zapisany w zmiennej klasy, a dozwolone typy tras są określone dodając MediaControlIntent obiekty:

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

W większości aplikacji jedyny wymagany typ trasy to CATEGORY_REMOTE_PLAYBACK. Ten typ trasy traktuje urządzenie, na którym jest uruchomiona Twoja aplikacja, jak pilota. Pobieranie, dekodowanie i odtwarzanie wszystkich danych treści odbywa się za pomocą podłączonego urządzenia odbierającego. Dzięki temu aplikacje obsługujące Google Cast, takie jak Chromecast – działa.

Kilku producentów obsługuje specjalną opcję routingu z nazwą „wyjściowe dodatkowe”. Przy takim wyznaczaniech tras aplikacja do multimediów pobiera, renderuje i strumieniowo przesyła filmy bądź muzykę bezpośrednio na ekran lub głośniki na wybranym odbiorniku zdalnym. Używaj dodatkowych wyjścia do wysyłania treści do bezprzewodowych systemów muzycznych lub wyświetlaczy wideo. Aby umożliwić wykrywanie dotyczące wyboru tych urządzeń, musisz dodać CATEGORY_LIVE_AUDIO lub CATEGORY_LIVE_VIDEO steruj kategoriami za pomocą obiektu MediaRouteSelector. Musisz też utworzyć i obsługiwać własne okno Presentation.

Dodawanie przycisku trasy multimediów do paska działań

Po zdefiniowaniu menu trasy multimediów i zdefiniowania MediaRouteSelector możesz teraz dodać do aktywności przycisk trasy multimediów. Aby dodać opcje, zastąp metodę onCreateOptionsMenu() w przypadku każdej aktywności .

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

Więcej informacji o implementowaniu paska działań w aplikacji znajdziesz zobacz pasek działań. przewodnik dla programistów.

Przycisk trasy multimediów możesz też dodać jako obiekt MediaRouteButton w dowolnym widok. Element MediaRouteSelector musisz dołączyć do przycisku za pomocą metody setRouteSelector(). Zobacz Lista kontrolna do projektowania w Google Cast .

Wywołania zwrotne MediaRouter

Wszystkie aplikacje uruchomione na tym samym urządzeniu korzystają z jednej instancji MediaRouter i jej tras (filtrowane według aplikacji według parametru MediaRouteSelector). Każde działanie komunikuje się z MediaRouter przy użyciu własnej implementacji obiektu MediaRouter.Callback . MediaRouter wywołuje metody wywołania zwrotnego za każdym razem, gdy użytkownik wybierze, zmieni lub rozłączy trasę.

Wywołanie zwrotne zawiera kilka metod, które możesz zastąpić, aby uzyskać informacje o zdarzeń routingu. Implementacja klasy MediaRouter.Callback powinna przynajmniej zastąpić onRouteSelected() i onRouteUnselected()

Ponieważ MediaRouter jest zasobem udostępnionym, aplikacja musi zarządzać wywołaniami zwrotnymi MediaRouter w odpowiedzi na typowe wywołania zwrotne cyklu życia aktywności:

  • Po utworzeniu aktywności (onCreate(Bundle)) użyj wskaźnika MediaRouter i przytrzymaj go przez cały okres istnienia aplikacji.
  • Dołączaj wywołania zwrotne do MediaRouter, gdy aktywność staje się widoczna (onStart()) i odłączaj je, gdy jest ukryta (onStop()).

Następujący przykładowy kod pokazuje, jak jak utworzyć i zapisać obiekt wywołania zwrotnego, uzyskać instancję MediaRouter i zarządzać wywołaniami zwrotnymi. Zwróć uwagę na użycie flagi CALLBACK_FLAG_REQUEST_DISCOVERY podczas dołączania wywołań zwrotnych w onStart(). Dzięki temu element MediaRouteSelector będzie odświeżać przycisk trasy multimediów z listą dostępnych tras.

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

Platforma routera multimediów też zapewnia MediaRouteDiscoveryFragment klasa, która obsługuje dodawanie i przez usunięcie wywołania zwrotnego dla aktywności.

Uwaga: jeśli tworzysz aplikację do odtwarzania muzyki i chcesz, aby była ona włączona muzyki, gdy jest odtwarzana w tle, do jej odtwarzania musisz utworzyć pakiet Service i wywołaj platformę routera multimediów z wywołań zwrotnych cyklu życia usługi.

Sterowanie trasą odtwarzania zdalnego

Gdy wybierzesz trasę zdalnego odtwarzania, aplikacja będzie działać jak pilot. urządzenie na drugim końcu trasy, obsługuje wszystkie funkcje pobierania, dekodowania i odtwarzania danych treści. Elementy sterujące w interfejsie aplikacji komunikują się z urządzeniem odbierającym za pomocą RemotePlaybackClient obiekt.

Klasa RemotePlaybackClient udostępnia dodatkowe metody do zarządzania odtwarzaniem treści. Oto kilka najważniejszych metod odtwarzania z klasy RemotePlaybackClient:

  • play() – odtwórz określony utwór plik multimedialny określony przez parametr Uri.
  • pause() – wstrzymaj odtwarzanej ścieżki multimedialnej.
  • resume() – kontynuuj odtwarzanie bieżącego utworu po użyciu polecenia wstrzymania.
  • seek() – przenieś do określonego miejsca pozycji w bieżącej ścieżce.
  • release() – zdemontuj połączenia między aplikacją a zdalnym urządzeniem odtwarzającym.

Korzystając z tych metod, możesz dołączać działania do elementów sterujących odtwarzaniem, które podasz na swoim . Większość z tych metod pozwala też dołączyć obiekt wywołania zwrotnego, aby można było monitorować postęp zadania odtwarzania lub żądania sterowania.

Klasa RemotePlaybackClient obsługuje również kolejkowanie wiele elementów multimedialnych do odtwarzania i zarządzania kolejką multimediów.

Kod demonstracyjny

Android BasicMediaRouter i MediaRouter Przykłady dokładniej pokazują wykorzystanie interfejsu MediaRouter API.