Cast'i Android Uygulamanıza Entegre Edin

Bu geliştirici kılavuzunda, Android Gönderen SDK'sını kullanarak Android gönderen uygulamanıza Google Cast desteğinin nasıl ekleneceği açıklanmaktadır.

Mobil cihaz veya dizüstü bilgisayar, oynatmayı kontrol eden gönderici, Google Cast cihazı ise içeriği TV'de gösteren alıcı olur.

Gönderen çerçevesi, Cast sınıf kitaplığı ikilisini ve gönderende çalışma zamanında bulunan ilişkili kaynakları ifade eder. Gönderen uygulaması veya Yayın uygulaması, gönderende de çalışan bir uygulamayı ifade eder. Web alıcı uygulaması, Cast özellikli cihazda çalışan HTML uygulamasını ifade eder.

Gönderen çerçevesi, gönderen uygulamasını etkinlikler hakkında bilgilendirmek ve Cast uygulaması yaşam döngüsünün çeşitli durumları arasında geçiş yapmak için eşzamansız bir geri çağırma tasarımı kullanır.

Uygulama akışı

Aşağıdaki adımlarda, gönderen Android uygulaması için genel üst düzey yürütme akışı açıklanmaktadır:

  • Cast çerçevesi, Activity yaşam döngüsüne göre MediaRouter cihaz keşfini otomatik olarak başlatır.
  • Kullanıcı Yayınla düğmesini tıkladığında çerçeve, bulunan Cast cihazlarının listesini içeren Cast iletişim kutusunu gösterir.
  • Kullanıcı bir Cast cihazı seçtiğinde çerçeve, Cast cihazında Web Alıcısı uygulamasını başlatmaya çalışır.
  • Çerçeve, Web Alıcısı uygulamasının başlatıldığını onaylamak için gönderen uygulamasında geri çağırma işlevlerini çağırır.
  • Çerçeve, gönderen ve Web Alıcı uygulamaları arasında bir iletişim kanalı oluşturur.
  • Çerçeve, web alıcısında medya oynatmayı yüklemek ve kontrol etmek için iletişim kanalını kullanır.
  • Çerçeve, medya oynatma durumunu gönderen ve web alıcısı arasında senkronize eder: Kullanıcı, gönderen kullanıcı arayüzü işlemlerini yaptığında çerçeve bu medya kontrol isteklerini web alıcısına iletir ve web alıcısı medya durumu güncellemeleri gönderdiğinde çerçeve, gönderen kullanıcı arayüzünün durumunu günceller.
  • Kullanıcı, Cast cihazıyla bağlantıyı kesmek için Cast düğmesini tıkladığında çerçeve, gönderen uygulamasının Web Alıcısı ile bağlantısını keser.

Google Cast Android SDK'sındaki tüm sınıfların, yöntemlerin ve etkinliklerin kapsamlı bir listesi için Android için Google Cast Gönderen API Referansı başlıklı makaleyi inceleyin. Aşağıdaki bölümlerde, Android uygulamanıza Cast'i ekleme adımları açıklanmaktadır.

Android manifest dosyasını yapılandırma

Uygulamanızın AndroidManifest.xml dosyasında, Cast SDK'sı için aşağıdaki öğeleri yapılandırmanız gerekir:

uses-sdk

Cast SDK'sının desteklediği minimum ve hedef Android API düzeylerini ayarlayın. Şu anda minimum API düzeyi 23, hedef API düzeyi ise 34'tür.

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

android:theme

Uygulamanızın temasını, minimum Android SDK sürümüne göre ayarlayın. Örneğin, kendi temanızı uygulamıyorsanız Lollipop öncesi bir minimum Android SDK sürümünü hedeflerken Theme.AppCompat'ün bir varyantını kullanmanız gerekir.

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

Yayınlama bağlamını başlatma

Çerçeve, tüm çerçeve etkileşimlerini koordine eden CastContext adlı genel bir tekil nesne içerir.

