Zintegruj przesyłanie z aplikacją na Androida

Ten przewodnik dla programistów zawiera informacje o tym, jak dodać obsługę Google Cast na urządzeniach z Androidem. aplikacji nadawcy, używając pakietu Android Sender SDK.

Urządzenie mobilne lub laptop jest nadawcą, który steruje odtwarzaniem. Urządzenie Google Cast to odbiornik, który wyświetla treści na telewizorze.

Platforma nadawcy odnosi się do pliku binarnego biblioteki klas Cast zasoby dostępne w czasie działania u nadawcy. aplikację nadawcy lub aplikację Cast. odnosi się do aplikacji również uruchomionej u nadawcy. aplikacji Web Receiver odnosi się do aplikacji HTML działającej na urządzeniu obsługującym Cast.

Platforma nadawcy korzysta z asynchronicznego projektu wywołania zwrotnego do informowania nadawcy możesz w niej używać zdarzeń i przełączać się między różnymi stanami aplikacji Cast. cyklu.

Przepływ aplikacji

Poniższe kroki opisują typowy proces wysyłania wysokiego poziomu u nadawcy Aplikacja na Androida:

  • Platforma Cast uruchamia się automatycznie MediaRouter wykrywanie urządzeń na podstawie cyklu życia Activity.
  • Gdy użytkownik kliknie przycisk Cast, platforma wyświetla moduł Cast z listą wykrytych urządzeń przesyłających.
  • Gdy użytkownik wybierze urządzenie przesyłające, platforma próbuje uruchomić aplikacja Web Receiver na urządzeniu przesyłającym.
  • Platforma wywołuje wywołania zwrotne w aplikacji nadawcy, aby potwierdzić, że internet Aplikacja odbiornika została uruchomiona.
  • Platforma tworzy kanał komunikacji między nadawcą a internetem Aplikacje odbiorników.
  • Platforma używa kanału komunikacyjnego do wczytywania mediów i sterowania nimi na odbiorniku internetowym.
  • Platforma synchronizuje stan odtwarzania multimediów między nadawcą i Odbiornik internetowy: gdy użytkownik wykonuje działania w interfejsie nadawcy, platforma przekazuje żądania sterowania multimediami do odbiornika internetowego, wysyła aktualizacje stanu multimediów, platforma aktualizuje stan interfejsu użytkownika nadawcy.
  • Gdy użytkownik kliknie przycisk Cast, by odłączyć urządzenie przesyłające, platforma odłączy aplikację wysyłającą od odbiornika internetowego.

Pełną listę wszystkich klas, metod i zdarzeń w Google Cast SDK dla Androida: zobacz materiały referencyjne na temat interfejsu Google Cast Sender API na urządzeniu z Androidem. W sekcjach poniżej znajdziesz instrukcje dodawania przesyłania do aplikacji na Androida.

Konfigurowanie pliku manifestu na Androida

Plik AndroidManifest.xml Twojej aplikacji wymaga skonfigurowania tych elementów elementy pakietu Cast SDK:

uses-sdk

Ustaw minimalne i docelowe poziomy interfejsu Android API obsługiwane przez pakiet Cast SDK. Obecnie minimalnym poziomem interfejsu API jest 23, a docelowym poziomem Poziom API 34.

<uses-sdk
        android:minSdkVersion="23"
        android:targetSdkVersion="34" />

android:theme

Ustaw motyw aplikacji na podstawie minimalnej wersji pakietu SDK na Androida. Na przykład, jeśli nie implementujesz własnego motywu, użyj odmiany Theme.AppCompat w przypadku kierowania na wersję pakietu Android SDK na minimalną wersję przed Lollipop.

<application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat" >
       ...
</application>

Inicjowanie kontekstu przesyłania

Platforma ma globalny obiekt typu singleton o nazwie CastContext, który udostępnia współrzędne do wszystkich interakcji w ramach platformy.

Aplikacja musi implementować OptionsProvider interfejsu dostarcza opcji potrzebnych do zainicjowania CastContext singleton. OptionsProvider udostępnia instancję CastOptions który zawiera opcje wpływające na działanie platformy. Najbardziej ważnym z nich jest identyfikator aplikacji odbiornika internetowego, który służy do filtrowania w wynikach wykrywania i uruchamiać aplikację Web Receiver po rozpoczęciu sesji przesyłania. rozpoczęto.

