این راهنمای برنامهنویس نحوه افزودن پشتیبانی Google Cast را با استفاده از Android Sender SDK به برنامه فرستنده Android خود توضیح میدهد.
دستگاه تلفن همراه یا لپ تاپ فرستنده ای است که پخش را کنترل می کند و دستگاه Google Cast گیرنده ای است که محتوا را روی تلویزیون نمایش می دهد.
چارچوب فرستنده به کتابخانه باینری کلاس Cast و منابع مرتبط موجود در زمان اجرا بر روی فرستنده اشاره دارد. برنامه فرستنده یا برنامه Cast به برنامه ای اشاره دارد که روی فرستنده نیز اجرا می شود. برنامه Web Receiver به برنامه HTML در حال اجرا در دستگاه دارای Cast-enabled اشاره دارد.
چارچوب فرستنده از یک طراحی پاسخ به تماس ناهمزمان برای اطلاع رسانی به برنامه فرستنده از رویدادها و انتقال بین حالت های مختلف چرخه عمر برنامه Cast استفاده می کند.
جریان برنامه
مراحل زیر جریان اجرای معمولی سطح بالا را برای یک برنامه Android فرستنده توضیح می دهد:
- چارچوب Cast به طور خودکار کشف دستگاه
MediaRouter
را بر اساس چرخه حیاتActivity
شروع می کند. - هنگامی که کاربر روی دکمه Cast کلیک میکند، چارچوب گفتگوی Cast را با لیست دستگاههای Cast کشف شده نشان میدهد.
- وقتی کاربر یک دستگاه Cast را انتخاب میکند، چارچوب تلاش میکند تا برنامه Web Receiver را در دستگاه Cast راهاندازی کند.
- این چارچوب برای تأیید راهاندازی برنامه گیرنده وب، تماسهای برگشتی را در برنامه فرستنده فراخوانی میکند.
- این چارچوب یک کانال ارتباطی بین برنامههای فرستنده و گیرنده وب ایجاد میکند.
- این چارچوب از کانال ارتباطی برای بارگیری و کنترل پخش رسانه در گیرنده وب استفاده می کند.
- این فریم ورک حالت پخش رسانه را بین فرستنده و گیرنده وب همگام میکند: زمانی که کاربر اقدامات رابط کاربر فرستنده را انجام میدهد، فریم ورک آن درخواستهای کنترل رسانه را به گیرنده وب ارسال میکند و هنگامی که گیرنده وب بهروزرسانیهای وضعیت رسانه را ارسال میکند، فریم ورک وضعیت را بهروزرسانی میکند. رابط کاربر فرستنده
- هنگامی که کاربر برای قطع ارتباط از دستگاه Cast، روی دکمه Cast کلیک میکند، چارچوب برنامه فرستنده را از گیرنده وب قطع میکند.
برای فهرستی جامع از همه کلاسها، روشها و رویدادها در Google Cast Android SDK، به مرجع API فرستنده Google Cast برای Android مراجعه کنید. بخشهای زیر مراحل اضافه کردن Cast به برنامه Android خود را پوشش میدهند.
مانیفست اندروید را پیکربندی کنید
فایل AndroidManifest.xml برنامه شما به پیکربندی عناصر زیر برای Cast SDK نیاز دارد:
use-sdk
حداقل سطوح Android API را که Cast SDK پشتیبانی میکند، تنظیم کنید. در حال حاضر حداقل سطح API 23 و هدف سطح API 34 است.
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
android:theme
تم برنامه خود را بر اساس حداقل نسخه Android SDK تنظیم کنید. برای مثال، اگر طرح زمینه خود را پیادهسازی نمیکنید، هنگام هدف قرار دادن حداقل نسخه Android SDK که قبل از Lollipop است، باید از یک نوع Theme.AppCompat
استفاده کنید.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
قالب Cast را مقداردهی اولیه کنید
این فریم ورک دارای یک شی تکتنه جهانی به نام CastContext
است که تمام تعاملات چارچوب را هماهنگ میکند.
برنامه شما باید رابط OptionsProvider
را برای ارائه گزینه های مورد نیاز برای مقداردهی اولیه CastContext
singleton پیاده سازی کند. OptionsProvider
نمونه ای از CastOptions
را ارائه می دهد که حاوی گزینه هایی است که بر رفتار چارچوب تأثیر می گذارد. مهمترین آنها شناسه برنامه Web Receiver است که برای فیلتر کردن نتایج کشف و راه اندازی برنامه Web Receiver هنگام شروع جلسه Cast استفاده می شود.
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; } }
شما باید نام کاملا واجد شرایط OptionsProvider
پیاده سازی شده را به عنوان فیلد فراداده در فایل AndroidManifest.xml برنامه فرستنده اعلام کنید:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOptionsProvider" />
</application>
هنگامی که CastContext.getSharedInstance()
فراخوانی می شود، CastContext
به طرز تنبلی مقدار دهی اولیه می شود.
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); } }
ابزارک های Cast UX
چارچوب Cast ابزارکهایی را ارائه میکند که با فهرست چک طراحی Cast مطابقت دارند:
پوشش مقدماتی : این چارچوب یک نمای سفارشی،
IntroductoryOverlay
را ارائه میکند، که به کاربر نشان داده میشود تا در اولین باری که گیرنده در دسترس است، توجه خود را به دکمه Cast جلب کند. برنامه فرستنده می تواند متن و موقعیت متن عنوان را سفارشی کند .دکمه Cast : دکمه Cast بدون توجه به در دسترس بودن دستگاههای Cast قابل مشاهده است. هنگامی که کاربر برای اولین بار روی دکمه Cast کلیک می کند، یک گفتگوی Cast نمایش داده می شود که دستگاه های کشف شده را لیست می کند. هنگامی که کاربر روی دکمه Cast کلیک می کند در حالی که دستگاه متصل است، فوق داده رسانه فعلی (مانند عنوان، نام استودیوی ضبط و یک تصویر کوچک) را نمایش می دهد یا به کاربر اجازه می دهد ارتباط خود را با دستگاه Cast قطع کند. گاهی اوقات از "دکمه Cast" به عنوان "نماد Cast" یاد می شود.
کنترلکننده کوچک : وقتی کاربر در حال ارسال محتوا است و از صفحه محتوای فعلی یا کنترلکننده گسترشیافته دور شده و به صفحه دیگری در برنامه فرستنده رفته است، مینی کنترلکننده در پایین صفحه نمایش داده میشود تا به کاربر اجازه دهد رسانه در حال ارسال را ببیند. ابرداده و کنترل پخش.
Expanded Controller : هنگامی که کاربر در حال ارسال محتوا است، اگر روی اعلان رسانه یا مینی کنترلر کلیک کند، کنترلر توسعه یافته راه اندازی می شود که متادیتای رسانه در حال پخش را نمایش می دهد و چندین دکمه برای کنترل پخش رسانه ارائه می دهد.
اعلان : فقط اندروید. وقتی کاربر در حال ارسال محتوا است و از برنامه فرستنده دور میشود، یک اعلان رسانه نمایش داده میشود که فراداده رسانه در حال ارسال و کنترلهای پخش را نشان میدهد.
قفل صفحه : فقط اندروید. هنگامی که کاربر در حال ارسال محتوا است و به صفحه قفل می رود (یا زمان دستگاه به پایان می رسد)، یک کنترل صفحه قفل رسانه نمایش داده می شود که فراداده رسانه در حال ارسال و کنترل های پخش را نشان می دهد.
راهنمای زیر شامل توضیحاتی در مورد نحوه افزودن این ویجت ها به برنامه شما است.
یک دکمه Cast اضافه کنید
API های Android MediaRouter
برای فعال کردن نمایش و پخش رسانه در دستگاه های ثانویه طراحی شده اند. برنامههای اندرویدی که از MediaRouter
API استفاده میکنند باید یک دکمه Cast را به عنوان بخشی از رابط کاربری خود داشته باشند تا به کاربران اجازه دهد مسیر رسانه را برای پخش رسانه در دستگاه ثانویه مانند دستگاه Cast انتخاب کنند.
این چارچوب اضافه کردن MediaRouteButton
به عنوان Cast button
را بسیار آسان می کند. ابتدا باید یک آیتم منو یا یک MediaRouteButton
را در فایل xml که منوی شما را تعریف می کند، اضافه کنید و از CastButtonFactory
برای اتصال آن به فریمورک استفاده کنید.
// 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; }
سپس، اگر Activity
شما از FragmentActivity
به ارث می رسد، می توانید MediaRouteButton
به طرح بندی خود اضافه کنید.
// 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); }
برای تنظیم ظاهر دکمه Cast با استفاده از یک طرح زمینه، به سفارشی کردن دکمه Cast مراجعه کنید.
پیکربندی کشف دستگاه
کشف دستگاه به طور کامل توسط CastContext
مدیریت می شود. هنگام تنظیم اولیه CastContext، برنامه فرستنده شناسه برنامه Web Receiver را مشخص می کند و می تواند به صورت اختیاری با تنظیم supportedNamespaces
در CastOptions
، فیلتر فضای نام را درخواست کند. CastContext
به طور داخلی یک مرجع به MediaRouter
دارد و فرآیند کشف را تحت شرایط زیر آغاز می کند:
- بر اساس الگوریتمی که برای متعادل کردن تأخیر اکتشاف دستگاه و مصرف باتری طراحی شده است، گهگاه با ورود برنامه فرستنده به پیش زمینه، اکتشاف به صورت خودکار شروع می شود.
- گفتگوی Cast باز است.
- Cast SDK در حال تلاش برای بازیابی یک جلسه Cast است.
هنگامی که گفتگوی Cast بسته شود یا برنامه فرستنده وارد پسزمینه شود، فرآیند کشف متوقف میشود.
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; } }
نحوه عملکرد مدیریت جلسه
Cast SDK مفهوم جلسه Cast را معرفی می کند که ایجاد آن ترکیبی از مراحل اتصال به یک دستگاه، راه اندازی (یا پیوستن) یک برنامه گیرنده وب، اتصال به آن برنامه و راه اندازی یک کانال کنترل رسانه است. برای اطلاعات بیشتر در مورد جلسات Cast و چرخه عمر گیرنده وب، به راهنمای چرخه عمر برنامه گیرنده وب مراجعه کنید.
جلسات توسط کلاس SessionManager
مدیریت می شوند که برنامه شما می تواند از طریق CastContext.getSessionManager()
به آن دسترسی داشته باشد. جلسات فردی توسط زیر کلاس های کلاس Session
نشان داده می شوند. برای مثال، CastSession
جلسات را با دستگاههای Cast نشان میدهد. برنامه شما می تواند از طریق SessionManager.getCurrentCastSession()
به جلسه Cast در حال حاضر فعال دسترسی داشته باشد.
برنامه شما میتواند از کلاس SessionManagerListener
برای نظارت بر رویدادهای جلسه، مانند ایجاد، تعلیق، از سرگیری و خاتمه استفاده کند. چارچوب به طور خودکار تلاش می کند تا زمانی که یک جلسه فعال بود، از یک خاتمه غیرعادی/ ناگهانی از سر گرفته شود.
جلسات به طور خودکار در پاسخ به حرکات کاربر از گفتگوهای MediaRouter
ایجاد و پاره می شوند.
برای درک بهتر خطاهای شروع Cast، برنامهها میتوانند از CastContext#getCastReasonCodeForCastStatusCode(int)
برای تبدیل خطای شروع جلسه به CastReasonCodes
استفاده کنند. لطفاً توجه داشته باشید که برخی از خطاهای شروع جلسه (مثلاً CastReasonCodes#CAST_CANCELLED
) رفتار مورد نظر هستند و نباید به عنوان خطا ثبت شوند.
اگر باید از تغییرات وضعیت جلسه آگاه باشید، می توانید یک SessionManagerListener
را پیاده سازی کنید. این مثال به در دسترس بودن یک CastSession
در یک Activity
گوش می دهد.
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) } }
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); } }
انتقال جریان
حفظ وضعیت جلسه اساس انتقال جریان است، جایی که کاربران میتوانند با استفاده از دستورات صوتی، برنامه Google Home یا نمایشگرهای هوشمند، جریانهای صوتی و تصویری موجود را در دستگاهها جابهجا کنند. پخش رسانه در یک دستگاه (منبع) متوقف می شود و در دستگاه دیگر (مقصد) ادامه می یابد. هر دستگاه Cast با آخرین سیستمافزار میتواند به عنوان منبع یا مقصد در انتقال جریان عمل کند.
برای دریافت دستگاه مقصد جدید در حین انتقال یا گسترش جریان، با استفاده از CastSession#addCastListener
یک Cast.Listener
ثبت کنید. سپس در حین پاسخ به تماس onDeviceNameChanged
CastSession#getCastDevice()
را فراخوانی کنید.
برای اطلاعات بیشتر به انتقال جریان در گیرنده وب مراجعه کنید.
اتصال مجدد خودکار
این چارچوب یک ReconnectionService
را ارائه می دهد که می تواند توسط برنامه فرستنده فعال شود تا اتصال مجدد را در بسیاری از موارد گوشه ای ظریف انجام دهد، مانند:
- بهبودی از از دست دادن موقت WiFi
- بازیابی از خواب دستگاه
- بازیابی از پسزمینه برنامه
- در صورت خراب شدن برنامه بازیابی کنید
این سرویس به طور پیشفرض روشن است و میتوان آن را در CastOptions.Builder
خاموش کرد.
اگر ادغام خودکار در فایل gradle شما فعال باشد، این سرویس می تواند به طور خودکار در مانیفست برنامه شما ادغام شود.
فریم ورک سرویس را هنگامی که جلسه رسانه ای وجود دارد شروع می کند و پس از پایان جلسه رسانه آن را متوقف می کند.
کنترل رسانه چگونه کار می کند
چارچوب Cast کلاس RemoteMediaPlayer
را از Cast 2.x به نفع کلاس جدید RemoteMediaClient
منسوخ میکند، که همان عملکرد را در مجموعهای از APIهای راحتتر ارائه میدهد و از ارسال در GoogleApiClient اجتناب میکند.
هنگامی که برنامه شما یک CastSession
با یک برنامه گیرنده وب ایجاد می کند که از فضای نام رسانه پشتیبانی می کند، یک نمونه از RemoteMediaClient
به طور خودکار توسط چارچوب ایجاد می شود. برنامه شما می تواند با فراخوانی متد getRemoteMediaClient()
در نمونه CastSession
به آن دسترسی داشته باشد.
همه روشهای RemoteMediaClient
که درخواستهایی را به گیرنده وب ارسال میکنند، یک شی PendingResult را برمیگردانند که میتواند برای ردیابی آن درخواست استفاده شود.
انتظار می رود که نمونه RemoteMediaClient
ممکن است توسط چندین بخش از برنامه شما، و در واقع برخی از اجزای داخلی چارچوب، مانند کنترلرهای کوچک دائمی و سرویس اعلان ، به اشتراک گذاشته شود. برای این منظور، این نمونه از ثبت چندین نمونه از RemoteMediaClient.Listener
پشتیبانی می کند.
متادیتا رسانه را تنظیم کنید
کلاس MediaMetadata
اطلاعاتی را در مورد یک آیتم رسانه ای که می خواهید ارسال کنید نشان می دهد. مثال زیر یک نمونه MediaMetadata جدید از یک فیلم ایجاد می کند و عنوان، زیرنویس و دو تصویر را تنظیم می کند.
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))));
به انتخاب تصویر در مورد استفاده از تصاویر با فراداده رسانه مراجعه کنید.
رسانه را بارگیری کنید
همانطور که در کد زیر نشان داده شده است، برنامه شما می تواند یک آیتم رسانه را بارگیری کند. ابتدا از MediaInfo.Builder
با متادیتای رسانه برای ساختن یک نمونه MediaInfo
استفاده کنید. RemoteMediaClient
از CastSession
فعلی دریافت کنید، سپس MediaInfo
در آن RemoteMediaClient
بارگیری کنید. از RemoteMediaClient
برای پخش، توقف موقت و در غیر این صورت کنترل برنامه پخش کننده رسانه در حال اجرا در گیرنده وب استفاده کنید.
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());
همچنین به بخش استفاده از آهنگ های رسانه ای مراجعه کنید.
فرمت ویدیویی 4K
برای بررسی فرمت ویدیوی رسانه شما، از getVideoInfo()
در MediaStatus استفاده کنید تا نمونه فعلی VideoInfo
را دریافت کنید. این نمونه شامل نوع فرمت تلویزیون HDR و ارتفاع و عرض نمایشگر بر حسب پیکسل است. انواع فرمت 4K با ثابت HDR_TYPE_*
نشان داده می شود.
اعلان های کنترل از راه دور به چندین دستگاه
وقتی کاربر در حال ارسال محتوا است، سایر دستگاههای Android در همان شبکه اعلانی دریافت میکنند تا به آنها اجازه کنترل پخش را بدهد. هرکسی که دستگاهش چنین اعلانهایی را دریافت میکند، میتواند آنها را برای آن دستگاه در برنامه تنظیمات در Google > Google Cast > نمایش اعلانهای کنترل از راه دور خاموش کند. (اعلانها شامل میانبری برای برنامه تنظیمات هستند.) برای جزئیات بیشتر، به اعلانهای کنترل از راه دور Cast مراجعه کنید.
مینی کنترلر اضافه کنید
با توجه به چک لیست طراحی Cast ، یک برنامه فرستنده باید یک کنترل دائمی به نام کنترلر کوچک ارائه دهد که وقتی کاربر از صفحه محتوای فعلی به قسمت دیگری از برنامه فرستنده دور میشود، ظاهر شود. مینی کنترلر یک یادآوری قابل مشاهده از جلسه Cast فعلی را به کاربر ارائه می دهد. با ضربه زدن بر روی مینی کنترلر، کاربر می تواند به نمای کنترل کننده گسترده تمام صفحه Cast بازگردد.
این فریم ورک یک نمای سفارشی، MiniControllerFragment را ارائه می دهد، که می توانید آن را به پایین فایل طرح بندی هر فعالیتی که می خواهید کنترلر کوچک را در آن نشان دهید، اضافه کنید.
<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" />
هنگامی که برنامه فرستنده شما در حال پخش جریانی زنده ویدیویی یا صوتی است، SDK به طور خودکار یک دکمه پخش/توقف را به جای دکمه پخش/مکث در کنترلر کوچک نمایش می دهد.
برای تنظیم ظاهر متن عنوان و زیرنویس این نمای سفارشی و انتخاب دکمهها، به Customize Mini Controller مراجعه کنید.
اضافه کردن کنترلر توسعه یافته
فهرست بررسی طراحی Google Cast مستلزم آن است که یک برنامه فرستنده یک کنترلر گسترده برای رسانه در حال Cast ارائه دهد. کنترلر توسعه یافته یک نسخه تمام صفحه از مینی کنترلر است.
Cast SDK ویجتی را برای کنترلر توسعه یافته به نام ExpandedControllerActivity
فراهم می کند. این یک کلاس انتزاعی است که برای اضافه کردن دکمه Cast باید آن را زیر کلاس قرار دهید.
ابتدا یک فایل منبع منوی جدید برای کنترلر توسعه یافته ایجاد کنید تا دکمه 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>
یک کلاس جدید ایجاد کنید که ExpandedControllerActivity
را گسترش دهد.
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; } }
اکنون فعالیت جدید خود را در مانیفست برنامه در تگ 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>
CastOptionsProvider
را ویرایش کنید و NotificationOptions
و CastMediaOptions
را تغییر دهید تا فعالیت هدف را روی فعالیت جدید خود تنظیم کنید:
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(); }
روش LocalPlayerActivity
loadRemoteMedia
را برای نمایش فعالیت جدید خود هنگام بارگیری رسانه راه دور به روز کنید:
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()); }
هنگامی که برنامه فرستنده شما در حال پخش یک پخش زنده ویدیویی یا صوتی است، SDK به طور خودکار یک دکمه پخش/توقف را به جای دکمه پخش/مکث در کنترلر گسترش یافته نمایش می دهد.
برای تنظیم ظاهر با استفاده از تمها، دکمههای نمایش داده شده را انتخاب کنید و دکمههای سفارشی را اضافه کنید، به سفارشی کردن کنترلکننده گسترده مراجعه کنید.
کنترل صدا
چارچوب به طور خودکار حجم برنامه فرستنده را مدیریت می کند. چارچوب به طور خودکار برنامههای فرستنده و گیرنده وب را همگامسازی میکند تا رابط کاربر فرستنده همیشه حجم مشخصشده توسط گیرنده وب را گزارش کند.
کنترل صدا دکمه فیزیکی
در Android، دکمههای فیزیکی دستگاه فرستنده را میتوان برای تغییر صدای جلسه Cast در گیرنده وب بهطور پیشفرض برای هر دستگاهی که از Jelly Bean یا جدیدتر استفاده میکند، استفاده کرد.
کنترل صدا دکمه فیزیکی قبل از Jelly Bean
برای استفاده از کلیدهای حجم فیزیکی برای کنترل صدای دستگاه Web Receiver در دستگاههای Android قدیمیتر از Jelly Bean، برنامه فرستنده باید dispatchKeyEvent
در فعالیتهای خود لغو کند و CastContext.onDispatchVolumeKeyEventBeforeJellyBean()
را فراخوانی کند:
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); } }
کنترل های رسانه را به اعلان و صفحه قفل اضافه کنید
فقط در Android، فهرست چک طراحی Google Cast به یک برنامه فرستنده نیاز دارد تا کنترلهای رسانه را در یک اعلان و در صفحه قفل ، جایی که فرستنده در حال ارسال محتوا است، اما برنامه فرستنده تمرکز ندارد، اجرا کند. این چارچوب MediaNotificationService
و MediaIntentReceiver
را فراهم می کند تا به برنامه فرستنده کمک کند تا کنترل های رسانه را در یک اعلان و در صفحه قفل ایجاد کند.
MediaNotificationService
زمانی اجرا میشود که فرستنده در حال ارسال محتوا است، و یک اعلان با تصویر کوچک تصویر و اطلاعات مورد ارسال فعلی، یک دکمه پخش/مکث و یک دکمه توقف نشان میدهد.
MediaIntentReceiver
یک BroadcastReceiver
است که اقدامات کاربر از اعلان را کنترل می کند.
برنامه شما می تواند اعلان و کنترل رسانه را از صفحه قفل از طریق NotificationOptions
پیکربندی کند. برنامه شما میتواند پیکربندی کند که چه دکمههای کنترلی در اعلان نشان داده شود، و وقتی کاربر روی اعلان ضربه میزند، کدام Activity
باز شود. اگر کنشها به صراحت ارائه نشده باشند، از مقادیر پیشفرض MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
و MediaIntentReceiver.ACTION_STOP_CASTING
استفاده میشود.
// 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();
نمایش کنترلهای رسانه از اعلانها و صفحه قفل بهطور پیشفرض روشن هستند و میتوانند با فراخوانی setNotificationOptions
با null در CastMediaOptions.Builder
غیرفعال شوند. در حال حاضر، تا زمانی که اعلان روشن باشد، ویژگی صفحه قفل فعال است.
// ... 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();
هنگامی که برنامه فرستنده شما در حال پخش جریانی زنده ویدیویی یا صوتی است، SDK به طور خودکار یک دکمه پخش/توقف را به جای دکمه پخش/مکث در کنترل اعلان نمایش می دهد، اما کنترل صفحه قفل را نشان نمی دهد.
توجه : برای نمایش کنترلهای صفحه قفل در دستگاههای قبل از Lollipop، RemoteMediaClient
بهطور خودکار فوکوس صوتی را از طرف شما درخواست میکند.
رسیدگی به خطاها
برای برنامههای فرستنده بسیار مهم است که همه تماسهای خطا را مدیریت کنند و بهترین پاسخ را برای هر مرحله از چرخه حیات Cast تصمیم بگیرند. این برنامه می تواند گفتگوهای خطا را به کاربر نمایش دهد یا می تواند تصمیم بگیرد که اتصال به گیرنده وب را قطع کند.