Uygulamanız, CastContext tekil nesneyi başlatmak için gereken seçenekleri sağlamak amacıyla OptionsProvider arayüzünü uygulamalıdır. OptionsProvider, çerçevenin davranışını etkileyen seçenekleri içeren bir CastOptions örneği sağlar. Bunlardan en önemlisi, keşif sonuçlarını filtrelemek ve bir Cast oturumu başlatıldığında Web Alıcı uygulamasını başlatmak için kullanılan Web Alıcı uygulama kimliğidir.

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

Gönderen uygulamanın AndroidManifest.xml dosyasında, uygulanan OptionsProvider'nin tam nitelikli adını bir meta veri alanı olarak beyan etmeniz gerekir:

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

CastContext.getSharedInstance() çağrıldığında CastContext yavaşça başlatılır.

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

Yayınlama UX widget'ları

Cast çerçevesi, Cast Tasarım Kontrol Listesi'ne uygun widget'ları sağlar:

  • Tanıtım amaçlı yer paylaşımı: Çerçeve, alıcı ilk kez kullanılabilir olduğunda kullanıcıya Cast düğmesine dikkat çekmek için gösterilen özel bir görünüm (IntroductoryOverlay) sağlar. Gönderen uygulaması başlık metninin metnini ve konumunu özelleştirebilir.

  • Yayınlama düğmesi: Yayınlama düğmesi, Cast cihazlarının kullanılabilirliğinden bağımsız olarak görünür. Kullanıcı Yayınla düğmesini ilk kez tıkladığında, bulunan cihazların listeleneceği bir Yayınla iletişim kutusu gösterilir. Kullanıcı, cihaz bağlıyken Cast düğmesini tıkladığında mevcut medya meta verileri (ör. başlık, kayıt stüdyosunun adı ve küçük resim) gösterilir veya kullanıcının Cast cihazıyla bağlantısını kesmesine izin verilir. "Yayın düğmesi" bazen "Yayın simgesi" olarak da adlandırılır.

  • Mini Denetleyici: Kullanıcı içerik yayınlarken mevcut içerik sayfasından veya genişletilmiş denetleyiciden gönderen uygulamadaki başka bir ekrana gittiğinde, kullanıcının şu anda yayınlanan medya meta verilerini görmesine ve oynatmayı kontrol etmesine olanak tanımak için ekranın alt kısmında mini denetleyici gösterilir.

  • Genişletilmiş Denetleyici: Kullanıcı içerik yayınlarken medya bildirimini veya mini denetleyiciyi tıklarsa genişletilmiş denetleyici açılır. Bu denetleyici, oynatılan medya meta verilerini gösterir ve medya oynatmayı kontrol etmek için çeşitli düğmeler sunar.

  • Bildirim: Yalnızca Android. Kullanıcı içerik yayınlarken gönderen uygulamasından uzaklaştığında, şu anda yayınlanan medya meta verilerini ve oynatma kontrollerini gösteren bir medya bildirimi gösterilir.

  • Kilit Ekranı: Yalnızca Android. Kullanıcı içerik yayınlarken kilit ekranına gittiğinde (veya cihazın zaman aşımı olduğunda) şu anda yayınlanan medya meta verilerini ve oynatma denetimlerini gösteren bir medya kilit ekranı denetimi gösterilir.

Aşağıdaki kılavuzda, bu widget'ların uygulamanıza nasıl ekleneceği açıklanmaktadır.

Yayın düğmesi ekleme

AndroidMediaRouter API'leri, ikincil cihazlarda medya görüntüleme ve oynatma işlemlerini etkinleştirmek için tasarlanmıştır. MediaRouter API'yi kullanan Android uygulamaları, kullanıcıların Cast cihazı gibi ikincil bir cihazda medya oynatmak için medya yolu seçmesine olanak tanımak amacıyla kullanıcı arayüzlerinin bir parçası olarak bir Cast düğmesi içermelidir.