Kotlin
class CastOptionsProvider : OptionsProvider {
    override fun getCastOptions(context: Context): CastOptions {
        return Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}
Java
public class CastOptionsProvider implements OptionsProvider {
    @Override
    public CastOptions getCastOptions(Context context) {
        CastOptions castOptions = new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .build();
        return castOptions;
    }
    @Override
    public List<SessionProvider> getAdditionalSessionProviders(Context context) {
        return null;
    }
}

Musisz zadeklarować pełną nazwę wdrożonego tagu OptionsProvider jako pole metadanych w pliku AndroidManifest.xml aplikacji nadawcy:

<application>
    ...
    <meta-data
        android:name=
            "com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
        android:value="com.foo.CastOptionsProvider" />
</application>

Gdy funkcja CastContext.getSharedInstance() jest inicjowana leniwie, funkcja CastContext .

Kotlin
class MyActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val castContext = CastContext.getSharedInstance(this)
    }
}
Java
public class MyActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        CastContext castContext = CastContext.getSharedInstance(this);
    }
}

Widżety przesyłania

Platforma Cast udostępnia widżety zgodne z technologią Cast. Lista kontrolna:

  • Nakładka wprowadzająca: Platforma udostępnia widok niestandardowy, IntroductoryOverlay, wyświetlany użytkownikowi, by zwrócić uwagę na przycisk Cast. przy pierwszym użyciu odbiornika. Aplikacja Sender może dostosujesz tekst i pozycję tytułu. tekst.

  • Przycisk przesyłania: Przycisk Cast jest widoczny niezależnie od dostępności urządzeń przesyłających. Gdy użytkownik po raz pierwszy kliknie przycisk Cast, pojawi się okno przesyłania. który zawiera listę wykrytych urządzeń. Gdy użytkownik kliknie przycisk Cast gdy jest podłączone, wyświetlane są bieżące metadane multimediów (np. tytułu, nazwy studia nagraniowego i obrazu miniatury) lub zezwala użytkownikowi , aby odłączyć urządzenie przesyłające. Przycisk „Przesyłaj” jest czasami określane jako „ikonę przesyłania”.

  • Minikontroler: Gdy użytkownik przesyła treści i opuszcza bieżące strony treści lub rozszerzenia kontrolera na inny ekran w aplikacji nadawcy, na dole ekranu wyświetlany jest minikontroler, aby użytkownik mógł przeglądać metadane aktualnie przesyłanych multimediów i sterować odtwarzaniem.

  • Rozszerzony kontroler: Gdy użytkownik przesyła treści, po kliknięciu powiadomienia o multimediach lub mini kontroler, pojawi się rozwinięty kontroler, który wyświetla odtwarzane metadane multimediów i udostępnienie kilku przycisków do sterowania, do odtwarzania multimediów.

  • Powiadomienie: Tylko na Androidzie. Gdy użytkownik przesyła treści i opuszcza aplikację nadawcy, wyświetla się powiadomienie o multimediach, które pokazuje aktualnie przesyłane treści metadanych multimediów i elementach sterujących odtwarzaniem.

  • Ekran blokady: Tylko na Androidzie. Gdy użytkownik przesyła treści i się porusza (lub gdy urządzenie limit czasu) na ekranie blokady, pojawia się element sterujący ekranu blokady multimediów, pokazuje metadane aktualnie przesyłanych multimediów i elementy sterujące odtwarzaniem.

W tym przewodniku znajdziesz opis tego, jak dodać te widżety do do aplikacji.

Dodaj przycisk Cast

Android MediaRouter Interfejsy API umożliwiają wyświetlanie i odtwarzanie multimediów na urządzeniach dodatkowych. Aplikacje na Androida, które używają interfejsu API MediaRouter, powinny zawierać przycisk Cast interfejsu, aby umożliwić użytkownikom wybór trasy multimediów z urządzenia dodatkowego, np. urządzenia przesyłającego.

