Omówienie MediaRouteProvider

Platforma routera multimedialnego w Androidzie umożliwia producentom odtwarzanie treści na urządzeniach. za pomocą standaryzowanego interfejsu o nazwie MediaRouteProvider. Dostawca trasy definiuje wspólny interfejs do odtwarzania multimediów na urządzeniu odbiornika, możliwość odtwarzania multimediów na sprzęcie z dowolnej aplikacji na Androida, która obsługuje multimedia trasy.

Z tego przewodnika dowiesz się, jak utworzyć dostawcę tras multimediów dla urządzenia odbiornika w innych aplikacjach do odtwarzania multimediów na Androidzie. Aby korzystać z tego interfejsu API, musisz znać najważniejsze klasy MediaRouteProvider MediaRouteProviderDescriptor i RouteController.

Omówienie

Platforma routera multimedialnego na Androida umożliwia programistom aplikacji do multimediów i urządzeniom do odtwarzania multimediów producentom możliwość łączenia się za pomocą wspólnego interfejsu API i wspólnego interfejsu użytkownika. Deweloperzy aplikacji, którzy zaimplementuj interfejs MediaRouter, będzie mógł łączyć się z platformy i odtwarzania treści na urządzeniach, które działają w ramach platformy routera multimediów. Multimedia producenci urządzeń odtwarzających mogą korzystać z platformy, publikując MediaRouteProvider, który umożliwia innym aplikacjom nawiązywanie połączeń na urządzeniach odbioru. Rysunek 1 pokazuje, jak aplikacja łączy się z punktem odbierającym za pomocą platformy routera multimediów.

Rysunek 1. Omówienie sposobu, w jaki klasy dostawców tras mediów zapewniają komunikację z aplikacji do multimediów na urządzenie odbiornika.

Gdy utworzysz dostawcę tras multimediów dla urządzenia odbiornika, będzie on udostępniał w następujących celach:

  • Opisz i opublikuj możliwości urządzenia odbierającego, aby mogły je wykryć inne aplikacje i używać funkcji odtwarzania.
  • Opakuj interfejs programowania urządzenia odbierającego i jego komunikację z mechanizmów transportowych zapewniających zgodność urządzenia z platformą routera multimediów.

Rozłożenie dostawców tras

Dostawca tras multimediów jest rozpowszechniany jako część aplikacji na Androida. Twoim dostawcą tras może być udostępniane innym aplikacjom przez rozszerzenie MediaRouteProviderService lub opakowanie implementacji MediaRouteProvider z własną usługą i zadeklarowanie zamiaru użytkownika dla dostawcy kierowania multimediów. Te czynności pozwalają innym aplikacjom wykryć i wykorzystać zgodnie z przepisami dotyczącymi multimediów.

Uwaga: aplikacja zawierająca dostawcę trasy multimediów może też zawierać element Interfejs MediaRouter do dostawcy trasy, ale nie jest to wymagane.

Biblioteka pomocy MediaRouter

Interfejsy API routerów multimediów są zdefiniowane w sekcji Biblioteka MediaRouter na AndroidaX Musisz dodać tę bibliotekę do projektu deweloperskiego aplikacji. Więcej informacji o dodawaniu bibliotek pomocy do projektu, zobacz Konfigurowanie biblioteki pomocy.

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

Tworzenie usługi dostawcy

Platforma routera multimediów musi mieć możliwość wykrycia dostawcy tras multimediów i połączenia się z nim , aby umożliwić innym aplikacjom korzystanie z Twojej trasy. W tym celu platforma routera multimediów wyszukuje aplikacje deklarujące działanie intencji dostawcy trasy multimediów. Gdy inna aplikacja chce połączyć się z dostawcą, platforma musi mieć możliwość jej wywoływania i łączenia się z nią. Dzięki temu dostawca musi być zawarta w elemencie Service.

Ten przykładowy kod przedstawia deklarację usługi dostawcy tras multimediów oraz filtr intencji w pliku manifestu, który umożliwia jego wykrywanie i używanie przez router multimediów platforma:

<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 opakowuje rzeczywiste klasy dostawcy trasy multimediów. Platforma routera multimediów na Androida zapewnia Klasa MediaRouteProviderService do użycia jako kod usługi dla dostawców tras multimediów. Ten przykładowy kod pokazuje, jak używać tego opakowania zajęcia:

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ą wykryć trasę multimediów przez z pliku manifestu aplikacji, ale muszą też znać możliwości tras multimediów które dostarczą. Trasy multimediów mogą być różnego rodzaju i mają odmienne funkcje. Mogą też mieć inne aplikacje musisz mieć możliwość wykrycia tych danych, aby określić, czy są one zgodne z Twoją trasą.

Platforma routera multimediów umożliwia definiowanie i publikowanie możliwości mediów trasa przez obiekty IntentFilter, MediaRouteDescriptor i MediaRouteProviderDescriptor. W tej sekcji wyjaśniamy, jak ich używać na potrzeby publikowania szczegółów trasy multimediów w innych aplikacjach.

Kategorie tras