Çerçeve, Cast button olarak MediaRouteButton eklemeyi çok kolaylaştırır. Öncelikle, xml dosyasına menünüzü tanımlayan bir menü öğesi veya MediaRouteButton eklemeniz ve bunu çerçeveye bağlamak için CastButtonFactory kullanmanız gerekir.

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

Ardından, Activity sınıfınız FragmentActivity sınıfından devralındıysa düzeninize bir MediaRouteButton ekleyebilirsiniz.

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

Bir tema kullanarak Yayınla düğmesinin görünümünü ayarlamak için Yayınla düğmesini özelleştirme başlıklı makaleyi inceleyin.

Cihaz bulmayı yapılandırma

Cihaz keşfi tamamen CastContext tarafından yönetilir. Gönderen uygulama, CastContext'i başlatırken web alıcı uygulama kimliğini belirtir ve isteğe bağlı olarak CastOptions içinde supportedNamespaces ayarlayarak ad alanı filtrelemesi isteyebilir. CastContext, MediaRouter'a dahili olarak referans verir ve aşağıdaki koşullar altında keşif sürecini başlatır:

  • Cihaz bulma gecikmesi ile pil kullanımını dengelemek için tasarlanmış bir algoritmaya göre, gönderen uygulama ön plana girdiğinde keşif bazen otomatik olarak başlatılır.
  • Yayınlama iletişim kutusu açık.
  • Cast SDK'sı bir Cast oturumunu kurtarmaya çalışıyor.

Yayınlama iletişim kutusu kapatıldığında veya gönderen uygulama arka plana geçtiğinde keşif işlemi durdurulur.

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

Oturum yönetiminin işleyiş şekli

Cast SDK'sı, Cast oturumu kavramını sunar. Bu oturumun oluşturulması, bir cihaza bağlanma, Web Alıcı uygulaması başlatma (veya katılma), bu uygulamaya bağlanma ve bir medya kontrol kanalı başlatma adımlarını içerir. Yayın oturumları ve Web Alıcısı yaşam döngüsü hakkında daha fazla bilgi için Web Alıcısı Uygulama yaşam döngüsü kılavuzuna bakın.

Oturumlar, CastContext.getSessionManager() aracılığıyla uygulamanızın erişebildiği SessionManager sınıfı tarafından yönetilir. Tekil oturumlar, Session sınıfının alt sınıflarıyla temsil edilir. Örneğin, CastSession, Cast cihazlarıyla yapılan oturumları temsil eder. Uygulamanız, SessionManager.getCurrentCastSession() aracılığıyla etkin Cast oturumuna erişebilir.

Uygulamanız, oluşturma, askıya alma, devam ettirme ve sonlandırma gibi oturum etkinliklerini izlemek için SessionManagerListener sınıfını kullanabilir. Çerçeve, oturum etkinken anormal/ani bir sonlandırmadan otomatik olarak devam etmeyi dener.

Oturumlar, MediaRouter iletişim kutularındaki kullanıcı hareketlerine yanıt olarak otomatik olarak oluşturulur ve kapatılır.

Uygulamalar, Cast başlatma hatalarını daha iyi anlamak için oturum başlatma hatasını CastReasonCodes olarak dönüştürmek üzere CastContext#getCastReasonCodeForCastStatusCode(int) kullanabilir. Bazı oturum başlatma hatalarının (ör. CastReasonCodes#CAST_CANCELLED) istenen davranış olduğunu ve hata olarak günlüğe kaydedilmemesi gerektiğini unutmayın.

Oturumla ilgili durum değişikliklerinden haberdar olmanız gerekiyorsa bir SessionManagerListener uygulayabilirsiniz. Bu örnekte, bir Activity içindeki CastSession öğesinin kullanılabilirliği dinlenmektedir.

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

Akış aktarma