Struktura ta umożliwia dodanie MediaRouteButton jako Cast button bardzo łatwe. Najpierw dodaj pozycję menu lub pole MediaRouteButton w pliku XML definiujący menu oraz CastButtonFactory w ramach konstrukcji.

// To add a Cast button, add the following snippet.
// menu.xml
<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
    app:showAsAction="always" />
Kotlin
// Then override the onCreateOptionMenu() for each of your activities.
// MyActivity.kt
override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)
    menuInflater.inflate(R.menu.main, menu)
    CastButtonFactory.setUpMediaRouteButton(
        applicationContext,
        menu,
        R.id.media_route_menu_item
    )
    return true
}
Java
// Then override the onCreateOptionMenu() for each of your activities.
// MyActivity.java
@Override public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.main, menu);
    CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                                            menu,
                                            R.id.media_route_menu_item);
    return true;
}

Jeśli następnie element Activity dziedziczy z elementu FragmentActivity możesz dodać MediaRouteButton do układu strony.

// activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:gravity="center_vertical"
   android:orientation="horizontal" >

   <androidx.mediarouter.app.MediaRouteButton
       android:id="@+id/media_route_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:mediaRouteTypes="user"
       android:visibility="gone" />

</LinearLayout>
Kotlin
// MyActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_layout)

    mMediaRouteButton = findViewById<View>(R.id.media_route_button) as MediaRouteButton
    CastButtonFactory.setUpMediaRouteButton(applicationContext, mMediaRouteButton)

    mCastContext = CastContext.getSharedInstance(this)
}
Java
// MyActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_layout);

   mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button);
   CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton);

   mCastContext = CastContext.getSharedInstance(this);
}

Jeśli chcesz zmienić wygląd przycisku przesyłania, używając motywu, zobacz Dostosuj przycisk Cast

Skonfiguruj wykrywanie urządzeń

Wykrywaniem urządzeń zarządza w pełni CastContext Podczas inicjowania CastContext aplikacja nadawcy określa odbiornika internetowego Identyfikator aplikacji i opcjonalnie może zażądać filtrowania przestrzeni nazw według ustawienia supportedNamespaces in CastOptions CastContext zawiera wewnętrznie odwołanie do MediaRouter i rozpocznie się procesu wykrywania w następujących warunkach:

  • Jest oparty na algorytmie zaprojektowanym z myślą o równowadze czasu oczekiwania w wykrywaniu urządzeń wykorzystanie baterii, wykrywanie będzie od czasu do czasu automatycznie uruchamiane, gdy aplikacja nadawcy działa na pierwszym planie.
  • Okno Cast jest otwarte.
  • Pakiet Cast SDK próbuje przywrócić sesję przesyłania.

Proces wykrywania zostanie zatrzymany po zamknięciu okna przesyłania lub aplikacja nadawcy przechodzi w tle.

Kotlin
class CastOptionsProvider : OptionsProvider {
    companion object {
        const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"
    }

    override fun getCastOptions(appContext: Context): CastOptions {
        val supportedNamespaces: MutableList<String> = ArrayList()
        supportedNamespaces.add(CUSTOM_NAMESPACE)

        return CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setSupportedNamespaces(supportedNamespaces)
            .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}
Java
class CastOptionsProvider implements OptionsProvider {
    public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace";

    @Override
    public CastOptions getCastOptions(Context appContext) {
        List<String> supportedNamespaces = new ArrayList<>();
        supportedNamespaces.add(CUSTOM_NAMESPACE);

        CastOptions castOptions = new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setSupportedNamespaces(supportedNamespaces)
            .build();
        return castOptions;
    }