W automatycznym opisie dostawcy trasy multimediów musisz określić czy Twój dostawca obsługuje odtwarzanie zdalne, dodatkowe wyjście czy oba te tryby. Oto trasa kategorie udostępniane przez platformę Media Router:

  • CATEGORY_LIVE_AUDIO – wyjście audio do dodatkowego urządzenia wyjściowego, np. bezprzewodowego systemu muzycznego.
  • CATEGORY_LIVE_VIDEO – Wyjście wideo do dodatkowego urządzenia wyjściowego, np. wyświetlacza bezprzewodowego.
  • CATEGORY_REMOTE_PLAYBACK – odtwarzaj filmy lub dźwięk na innym urządzeniu, które obsługuje multimedia pobieranie, dekodowanie i odtwarzanie, na przykład Urządzeń Chromecast.

Aby dodać te ustawienia do opisu trasy multimediów, musisz wstawić je w polu obiekt IntentFilter, który dodasz później do Obiekt 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ż zdefiniować typy mediów elementy sterujące odtwarzaniem są obsługiwane przez Twojego dostawcę tras multimediów. W następnej sekcji dowiesz się, jak określić te ustawienia dla urządzenia.

Typy multimediów i protokoły

Dostawca kierowania multimediów dla zdalnego urządzenia odtwarzania musi określić typy multimediów i przenoszenie obsługiwanych protokołów. Te ustawienia określa się za pomocą funkcji IntentFilter i addDataScheme() oraz addDataType() metod tego obiektu. ten fragment kodu pokazuje, jak zdefiniować filtr intencji na potrzeby obsługi filmów zdalnych przy użyciu protokołów http, https i protokołu Realtime 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 tras multimediów, który oferuje zdalne odtwarzanie, musi określić typy elementów sterujących multimediami który obsługuje. Oto ogólne rodzaje ustawień zapewnianych przez trasy multimediów:

  • Elementy sterujące odtwarzaniem, takie jak odtwarzanie, wstrzymywanie, przewijanie do tyłu i do przodu.
  • funkcje kolejki umożliwiające aplikacji wysyłającej dodawanie i usuwanie elementów; z playlisty przechowywanej przez urządzenie odbierające.
  • funkcje sesji, które uniemożliwiają wysyłanie aplikacji i nie zakłócają działania Jeśli urządzenie odbierające poda identyfikator sesji aplikacji wysyłającej żądanie, a następnie identyfikator ten przy każdym kolejnym żądaniu elementu sterującego odtwarzaniem.

Poniższy przykładowy kod pokazuje, jak utworzyć filtr intencji do obsługi funkcji podstawowe sterowanie odtwarzaniem 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 MediaControlIntent zajęcia.

Deskryptor MediaRouteProvider

Po zdefiniowaniu możliwości trasy multimediów za pomocą obiektów IntentFilter możesz utworzyć obiekt deskryptora do opublikowania routera multimedialnego w Androidzie. Ten obiekt deskryptora zawiera specyfikę Twoich multimediów dzięki funkcji tras, dzięki którym inne aplikacje mogą określić sposób interakcji z multimediami .

Ten przykładowy kod pokazuje, jak dodać wcześniej utworzone filtry intencji do MediaRouteProviderDescriptor i ustaw deskryptor do użycia przez platforma 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 deskryptora znajdziesz w dokumentacji dla MediaRouteDescriptor i MediaRouteProviderDescriptor.

Sterowanie trasami

Gdy aplikacja łączy się z dostawcą tras multimediów, dostawca odbiera odtwarzanie za pomocą platformy routera multimediów wysyłanych do Twojej trasy przez inne aplikacje. Aby rozwiązać ten problem: żądań, musisz udostępnić implementację klasy MediaRouteProvider.RouteController, która przetwarza polecenia i obsługuje faktyczną komunikację z urządzeniem odbierającym.

Platforma routera multimediów wywołuje onCreateRouteController() dostawcy tras, aby uzyskać instancję tej klasy, a następnie kierować do niej żądania. Oto kluczowe metody klasy MediaRouteProvider.RouteController, które musisz zaimplementować w przypadku Twój dostawca tras multimediów:

  • onSelect() – Wywoływane, gdy aplikacja wybiera trasę do odtwarzania. Używasz tej metody do: wszelkie prace przygotowawcze, które mogą być wymagane przed rozpoczęciem odtwarzania multimediów.
  • onControlRequest() – wysyła określone polecenia dotyczące odtwarzania do urządzenia odbierającego.
  • onSetVolume() – wysyła do urządzenia odbierającego żądanie ustawienia głośności odtwarzania na dla konkretnej wartości.
  • onUpdateVolume() – wysyła żądanie do urządzenia odbierającego, aby zmodyfikować odtwarzanie o określoną ilość.
  • onUnselect() – wywoływane, gdy aplikacja odznacza trasę.
  • onRelease() – wywoływane, gdy trasa nie jest już potrzebna przez platformę, dzięki czemu może i zasobami Google Cloud.

Wszystkie żądania dotyczące sterowania odtwarzaniem (oprócz zmiany głośności) są kierowane do onControlRequest() . Twoja implementacja tej metody musi przeanalizować żądania kontrolne i na nie odpowiedzieć w odpowiedni sposób. Oto przykładowa implementacja tej metody, która przetwarza polecenia dla trasa 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 ma działać jako kod dla interfejsu API do sprzętu do odtwarzania multimediów. Implementacja metod w tej klasie jest całkowicie zależy od interfejsu programowego udostępnianego przez urządzenie odbierające.

Kod demonstracyjny

MediaRouter Przykład pokazuje, jak utworzyć dostawcę niestandardowego trasy multimediów.