Bu geliştirici kılavuzunda, Android Gönderen SDK'sını kullanarak Android gönderen uygulamanıza Google Cast desteğini nasıl ekleyeceğiniz açıklanmaktadır.
Mobil cihaz veya dizüstü bilgisayar, oynatmayı kontrol eden gönderen, Google Cast cihazı ise içeriği TV'de görüntüleyen Alıcı'dır.
Gönderen çerçevesi, Cast sınıfı kitaplığının ikili programını ve gönderende çalışma zamanında mevcut olan ilişkili kaynakları ifade eder. Gönderen uygulaması veya Cast uygulaması, gönderende de çalışan bir uygulamayı belirtir. Web Alıcısı uygulaması, Cast uyumlu cihazda çalışan HTML uygulamasını ifade eder.
Gönderen çerçevesi, gönderen uygulamayı 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, bir gönderen Android uygulaması için tipik üst düzey yürütme akışı açıklanmaktadır:
- Cast çerçevesi,
Activity
yaşam döngüsüne göre otomatik olarakMediaRouter
cihaz keşfini başlatır. - Kullanıcı Yayınla düğmesini tıkladığında çerçeve, keşfedilen yayın cihazlarının listesini içeren Yayın iletişim kutusunu gösterir.
- Kullanıcı bir yayın cihazı seçtiğinde, çerçeve yayın cihazında Web Alıcısı uygulamasını başlatmaya çalışır.
- Çerçeve, Web Alıcı uygulamasının başlatıldığını onaylamak için gönderen uygulamasında geri çağırmaları çağırır.
- Çerçeve, gönderen ile Web Alıcı uygulamaları arasında bir iletişim kanalı oluşturur.
- Çerçeve, medya oynatma listesini Web Alıcısı'na yüklemek ve kontrol etmek için iletişim kanalını kullanır.
- Çerçeve, medya oynatma durumunu gönderen ile Web Alıcısı arasında senkronize eder: Kullanıcı, gönderen kullanıcı arayüzü işlemleri yaptığında çerçeve, bu medya kontrolü isteklerini Web Alıcısına iletir. Web Alıcısı medya durumu güncellemelerini gönderdiğinde çerçeve, gönderenin kullanıcı arayüzünün durumunu günceller.
- Kullanıcı, yayın cihazıyla olan bağlantıyı kesmek için Yayın düğmesini tıkladığında çerçeve, gönderen uygulamanın Web Alıcısı ile bağlantısını keser.
Google Cast Android SDK'sındaki tüm sınıf, yöntem ve etkinliklerin kapsamlı bir listesi için Android için Google Cast Gönderen API Referansı'na bakın. Aşağıdaki bölümlerde, Cast'i Android uygulamanıza ekleme adımları ele alınmaktadır.
Android manifestini yapılandırma
Uygulamanızın AndroidManifest.xml dosyası, Cast SDK'sı için aşağıdaki öğeleri yapılandırmanızı gerektirir:
uses-sdk
Cast SDK'nın desteklediği minimum ve hedef Android API düzeylerini ayarlayın. Şu anda minimum değer API düzeyi 21, hedef ise API düzeyi 28'dir.
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="28" />
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 minimum Android SDK sürümünü hedeflerken Theme.AppCompat
varyantını kullanmanız gerekir.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
Yayın bağlamını başlatma
Çerçevede, çerçevenin tüm etkileşimlerini koordine eden genel bir tekil nesne (CastContext
) bulunur.
Uygulamanız, CastContext
single'ını 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ğini sağlar. Bunlardan en önemlisi, keşif sonuçlarını filtrelemek ve bir Yayın oturumu başlatıldığında Web Alıcısı uygulamasını başlatmak için kullanılan Web Alıcısı uygulama kimliğidir.
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 } }
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; } }
Uygulanan OptionsProvider
öğesinin tam nitelikli adını, gönderen uygulamanın AndroidManifest.xml dosyasında 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
geçitle başlatılır.
class MyActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val castContext = CastContext.getSharedInstance(this) } }
public class MyActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { CastContext castContext = CastContext.getSharedInstance(this); } }
Yayınlama Kullanıcı Deneyimi Widget'ları
Yayın çerçevesi, Yayın Tasarımı Kontrol Listesi'ne uygun widget'lar sağlar:
Tanıtım Yer Paylaşımı: Çerçeve, bir alıcı ilk kez kullanılabilir olduğunda Yayınla düğmesine dikkat etmesi için kullanıcıya gösterilen özel bir Görünüm
IntroductoryOverlay
sağlar. Gönderen uygulaması metni ve başlık metninin konumunu özelleştirebilir.Yayınla Düğmesi: Uygulamanızı destekleyen bir alıcı bulunduğunda Yayınla düğmesi görünür. Kullanıcı, Yayın düğmesini ilk kez tıkladığında, bulunan cihazları listeleyen bir Yayınlama iletişim kutusu gösterilir. Cihaz bağlıyken kullanıcı Yayınla düğmesini tıkladığında, geçerli medya meta verilerini (başlık, kayıt stüdyosunun adı ve küçük resim gibi) görüntüler veya kullanıcının Yayın cihazıyla olan bağlantısını kesmesine olanak tanır.
Mini Denetleyici: Kullanıcı içerik yayınlarken mevcut içerik sayfasından veya genişletilmiş denetleyiciden gönderen uygulamasındaki başka bir ekrana gittiğinde mini denetleyici ekranın alt kısmında görüntülenir. Böylece kullanıcının yayınlamakta olduğu medya meta verilerini görebilir ve oynatmayı kontrol edebilir.
Genişletilmiş Denetleyici: Kullanıcı içerik yayınlarken medya bildirimini veya mini denetleyiciyi tıklarsa genişletilmiş denetleyici açılır. Bu denetleyici, o anda oynatılan medya meta verilerini görüntüler ve medya oynatmayı kontrol etmek için çeşitli düğmeler sağlar.
Bildirim: Yalnızca Android. Kullanıcı içerik yayınlarken gönderen uygulamasından ayrıldığında, geçerli olarak yayınlanan medya meta verilerini ve oynatma kontrollerini gösteren bir medya bildirimi görüntülenir.
Kilit Ekranı: Yalnızca Android. Kullanıcı içerik yayınlarken (veya cihaz zaman aşımına uğradığında) kilit ekranına gittiğinde, o anda yayınlanan medya meta verilerini ve oynatma kontrollerini gösteren bir medya kilit ekranı kontrolü görüntülenir.
Aşağıdaki kılavuzda, bu widget'ların uygulamanıza nasıl ekleneceğiyle ilgili açıklamalar bulunmaktadır.
Yayınla Düğmesi Ekle
Android MediaRouter
API'leri, ikincil cihazlarda medya görüntülemeyi ve oynatmayı etkinleştirmek için tasarlanmıştır.
MediaRouter
API'yi kullanan Android uygulamalarında, kullanıcıların yayın cihazı gibi ikincil bir cihazda medya oynatmak için bir medya rotası seçmelerine olanak tanımak amacıyla kullanıcı arayüzlerinin bir parçası olarak Yayınla düğmesi bulunmalıdır.
Çerçeve, MediaRouteButton
'i Cast button
olarak eklemeyi çok kolay hale getirir. Öncelikle menünüzü tanımlayan bir menü öğesi veya MediaRouteButton
dosyasına menünüzü tanımlayan bir MediaRouteButton
eklemeniz ve CastButtonFactory
ile bunu çerçeveye bağlamanı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" />
// 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 }
// 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
öğesi FragmentActivity
öğesinden devralıyorsa 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>
// 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) }
// 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); }
Yayınla düğmesinin görünümünü tema kullanarak ayarlamak için Yayınla Düğmesini Özelleştirme konusuna bakın.
Cihaz bulmayı yapılandırın
Cihaz keşfi tamamen CastContext
tarafından yönetilir.
CastContext'i başlatırken, gönderen uygulaması, Web Alıcısı uygulama kimliğini belirtir ve isteğe bağlı olarak CastOptions
içindeki supportedNamespaces
ayarını yaparak ad alanı filtrelemesi için istekte bulunabilir.
CastContext
, dahili olarak MediaRouter
referansına sahiptir ve gönderen uygulaması ön plana girdiğinde keşif sürecini başlatır, gönderen uygulaması arka plana girdiğinde ise durur.
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 } }
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ı; cihaza bağlanma, Web Alıcısı uygulamasını başlatma (veya buna katılma), uygulamaya bağlanma ve medya kontrol kanalını başlatma adımlarının birleştirildiği Cast oturumu kavramını kullanıma sunar. 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, uygulamanızın CastContext.getSessionManager()
aracılığıyla erişebildiği SessionManager
sınıfı tarafından yönetilir.
Ayrı oturumlar Session
sınıfının alt sınıflarıyla temsil edilir.
Örneğin, CastSession
yayın cihazlarıyla yapılan oturumları temsil eder. Uygulamanız, şu anda etkin olan Yayın oturumuna SessionManager.getCurrentCastSession()
üzerinden 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, bir oturum aktifken otomatik olarak anormal/ani sonlandırmadan devam etmeye çalışır.
Oturumlar, MediaRouter
iletişim kutularından gelen kullanıcı hareketlerine yanıt olarak otomatik olarak oluşturulur ve kısaltılır.
Yayınlama başlatma hatalarını daha iyi anlamak için uygulamalar CastContext#getCastReasonCodeForCastStatusCode(int)
aracını kullanarak oturum başlatma hatasını CastReasonCodes
'e dönüştürebilir.
Bazı oturum başlatma hatalarının (ör. CastReasonCodes#CAST_CANCELLED
) amaçlanan davranış olduğunu ve hata olarak günlüğe kaydedilmemesi gerektiğini lütfen unutmayın.
Oturumla ilgili durum değişiklikleri hakkında bilgi sahibi olmanız gerekiyorsa SessionManagerListener
öğesini uygulayabilirsiniz. Bu örnek, Activity
içindeki bir CastSession
öğesinin kullanılabilirliğini dinler.
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 } override fun onResume() { super.onResume() mCastSession = mSessionManager.currentCastSession mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onPause() { super.onPause() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java) mCastSession = null } }
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(); } @Override protected void onResume() { super.onResume(); mCastSession = mSessionManager.getCurrentCastSession(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onPause() { super.onPause(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); mCastSession = null; } }
Akış aktarma
Oturum durumunun korunması, akış aktarımının temelini oluşturur. Bu aşamada kullanıcılar, mevcut ses ve video akışlarını sesli komutlar, Google Home uygulaması veya akıllı ekranlar kullanarak cihazlar arasında taşıyabilir. Medyanın oynatılması bir cihazda (kaynak) durdurulur ve başka bir cihazda (hedef) devam eder. En yeni donanım yazılımına sahip her yayın cihazı, akış aktarımında kaynak veya hedef olarak kullanılabilir.
Akış aktarımı veya genişletme sırasında yeni hedef cihazı almak için CastSession#addCastListener
kullanarak bir Cast.Listener
kaydedin.
Ardından onDeviceNameChanged
geri çağırma sırasında CastSession#getCastDevice()
numaralı telefonu arayın.
Daha fazla bilgi için Web Alıcısı'nda akış aktarımı bölümüne bakın.
Otomatik yeniden bağlanma
Çerçeve, gönderen uygulama tarafından etkinleştirilebilen bir ReconnectionService
sağlar. Bu özellik, aşağıdakiler gibi birçok ince örnekte yeniden bağlanmayı sağlar:
- Geçici kablosuz ağ kaybından kurtarma
- Cihaz uyku modundan çık
- Uygulamayı arka plandan kurtarma
- Uygulama kilitlenirse kurtarma
Bu hizmet varsayılan olarak etkin olup CastOptions.Builder
ürününde devre dışı bırakılabilir.
Gradle dosyanızda otomatik birleştirme etkinse bu hizmet otomatik olarak uygulamanızın manifest dosyasıyla birleştirilebilir.
Çerçeve, bir medya oturumu olduğunda hizmeti başlatır ve medya oturumu sona erdiğinde hizmeti durdurur.
Medya Denetimi nasıl çalışır?
Cast çerçevesi, Cast 2.x'teki RemoteMediaPlayer
sınıfını kullanımdan kaldırıp yerini yeni RemoteMediaClient
sınıfını kullanmaya bırakıyor. Bu sınıf, aynı işlevselliği daha kullanışlı bir dizi API'de sağlar ve GoogleApiClient ile geçiş yapmak zorunda kalmaz.
Uygulamanız, medya ad alanını destekleyen bir Web Alıcısı uygulamasıyla bir CastSession
oluşturduğunda, çerçeve tarafından otomatik olarak RemoteMediaClient
örneği oluşturulur. Uygulamanız, CastSession
örneğinde getRemoteMediaClient()
yöntemini çağırarak buna 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 birçok bölümü ve aslında çerçevenin kalıcı mini denetleyiciler ve bildirim hizmeti gibi bazı dahili bileşenleri tarafından paylaşılması beklenir.
Bu amaçla, bu örnek birden fazla RemoteMediaClient.Listener
örneğinin kaydedilmesini destekler.
Medya meta verilerini ayarla
MediaMetadata
sınıfı, Yayınlamak istediğiniz bir medya öğesiyle ilgili bilgileri temsil eder. Aşağıdaki örnek, bir filmin yeni MediaMetadata örneğini oluşturur ve başlık, alt başlık ve iki resmi ayarlar.
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))))
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 verileri içeren resimlerin kullanımı hakkında Resim Seçimi bölümüne bakın.
Medya yükle
Uygulamanız, aşağıdaki kodda gösterildiği gibi bir medya öğesi yükleyebilir. Bir MediaInfo
örneği oluşturmak için önce medyanın meta verileriyle MediaInfo.Builder
aracını kullanın. Geçerli CastSession
öğesinden RemoteMediaClient
öğesini alın, ardından MediaInfo
öğesini bu RemoteMediaClient
öğesine yükleyin. Web Alıcısı'nda çalışan bir medya oynatıcı uygulamasını oynatmak, duraklatmak ve başka bir şekilde kontrol etmek için RemoteMediaClient
uygulamasını kullanın.
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())
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());
Ayrıca, medya parçalarını kullanma ile ilgili bölüme de bakın.
4K video biçimi
Medyanızın hangi video biçimini kontrol ettiğini kontrol etmek için MediaStatus'da getVideoInfo()
kullanarak geçerli VideoInfo
örneğini alın.
Bu örnekte, HDR TV biçimi türü ve ekran yüksekliği ile genişliğini piksel cinsinden belirtir. 4K biçiminin varyantları sabit değerlerle HDR_TYPE_*
gösterilir.
Birden fazla cihaza uzaktan kumandayla bildirim gönderilir
Bir kullanıcı yayın yaparken aynı ağdaki diğer Android cihazlar da oynatmayı kontrol edebilmesini sağlayan bir bildirim alır. Cihazı bu tür bildirimleri alan herkes, Google > Google Cast > Uzaktan kumanda bildirimlerini göster'deki Ayarlar uygulaması'ndan söz konusu cihaz için bildirimleri kapatabilir. (Bildirimlerde, Ayarlar uygulamasının bir kısayolu bulunur.) Daha fazla bilgi için Uzaktan kumanda bildirimlerini yayınlama bölümünü inceleyin.
Mini kumanda ekleyin
Yayın Tasarımı Kontrol Listesi'ne göre, gönderen uygulaması mini denetleyici olarak bilinen ve 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 kalıcı bir denetim sağlamalıdır. Mini kumanda, kullanıcıya geçerli yayın oturumuyla ilgili görünür bir hatırlatıcı sağlar. Kullanıcılar mini kumandaya dokunarak tam ekran yayın 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 en altına ekleyebileceğiniz özel bir Görünüm olan 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 bir video veya sesli canlı yayın oynatırken SDK, mini kumandadaki oynat/duraklat düğmesinin yerine otomatik olarak bir oynat/durdur düğmesi görüntüler.
Bu özel görünümün başlık ve alt başlık metin görünümünü ayarlamak ve düğmeleri seçmek için Mini Denetleyiciyi Özelleştirme bölümüne bakın.
Genişletilmiş kumanda ekle
Google Cast Tasarım Kontrol Listesi, bir gönderenin uygulamanın Yayınlanacak medya için genişletilmiş denetleyici olmasını gerektirir. Genişletilmiş kumanda, mini kumandanın tam ekran sürümüdür.
Cast SDK'sı, genişletilmiş kumanda için ExpandedControllerActivity
adlı bir widget sağlar.
Bu, Yayınla düğmesi eklemek için alt sınıfa getirmeniz gereken soyut bir sınıftır.
Öncelikle, Yayınla düğmesini sağlaması amacıyla genişletilmiş denetleyici için yeni bir menü kaynak 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
kapsamını genişleten yeni bir sınıf oluşturun.
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 } }
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; } }
Şimdi yeni etkinliklerinizi, uygulama manifestinizde application
etiketinde 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>
CastOptionsProvider
öğesini düzenleyin ve hedef aktiviteyi yeni etkinliğinize ayarlamak için
NotificationOptions
ve CastMediaOptions
değerlerini değiştirin:
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() }
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örüntülemek için LocalPlayerActivity
loadRemoteMedia
yöntemini güncelleyin:
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() ) }
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 sesli canlı yayın oynatırken SDK, genişletilmiş kumandadaki oynat/duraklat düğmesinin yerine otomatik olarak bir oynat/durdur düğmesi gösterir.
Görünümü temaları kullanarak ayarlamak için hangi düğmelerin gösterileceğini seçin ve özel düğmeler ekleyin. Genişletilmiş Denetleyiciyi Özelleştirme bölümüne bakın.
Ses düzeyi kontrolü
Çerçeve, gönderen uygulama için ses düzeyini otomatik olarak yönetir. Çerçeve, gönderen ve Web Alıcısı uygulamalarını otomatik olarak senkronize eder. Böylece gönderen kullanıcı arayüzü, her zaman Web Alıcısı tarafından belirtilen hacmi bildirir.
Fiziksel düğme ses seviyesi kontrolü
Android'de, gönderen cihazındaki fiziksel düğmeler, Jelly Bean veya daha yeni sürümleri kullanan herhangi bir cihazda Web Alıcısı'ndaki Yayın oturumunun ses düzeyini varsayılan olarak değiştirmek için kullanılabilir.
Jelly Bean'den önceki fiziksel düğme ses seviyesi kontrolü
Jelly Bean'den daha eski Android cihazlarda Web Alıcısı cihazın ses düzeyini kontrol etmek üzere fiziksel ses tuşlarını kullanmak için, gönderen uygulaması, Etkinliklerindeki dispatchKeyEvent
ayarını geçersiz kılmalı ve CastContext.onDispatchVolumeKeyEventBeforeJellyBean()
numaralı telefonu aramalıdır:
class MyActivity : FragmentActivity() { override fun dispatchKeyEvent(event: KeyEvent): Boolean { return (CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event)) } }
class MyActivity extends FragmentActivity { @Override public boolean dispatchKeyEvent(KeyEvent event) { return CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event); } }
Bildirimlere ve kilit ekranına medya denetimleri ekleme
Yalnızca Android'de Google Cast Tasarım Kontrol Listesi, gönderenin uygulamanın bildirimde medya kontrollerini uygulamasını ve gönderenin yayın yaptığı ancak gönderenin uygulamanın odaklanmadığı kilit ekranında olmasını gerektirir. Çerçeve, gönderen uygulamanın bir bildirimde ve kilit ekranında medya denetimleri oluşturmasına yardımcı olmak için MediaNotificationService
ve MediaIntentReceiver
hizmetlerini sağlar.
MediaNotificationService
, gönderen yayındayken çalışır ve küçük resim ile mevcut yayınlama öğesiyle ilgili bilgileri, oynat/duraklat düğmesi ve durdurma düğmesini içeren bir bildirim gösterir.
MediaIntentReceiver
, bildirimdeki kullanıcı işlemlerini işleyen bir BroadcastReceiver
'dir.
Uygulamanız, kilit ekranından NotificationOptions
aracılığıyla bildirim ve medya kontrolünü yapılandırabilir.
Uygulamanız, bildirimde hangi kontrol düğmelerinin gösterileceğini ve kullanıcı bildirime dokunduğunda hangi Activity
cihazının açılacağını yapılandırabilir. İşlemler açıkça sağlanmazsa varsayılan değerler olan MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
ve MediaIntentReceiver.ACTION_STOP_CASTING
kullanılır.
// 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()
// 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ındaki medya denetimlerinin gösterilmesi varsayılan olarak etkindir ve CastMediaOptions.Builder
içinde null özellikli setNotificationOptions
çağrısı yapılarak devre dışı bırakılabilir.
Şu anda kilit ekranı özelliği, bildirim etkin olduğu sürece etkindir.
// ... 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()
// ... 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 bir video veya sesli canlı yayın oynatırken SDK, bildirim kontrolündeki oynat/duraklat düğmesinin yerine otomatik olarak bir oynat/durdur düğmesi gösterir, ancak kilit ekranı kontrolünde göstermez.
Not: Lollipop öncesi cihazlarda kilit ekranı kontrollerini görüntülemek için
RemoteMediaClient
, sizin adınıza otomatik olarak ses odaklama isteğinde bulunur.
Hataları işleme
Gönderen uygulamalarının tüm hata geri çağırmalarını işlemesi ve Yayın yaşam döngüsünün her aşamasında en iyi yanıtı belirlemesi çok önemlidir. Uygulama, kullanıcıya hata iletişim kutuları görüntüleyebilir veya Web Alıcısı ile bağlantıyı kesmeye karar verebilir.