    @Override
    public List<SessionProvider> getAdditionalSessionProviders(Context context) {
        return null;
    }
}

Jak działa zarządzanie sesjami

SDK Cast wprowadza pojęcie sesji przesyłania: instytucja łącząca etapy łączenia się z urządzeniem, uruchamiania (lub łączenia) z internetem Aplikacja odbiornika, łączenie się z nią i inicjowanie kanału sterowania multimediami. Zobacz odbiornik internetowy Przewodnik po cyklu życia zgłoszenia , by dowiedzieć się więcej o sesjach przesyłania i cyklu życia odbiornika internetowego.

Sesjami zarządza zajęcia SessionManager aplikacji, do których aplikacja ma dostęp CastContext.getSessionManager() Poszczególne sesje są reprezentowane przez podklasy klasy Session Przykład: CastSession reprezentuje sesje z urządzeniami przesyłającymi. Aplikacja może uzyskać dostęp do obecnie aktywnych Sesja przesyłania przez SessionManager.getCurrentCastSession()

Aplikacja może używać SessionManagerListener do monitorowania zdarzeń w sesji, takich jak utworzenie, zawieszenie, wznowienie aplikacji. Platforma automatycznie próbuje wznowić od nieprawidłowe lub nagłe zakończenie sesji, gdy była aktywna.

Sesje są tworzone i usuwane automatycznie w odpowiedzi na gesty użytkownika. z okna MediaRouter.

Aby lepiej zrozumieć błędy rozpoczynania przesyłania, aplikacje mogą używać CastContext#getCastReasonCodeForCastStatusCode(int) do konwertowania błędu rozpoczęcia sesji na CastReasonCodes Zwróć uwagę na błędy podczas uruchamiania sesji (np. CastReasonCodes#CAST_CANCELLED) są zamierzone i nie powinny być rejestrowane jako błąd.

Jeśli chcesz otrzymywać informacje o zmianach stanu w sesji, możesz zaimplementować SessionManagerListener. W tym przykładzie słyszymy o dostępności CastSession w: Activity.

Kotlin
class MyActivity : Activity() {
    private var mCastSession: CastSession? = null
    private lateinit var mCastContext: CastContext
    private lateinit var mSessionManager: SessionManager
    private val mSessionManagerListener: SessionManagerListener<CastSession> =
        SessionManagerListenerImpl()

    private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> {
        override fun onSessionStarting(session: CastSession?) {}

        override fun onSessionStarted(session: CastSession?, sessionId: String) {
            invalidateOptionsMenu()
        }

        override fun onSessionStartFailed(session: CastSession?, error: Int) {
            val castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error)
            // Handle error
        }

        override fun onSessionSuspended(session: CastSession?, reason Int) {}

        override fun onSessionResuming(session: CastSession?, sessionId: String) {}

        override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) {
            invalidateOptionsMenu()
        }

        override fun onSessionResumeFailed(session: CastSession?, error: Int) {}

        override fun onSessionEnding(session: CastSession?) {}

        override fun onSessionEnded(session: CastSession?, error: Int) {
            finish()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mCastContext = CastContext.getSharedInstance(this)
        mSessionManager = mCastContext.sessionManager
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java)
    }

    override fun onResume() {
        super.onResume()
        mCastSession = mSessionManager.currentCastSession
    }

    override fun onDestroy() {
        super.onDestroy()
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java)
    }
}
Java
public class MyActivity extends Activity {
    private CastContext mCastContext;
    private CastSession mCastSession;
    private SessionManager mSessionManager;
    private SessionManagerListener<CastSession> mSessionManagerListener =
            new SessionManagerListenerImpl();

    private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> {
        @Override
        public void onSessionStarting(CastSession session) {}
        @Override
        public void onSessionStarted(CastSession session, String sessionId) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionStartFailed(CastSession session, int error) {
            int castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error);
            // Handle error
        }
        @Override
        public void onSessionSuspended(CastSession session, int reason) {}
        @Override
        public void onSessionResuming(CastSession session, String sessionId) {}
        @Override
        public void onSessionResumed(CastSession session, boolean wasSuspended) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionResumeFailed(CastSession session, int error) {}
        @Override
        public void onSessionEnding(CastSession session) {}
        @Override
        public void onSessionEnded(CastSession session, int error) {
            finish();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCastContext = CastContext.getSharedInstance(this);
        mSessionManager = mCastContext.getSessionManager();
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mCastSession = mSessionManager.getCurrentCastSession();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class);
    }
}

Przenoszenie strumienia