Oturum durumunu korumak, kullanıcıların sesli komutları, Google Home uygulaması veya akıllı ekranlar kullanarak mevcut ses ve video akışlarını cihazlar arasında taşıyabileceği akış aktarımının temelini oluşturur. Medya, bir cihazda (kaynak) oynatmayı durdurur ve başka bir cihazda (hedef) oynatmaya devam eder. En son donanım yazılımına sahip tüm Cast cihazları, yayın aktarımında kaynak veya hedef olarak kullanılabilir.

Aktarılan veya genişletilen yayın için yeni hedef cihazı almak istiyorsanız CastSession#addCastListener kullanarak bir Cast.Listener kaydedin. Ardından, onDeviceNameChanged geri arama sırasında CastSession#getCastDevice()'i arayın.

Daha fazla bilgi için Web alıcısında aktarma başlıklı makaleyi inceleyin.

Otomatik yeniden bağlantı

Çerçeve, aşağıdakiler gibi birçok hassas durumda yeniden bağlantıyı ele almak için gönderen uygulama tarafından etkinleştirilebilen bir ReconnectionService sağlar:

  • Geçici olarak kesilen kablosuz bağlantıyı kurtarma
  • Cihaz uyku modundan kurtarma
  • Uygulamayı arka plana aldıktan sonra kurtarma
  • Uygulama kilitlenirse kurtarma

Bu hizmet varsayılan olarak etkindir ve CastOptions.Builder'te devre dışı bırakılabilir.

Gradle dosyanızda otomatik birleştirme etkinse bu hizmet, uygulamanızın manifest dosyasıyla otomatik olarak birleştirilebilir.

Çerçeve, medya oturumu olduğunda hizmeti başlatır ve medya oturumu sona erdiğinde durdurur.

Medya Denetimi'nin işleyiş şekli

Cast çerçevesi, Cast 2.x'teki RemoteMediaPlayer sınıfını, daha kullanışlı API'lerde aynı işlevleri sunan ve GoogleApiClient iletme zorunluluğunu ortadan kaldıran yeni bir sınıf RemoteMediaClient ile değiştiriyor.

Uygulamanız, medya ad alanını destekleyen bir Web Alıcısı uygulamasıyla CastSession kurarken çerçeve tarafından otomatik olarak bir RemoteMediaClient örneği oluşturulur. Uygulamanız, CastSession örneğinde getRemoteMediaClient() yöntemini çağırarak bu erişebilir.

Web alıcısına istek gönderen tüm RemoteMediaClient yöntemleri, bu isteği izlemek için kullanılabilecek bir PendingResult nesnesi döndürür.

RemoteMediaClient örneğinin, uygulamanızın birden fazla bölümü ve çerçevenin bazı dahili bileşenleri (ör. kalıcı mini denetleyiciler ve bildirim hizmeti) tarafından paylaşılabileceği beklenir. Bu nedenle, bu örnek RemoteMediaClient.Listener öğesinin birden fazla örneğinin kaydedilmesini destekler.

Medya meta verilerini ayarlama

MediaMetadata sınıfı, yayınlamak istediğiniz medya öğesiyle ilgili bilgileri temsil eder. Aşağıdaki örnekte, bir filmin yeni bir MediaMetadata örneği oluşturulmakta ve başlık, altyazı ve iki resim ayarlanmaktadır.

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

Medya meta verileriyle resim kullanımı hakkında bilgi edinmek için Resim Seçimi bölümüne bakın.

Medya yükleme

Uygulamanız, aşağıdaki kodda gösterildiği gibi bir medya öğesi yükleyebilir. Öncelikle, bir MediaInfo örneği oluşturmak için MediaInfo.Builder ile medya meta verilerini kullanın. Mevcut CastSession'tan RemoteMediaClient'i alın, ardından MediaInfo'i bu RemoteMediaClient'a yükleyin. Web alıcısında çalışan bir medya oynatıcı uygulamasını oynatmak, duraklatmak ve başka şekillerde kontrol etmek için RemoteMediaClient simgesini kullanın.

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