Zachowywanie stanu sesji jest podstawą transferu, gdzie użytkownicy mogą przenosić istniejące strumienie audio i wideo między urządzeniami, używając poleceń głosowych. Google Home Aplikacja lub inteligentne ekrany. Multimedia przestaje się odtwarzać na jednym urządzeniu (źródle) i kontynuuje na innym miejsce docelowe). Każde urządzenie przesyłające z najnowszą wersją oprogramowania może służyć jako źródło lub miejsce docelowe w przesyłanie strumienia.

Aby pobrać nowe urządzenie docelowe podczas przenoszenia lub rozszerzania transmisji: zarejestruj Cast.Listener za pomocą CastSession#addCastListener Następnie zadzwoń CastSession#getCastDevice() podczas wywołania zwrotnego onDeviceNameChanged.

Zobacz Przesyłanie strumienia w internetowym odbiorniku .

Automatyczne ponowne łączenie

Platforma ta zapewnia ReconnectionService który może zostać włączony przez aplikację nadawcy, aby obsługiwał ponowne połączenia w wielu subtelnych etui narożne, takie jak:

  • Odzyskanie połączenia po tymczasowej utracie sieci Wi-Fi
  • Wypoczynek po uśpieniu urządzenia
  • Przywracanie aplikacji w tle
  • Przywracanie systemu w przypadku awarii aplikacji

Ta usługa jest domyślnie włączona, ale można ją wyłączyć w CastOptions.Builder

Ta usługa może zostać automatycznie scalona z plikiem manifestu aplikacji w przypadku automatycznego scalania jest włączona w pliku Gradle.

Platforma uruchamia usługę w momencie wystąpienia sesji multimediów i ją zatrzymuje po zakończeniu sesji multimediów.

Jak działa Sterowanie multimediami

Platforma Cast wycofuje RemoteMediaPlayer klasy z Cast 2.x na nową klasę RemoteMediaClient, który ma te same funkcje w zestawie wygodniejszych interfejsów API; pozwala uniknąć konieczności przekazywania klienta GoogleApiClient.

Gdy aplikacja tworzy CastSession z aplikacją odbiornika internetowego, która obsługuje przestrzeń nazw multimediów, Wartość RemoteMediaClient zostanie automatycznie utworzona przez platformę. aplikacja może aby uzyskać do niego dostęp, wywołaj metodę getRemoteMediaClient() na: CastSession instancji.

Wszystkie metody RemoteMediaClient, które wysyłają żądania do odbiornika internetowego zwraca obiekt PendingResult, który można wykorzystać do śledzenia danego żądania.

Oczekiwana jest sytuacja, w której instancja RemoteMediaClient może być współdzielona przez elementów aplikacji, a także niektórych wewnętrznych komponentów takich jak stałe minikontrolery, korzystać z usługi powiadomień. Z tego względu ta instancja obsługuje rejestrację wielu instancji RemoteMediaClient.Listener

Ustawianie metadanych multimediów

MediaMetadata reprezentuje informacje o elemencie multimedialnym, który chcesz przesyłać. W poniższym przykładzie tworzy się nową instancję MediaMetadata filmu i ustawia tytuł, podtytuł i 2 obrazy.

Kotlin
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)

movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle())
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio())
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(1))))
Java
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);

movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle());
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio());
movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(0))));
movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));

Zobacz Wybór obrazu na temat używania obrazów z metadanymi multimediów.

Wczytaj multimedia

Aplikacja może wczytać element multimedialny, jak pokazano w tym kodzie. Pierwsze użycie MediaInfo.Builder z metadanymi multimediów, MediaInfo instancji. Pobierz RemoteMediaClient z bieżącego CastSession, a następnie wczytaj do niego MediaInfo RemoteMediaClient Używaj RemoteMediaClient do odtwarzania, wstrzymywania itp. sterować aplikacją odtwarzacza multimedialnego działającą na odbiorniku internetowym.

Kotlin
val mediaInfo = MediaInfo.Builder(mSelectedMedia.getUrl())
    .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
    .setContentType("videos/mp4")
    .setMetadata(movieMetadata)
    .setStreamDuration(mSelectedMedia.getDuration() * 1000)
    .build()
val remoteMediaClient = mCastSession.getRemoteMediaClient()
remoteMediaClient.load(MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build())
Java
MediaInfo mediaInfo = new MediaInfo.Builder(mSelectedMedia.getUrl())
        .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
        .setContentType("videos/mp4")
        .setMetadata(movieMetadata)
        .setStreamDuration(mSelectedMedia.getDuration() * 1000)
        .build();
RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());

Zobacz też sekcję na temat za pomocą ścieżek multimedialnych.

Format filmu 4K

Aby sprawdzić format wideo, użyj opcji getVideoInfo() w MediaStatus, aby uzyskać bieżącą instancję VideoInfo Ta instancja zawiera typ formatu telewizora HDR i wysokość wyświetlacza i szerokość w pikselach. Warianty formatu 4K są oznaczone stałymi wartościami HDR_TYPE_*

Zdalne sterowanie powiadomieniami na wiele urządzeń

Gdy użytkownik przesyła treści, inne urządzenia z Androidem w tej samej sieci otrzymują powiadomienie, aby umożliwić im sterowanie odtwarzaniem. Każda osoba, dla którego urządzenia otrzymujące takie powiadomienia, mogą je wyłączyć na tym urządzeniu w Ustawieniach w Google > Google Cast > Pokazuj powiadomienia pilota. (Powiadomienia zawierają skrót do aplikacji Ustawienia). Więcej informacji znajdziesz tutaj: Przesyłanie powiadomień z pilota

Dodaj minikontroler

Zgodnie z projektem obsady Lista kontrolna, aplikacja nadawcy powinna zapewniać trwałą kontrolę nazywaną minimalna kontroler który powinien pojawiać się, gdy użytkownik opuści bieżącą stronę z zawartością i w innej części aplikacji nadawcy. Minikontroler wyświetla widoczne przypomnienie użytkownikowi bieżącej sesji przesyłania. Po dotknięciu minikontrolera użytkownik może wrócić do rozszerzonego widoku kontrolera przesyłającego na pełny ekran.

Platforma udostępnia niestandardowy widok MiniControllerFragment, który można dodać na dole pliku układu każdej aktywności, w której chcesz pokazać minikontroler.

<fragment
    android:id="@+id/castMiniController"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:visibility="gone"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />

Gdy aplikacja nadawcy odtwarza transmisję na żywo wideo lub audio, pakiet SDK automatycznie wyświetla przycisk odtwarzania/zatrzymania w miejscu przycisku odtwarzania/wstrzymania. na minikontrolerze.

Aby ustawić wygląd tytułu i podtytułu tego widoku niestandardowego: oraz o wyborze przycisków, zobacz Dostosuj minikontroler.

Dodaj rozszerzony kontroler

Lista kontrolna projektu Google Cast wymaga, by aplikacja wysyłająca udostępniała rozwinięte kontroler w przypadku multimediów objętych przesyłaniem. Rozwinięty kontroler to pełnoekranowa wersja na minikontroler.

Pakiet Cast SDK udostępnia widżet dla rozszerzonego kontrolera o nazwie ExpandedControllerActivity To jest klasa abstrakcyjna, którą musisz umieścić w podklasie, aby dodać przycisk Cast.

Najpierw utwórz nowy plik zasobów menu, który będzie dostępny dla rozwiniętego kontrolera przycisk Cast:

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

Utwórz nowe zajęcia z rozszerzeniem ExpandedControllerActivity.

Kotlin
class ExpandedControlsActivity : ExpandedControllerActivity() {
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.expanded_controller, menu)
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)
        return true
    }
}
Java
public class ExpandedControlsActivity extends ExpandedControllerActivity {
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.expanded_controller, menu);
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item);
        return true;
    }
}

Teraz zadeklaruj nową aktywność w pliku manifestu aplikacji w tagu application:

<application>
...
<activity
        android:name=".expandedcontrols.ExpandedControlsActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@style/Theme.CastVideosDark"
        android:screenOrientation="portrait"
        android:parentActivityName="com.google.sample.cast.refplayer.VideoBrowserActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>
...
</application>

Edytuj CastOptionsProvider oraz zmień NotificationOptions i CastMediaOptions, aby ustawić nową aktywność jako docelową aktywność:

Kotlin
override fun getCastOptions(context: Context): CastOptions? {
    val notificationOptions = NotificationOptions.Builder()
        .setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
        .build()
    val mediaOptions = CastMediaOptions.Builder()
        .setNotificationOptions(notificationOptions)
        .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
        .build()

    return CastOptions.Builder()
        .setReceiverApplicationId(context.getString(R.string.app_id))
        .setCastMediaOptions(mediaOptions)
        .build()
}
Java
public CastOptions getCastOptions(Context context) {
    NotificationOptions notificationOptions = new NotificationOptions.Builder()
            .setTargetActivityClassName(ExpandedControlsActivity.class.getName())
            .build();
    CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName())
            .build();

    return new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setCastMediaOptions(mediaOptions)
            .build();
}

Zaktualizuj metodę LocalPlayerActivity loadRemoteMedia, aby wyświetlać nowe działanie po wczytaniu zdalnych multimediów:

Kotlin
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    val remoteMediaClient = mCastSession?.remoteMediaClient ?: return

    remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
        override fun onStatusUpdated() {
            val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java)
            startActivity(intent)
            remoteMediaClient.unregisterCallback(this)
        }
    })

    remoteMediaClient.load(
        MediaLoadRequestData.Builder()
            .setMediaInfo(mSelectedMedia)
            .setAutoplay(autoPlay)
            .setCurrentTime(position.toLong()).build()
    )
}
Java
private void loadRemoteMedia(int position, boolean autoPlay) {
    if (mCastSession == null) {
        return;
    }
    final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
    if (remoteMediaClient == null) {
        return;
    }
    remoteMediaClient.registerCallback(new RemoteMediaClient.Callback() {
        @Override
        public void onStatusUpdated() {
            Intent intent = new Intent(LocalPlayerActivity.this, ExpandedControlsActivity.class);
            startActivity(intent);
            remoteMediaClient.unregisterCallback(this);
        }
    });
    remoteMediaClient.load(new MediaLoadRequestData.Builder()
            .setMediaInfo(mSelectedMedia)
            .setAutoplay(autoPlay)
            .setCurrentTime(position).build());
}

Gdy aplikacja nadawcy odtwarza transmisję na żywo wideo lub audio, pakiet SDK automatycznie wyświetla przycisk odtwarzania/zatrzymania w miejscu przycisku odtwarzania/wstrzymania. w rozwiniętym kontrolerze.

Aby ustawić wygląd za pomocą motywów, wybierz przyciski, które mają być wyświetlane. i dodawanie przycisków niestandardowych, zobacz Dostosuj rozszerzony kontroler.

Sterowanie głośnością

Platforma automatycznie zarządza woluminem aplikacji nadawcy. Struktura automatycznie synchronizuje aplikacje nadawcy i adresata, Interfejs użytkownika zawsze zgłasza wolumin określony przez odbiornik internetowy.

Regulacja głośności za pomocą przycisku fizycznego

W Androidzie za pomocą fizycznych przycisków na urządzeniu nadawcy można zmienić sesji przesyłania na odbiorniku internetowym domyślnie na każdym urządzeniu Jelly Bean lub nowsza.

Sterowanie głośnością za pomocą przycisku fizycznego przed Jelly Bean

Aby sterować głośnością odbiornika internetowego za pomocą fizycznych przycisków głośności Urządzenia z Androidem starsze niż Jelly Bean – aplikacja nadawcy powinna zastąpić dispatchKeyEvent w swoich działaniach i zadzwonić CastContext.onDispatchVolumeKeyEventBeforeJellyBean():

Kotlin
class MyActivity : FragmentActivity() {
    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        return (CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
                || super.dispatchKeyEvent(event))
    }
}
Java
class MyActivity extends FragmentActivity {
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        return CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
            || super.dispatchKeyEvent(event);
    }
}

Dodaj opcje sterowania multimediami do powiadomień i ekranu blokady

Tylko na urządzeniach z Androidem lista kontrolna projektowania w Google Cast wymaga aplikacji nadawcy do wdrożyć opcje sterowania multimediami i w zamku ekranu, gdy nadawca przesyła treści, ale aplikacja nadawcy nie jest zaznaczona. platforma zapewnia MediaNotificationService oraz MediaIntentReceiver aby pomóc aplikacji nadawcy tworzyć opcje sterowania multimediami w powiadomieniu i w blokadzie ekranu.