Medya parçalarını kullanma bölümüne de göz atın.

4K video biçimi

Medyanızın video biçimini kontrol etmek için VideoInfo öğesinin geçerli örneğini almak üzere MediaStatus'ta getVideoInfo() öğesini kullanın. Bu örnek, HDR TV biçiminin türünü ve ekranın piksel cinsinden yüksekliğini ve genişliğini içerir. 4K biçiminin varyantları HDR_TYPE_* sabitleriyle gösterilir.

Birden fazla cihaza uzaktan kumanda bildirimleri

Bir kullanıcı içerik yayınlarken aynı ağdaki diğer Android cihazlar da oynatmayı kontrol etmelerine olanak tanıyan bir bildirim alır. Cihazına bu tür bildirimler gelen kullanıcılar, Ayarlar uygulamasında Google > Google Cast > Uzaktan kumanda bildirimlerini göster'i seçerek bildirimleri cihazlarında devre dışı bırakabilir. (Bildirimler, Ayarlar uygulamasının kısayolunu içerir.) Daha fazla bilgi için Yayınlama uzaktan kumandası bildirimleri başlıklı makaleyi inceleyin.

Mini kontrol cihazı ekleme

Cast Tasarım Kontrol Listesi'ne göre, gönderen uygulaması, kullanıcı mevcut içerik sayfasından gönderen uygulamasının başka bir bölümüne gittiğinde görünmesi gereken mini kontrol cihazı olarak bilinen kalıcı bir kontrol sağlamalıdır. Mini kontrol cihazı, kullanıcıya mevcut Cast oturumunu hatırlatan görünür bir hatırlatıcı sağlar. Kullanıcı, mini kumandaya dokunarak Cast tam ekran genişletilmiş kumanda görünümüne geri dönebilir.

Çerçeve, mini denetleyiciyi göstermek istediğiniz her etkinliğin düzen dosyasının alt kısmına ekleyebileceğiniz özel bir görünüm (MiniControllerFragment) sağlar.

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

Gönderen uygulamanız video veya ses canlı yayını oynatırken SDK, mini kumandadaki oynat/duraklat düğmesinin yerine otomatik olarak oynat/durdur düğmesi gösterir.

Bu özel görünümün başlığı ve alt başlığının metin görünümünü ayarlamak ve düğmeleri seçmek için Mini Denetleyici'yi özelleştirme başlıklı makaleyi inceleyin.

Genişletilmiş denetleyici ekleme

Google Cast Tasarım Kontrol Listesi, gönderen uygulamasının Cast edilen medya için genişletilmiş bir kontrolör sağlamasını zorunlu kılar. Genişletilmiş denetleyici, mini denetleyicinin tam ekran sürümüdür.

Cast SDK'sı, genişletilmiş kontrol cihazı için ExpandedControllerActivity adlı bir widget sağlar. Bu, yayınlama düğmesi eklemek için alt sınıf oluşturmanız gereken soyut bir sınıftır.

Öncelikle, genişletilmiş denetleyicinin Yayınla düğmesini sağlaması için yeni bir menü kaynağı dosyası oluşturun:

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

ExpandedControllerActivity sınıfını genişleten yeni bir sınıf oluşturun.

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

Ardından, yeni etkinliğinizi uygulama manifest dosyasında application etiketi içinde beyan edin:

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

Hedef etkinliği yeni etkinliğinize ayarlamak için CastOptionsProvider öğesini düzenleyin ve NotificationOptions ile CastMediaOptions öğelerini değiştirin:

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

Uzak medya yüklendiğinde yeni etkinliğinizi göstermek için LocalPlayerActivity loadRemoteMedia yöntemini güncelleyin:

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

Gönderen uygulamanız bir video veya ses canlı yayını oynatırken SDK, genişletilmiş kumandadaki oynat/duraklat düğmesi yerine otomatik olarak oynat/durdur düğmesi gösterir.

Görünümü temaları kullanarak ayarlamak, hangi düğmelerin gösterileceğini seçmek ve özel düğmeler eklemek için Genişletilmiş Denetleyiciyi Özelleştirme başlıklı makaleyi inceleyin.

Ses düzeyi kontrolü

Çerçeve, gönderen uygulamasının ses seviyesini otomatik olarak yönetir. Çerçeve, gönderen kullanıcı arayüzünün her zaman web alıcısı tarafından belirtilen ses seviyesini bildirmesi için gönderen ve web alıcısı uygulamalarını otomatik olarak senkronize eder.

Fiziksel düğmeyle ses kontrolü

Android'de, Jelly Bean veya sonraki sürümleri kullanan tüm cihazlarda varsayılan olarak web alıcısındaki Cast oturumunun ses seviyesini değiştirmek için gönderen cihazdaki fiziksel düğmeler kullanılabilir.

Jelly Bean'den önceki sürümlerde fiziksel düğme ses seviyesi denetimi

Jelly Bean'den eski Android cihazlarda Web Alıcı cihaz sesini fiziksel ses düğmeleriyle kontrol etmek için gönderen uygulaması, Etkinliklerinde dispatchKeyEvent'yi geçersiz kılmamalı ve CastContext.onDispatchVolumeKeyEventBeforeJellyBean()'i çağırmalıdır:

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

Bildirim ve kilit ekranına medya kontrolleri ekleme

Yalnızca Android'de Google Cast Tasarım Kontrol Listesi, gönderen uygulamasının medya denetimlerini bir bildirime ve gönderenin yayın yaptığı ancak gönderen uygulamasının odağa sahip olmadığı kilitli ekrana uygulamasını gerektirir. Gönderen uygulamanın bildirimde ve kilit ekranında medya kontrolleri oluşturmasına yardımcı olmak için çerçeve MediaNotificationService ve MediaIntentReceiver sağlar.

MediaNotificationService, gönderen içerik yayınlarken çalışır ve küçük resim içeren bir bildirim, mevcut yayın öğesi hakkında bilgi, oynatma/duraklatma ve durdurma düğmesi gösterir.

MediaIntentReceiver, bildirimdeki kullanıcı işlemlerini yöneten bir BroadcastReceiver öğesidir.

Uygulamanız, NotificationOptions aracılığıyla kilit ekranından bildirim ve medya denetimini yapılandırabilir. Uygulamanız, bildirimde hangi kontrol düğmelerinin gösterileceğini ve kullanıcı bildirime dokunduğunda hangi Activity'nin açılacağını yapılandırabilir. İşlemler açıkça sağlanmazsa varsayılan değerler (MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK ve MediaIntentReceiver.ACTION_STOP_CASTING) kullanılır.

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

Bildirim ve kilit ekranından medya denetimlerinin gösterilmesi varsayılan olarak açıktır ve CastMediaOptions.Builder içinde null değeriyle setNotificationOptions çağrılarak devre dışı bırakılabilir. Şu anda kilit ekranı özelliği, bildirim açık olduğu sürece etkindir.

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

Gönderen uygulamanız video veya sesli canlı yayın oynatırken SDK, bildirim kontrolünde oynatma/duraklatma düğmesi yerine otomatik olarak oynatma/durdurma düğmesi gösterir ancak kilit ekranı kontrolünde bu düğmeyi göstermez.

Not: Lollipop öncesi sürümlerin yüklü olduğu cihazlarda kilit ekranı kontrollerini göstermek için RemoteMediaClient, ses odağını sizin adınıza otomatik olarak ister.

Hataları işleme

Gönderen uygulamaların tüm hata geri çağırmalarını işlemesi ve Cast yaşam döngüsünün her aşaması için en iyi yanıtı belirlemesi çok önemlidir. Uygulama, kullanıcıya hata iletişim kutuları gösterebilir veya web alıcısıyla bağlantıyı kesmeye karar verebilir.