MediaNotificationService działa, gdy nadawca przesyła treści, i wyświetla komunikat powiadomienie z miniaturą obrazu i informacjami o aktualnie przesyłaniu element, przycisk odtwarzania/wstrzymywania i przycisk zatrzymania.

MediaIntentReceiver to BroadcastReceiver, który obsługuje działania użytkowników z: powiadomienie.

Aplikacja może konfigurować powiadomienia i sterowanie multimediami na ekranie blokady NotificationOptions Aplikacja może skonfigurować, które przyciski sterowania mają być wyświetlane w powiadomieniach. które Activity ma się otworzyć, gdy użytkownik kliknie powiadomienie. Działania „If” nie są jawnie podane wartości domyślne, MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK i Użyjemy formatu MediaIntentReceiver.ACTION_STOP_CASTING.

Kotlin
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting".
val buttonActions: MutableList<String> = ArrayList()
buttonActions.add(MediaIntentReceiver.ACTION_REWIND)
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK)
buttonActions.add(MediaIntentReceiver.ACTION_FORWARD)
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING)

// Showing "play/pause" and "stop casting" in the compat view of the notification.
val compatButtonActionsIndices = intArrayOf(1, 3)

// Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds.
// Tapping on the notification opens an Activity with class VideoBrowserActivity.
val notificationOptions = NotificationOptions.Builder()
    .setActions(buttonActions, compatButtonActionsIndices)
    .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS)
    .setTargetActivityClassName(VideoBrowserActivity::class.java.name)
    .build()
Java
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting".
List<String> buttonActions = new ArrayList<>();
buttonActions.add(MediaIntentReceiver.ACTION_REWIND);
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK);
buttonActions.add(MediaIntentReceiver.ACTION_FORWARD);
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING);

// Showing "play/pause" and "stop casting" in the compat view of the notification.
int[] compatButtonActionsIndices = new int[]{1, 3};

// Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds.
// Tapping on the notification opens an Activity with class VideoBrowserActivity.
NotificationOptions notificationOptions = new NotificationOptions.Builder()
    .setActions(buttonActions, compatButtonActionsIndices)
    .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS)
    .setTargetActivityClassName(VideoBrowserActivity.class.getName())
    .build();

Pokazywanie opcji sterowania multimediami z powiadomień i ekranu blokady jest włączone przez i można je wyłączyć, łącząc się setNotificationOptions z wartością null CastMediaOptions.Builder Funkcja ekranu blokady jest obecnie włączona, dopóki masz powiadomienie włączony.

Kotlin
// ... continue with the NotificationOptions built above
val mediaOptions = CastMediaOptions.Builder()
    .setNotificationOptions(notificationOptions)
    .build()
val castOptions: CastOptions = Builder()
    .setReceiverApplicationId(context.getString(R.string.app_id))
    .setCastMediaOptions(mediaOptions)
    .build()
Java
// ... continue with the NotificationOptions built above
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
        .setNotificationOptions(notificationOptions)
        .build();
CastOptions castOptions = new CastOptions.Builder()
        .setReceiverApplicationId(context.getString(R.string.app_id))
        .setCastMediaOptions(mediaOptions)
        .build();

Gdy aplikacja nadawcy odtwarza transmisję na żywo wideo lub audio, pakiet SDK automatycznie wyświetla przycisk odtwarzania/zatrzymania w miejscu przycisku odtwarzania/wstrzymania. na elemencie sterującym powiadomieniami, ale nie na ekranie blokady.

Uwaga: aby wyświetlić opcje ekranu blokady na urządzeniach z systemem starszym niż Lollipop, RemoteMediaClient automatycznie poprosi w Twoim imieniu o fokus.

Obsługa błędów

Aplikacje nadawcy muszą obsługiwać wszystkie błędne wywołania zwrotne i podejmować decyzje, najlepszą odpowiedź na każdy etap cyklu życia Cast. Aplikacja może wyświetlać może wyświetlić użytkownikowi komunikat o błędzie lub może on unieważnić połączenie Odbiornik internetowy.