Output Switcher یکی از ویژگیهای Cast SDK است که انتقال بیوقفه بین پخش محلی و از راه دور محتوا را با شروع Android 13 امکانپذیر میکند. هدف کمک به برنامههای فرستنده است که به راحتی و به سرعت مکان پخش محتوا را کنترل کنند. Output Switcher از کتابخانه MediaRouter
برای تغییر پخش محتوا بین بلندگوی تلفن، دستگاههای بلوتوث جفت شده و دستگاههای دارای قابلیت Cast از راه دور استفاده میکند. موارد استفاده را می توان به سناریوهای زیر تقسیم کرد:
برای مرجع نحوه پیاده سازی Output Switcher در برنامه خود ، برنامه نمونه CastVideos-android را دانلود و استفاده کنید.
Switcher خروجی باید برای پشتیبانی از محلی به راه دور، از راه دور به محلی و از راه دور به راه دور با استفاده از مراحل ارائه شده در این راهنما فعال باشد. هیچ مرحله اضافی برای پشتیبانی از انتقال بین بلندگوهای دستگاه محلی و دستگاه های بلوتوث جفت شده مورد نیاز نیست.
رابط کاربری سوئیچر خروجی
سوئیچر خروجی دستگاه های محلی و راه دور موجود و همچنین وضعیت فعلی دستگاه را نشان می دهد، از جمله در صورت انتخاب دستگاه، در حال اتصال، سطح صدای فعلی. اگر علاوه بر دستگاه فعلی، دستگاههای دیگری نیز وجود دارد، کلیک کردن روی دستگاه دیگر به شما امکان میدهد پخش رسانه را به دستگاه انتخابی منتقل کنید.
مسائل شناخته شده
- وقتی به اعلان Cast SDK بروید، جلسات رسانه ایجاد شده برای پخش محلی رد میشوند و دوباره ایجاد میشوند.
امتیاز ورودی
اطلاع رسانی رسانه ای
اگر یک برنامه یک اعلان رسانه با MediaSession
برای پخش محلی (پخش محلی) پست کند، گوشه سمت راست بالای اعلان رسانه یک تراشه اعلان را با نام دستگاه (مانند بلندگوی تلفن) که محتوا در حال پخش با آن است، نشان میدهد. با ضربه زدن بر روی تراشه اعلان، رابط کاربری سیستم گفت و گوی Output Switcher باز می شود.
تنظیمات میزان صدا
همچنین میتوانید با کلیک کردن روی دکمههای حجم فیزیکی دستگاه، ضربه زدن روی نماد تنظیمات در پایین، و ضربه زدن روی متن «Play <App Name> در <Cast Device>» فعال شود.
خلاصه مراحل
- از رعایت پیش نیازها اطمینان حاصل کنید
- گزینه Output Switcher را در AndroidManifest.xml فعال کنید
- SessionManagerListener را برای پخش پسزمینه بهروزرسانی کنید
- پشتیبانی از Remote-to-Remote را اضافه کنید
- پرچم setRemoteToLocalEnabled را تنظیم کنید
- پخش محلی را ادامه دهید
پیش نیازها
- برنامه اندروید موجود خود را به AndroidX منتقل کنید.
-
build.gradle
برنامه خود را بهروزرسانی کنید تا از حداقل نسخه مورد نیاز Android Sender SDK برای خروجی Switcher استفاده کنید:dependencies { ... implementation 'com.google.android.gms:play-services-cast-framework:21.2.0' ... }
- برنامه از اعلان های رسانه پشتیبانی می کند.
- دستگاه دارای اندروید 13.
اعلانهای رسانه را تنظیم کنید
برای استفاده از سوئیچر خروجی، برنامههای صوتی و تصویری باید یک اعلان رسانه ایجاد کنند تا وضعیت پخش و کنترلهای رسانه خود را برای پخش محلی نمایش دهد. این کار مستلزم ایجاد MediaSession
، تنظیم MediaStyle
با توکن MediaSession
و تنظیم کنترلهای رسانه در اعلان است.
اگر در حال حاضر از MediaStyle
و MediaSession
استفاده نمیکنید، قطعه زیر نحوه تنظیم آنها را نشان میدهد و راهنماهایی برای تنظیم تماسهای جلسه رسانه برای برنامههای صوتی و تصویری موجود است:
// Create a media session. NotificationCompat.MediaStyle // PlayerService is your own Service or Activity responsible for media playback. val mediaSession = MediaSessionCompat(this, "PlayerService") // Create a MediaStyle object and supply your media session token to it. val mediaStyle = Notification.MediaStyle().setMediaSession(mediaSession.sessionToken) // Create a Notification which is styled by your MediaStyle object. // This connects your media session to the media controls. // Don't forget to include a small icon. val notification = Notification.Builder(this@PlayerService, CHANNEL_ID) .setStyle(mediaStyle) .setSmallIcon(R.drawable.ic_app_logo) .build() // Specify any actions which your users can perform, such as pausing and skipping to the next track. val pauseAction: Notification.Action = Notification.Action.Builder( pauseIcon, "Pause", pauseIntent ).build() notification.addAction(pauseAction)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { // Create a media session. NotificationCompat.MediaStyle // PlayerService is your own Service or Activity responsible for media playback. MediaSession mediaSession = new MediaSession(this, "PlayerService"); // Create a MediaStyle object and supply your media session token to it. Notification.MediaStyle mediaStyle = new Notification.MediaStyle().setMediaSession(mediaSession.getSessionToken()); // Specify any actions which your users can perform, such as pausing and skipping to the next track. Notification.Action pauseAction = Notification.Action.Builder(pauseIcon, "Pause", pauseIntent).build(); // Create a Notification which is styled by your MediaStyle object. // This connects your media session to the media controls. // Don't forget to include a small icon. String CHANNEL_ID = "CHANNEL_ID"; Notification notification = new Notification.Builder(this, CHANNEL_ID) .setStyle(mediaStyle) .setSmallIcon(R.drawable.ic_app_logo) .addAction(pauseAction) .build(); }
علاوه بر این، برای پر کردن اعلان با اطلاعات رسانه خود، باید فراداده و وضعیت پخش رسانه خود را به MediaSession
اضافه کنید.
برای افزودن متادیتا به MediaSession
، از setMetaData()
استفاده کنید و تمام ثابت های MediaMetadata
مربوطه را برای رسانه خود در MediaMetadataCompat.Builder()
ارائه دهید.
mediaSession.setMetadata(MediaMetadataCompat.Builder() // Title .putString(MediaMetadata.METADATA_KEY_TITLE, currentTrack.title) // Artist // Could also be the channel name or TV series. .putString(MediaMetadata.METADATA_KEY_ARTIST, currentTrack.artist) // Album art // Could also be a screenshot or hero image for video content // The URI scheme needs to be "content", "file", or "android.resource". .putString( MediaMetadata.METADATA_KEY_ALBUM_ART_URI, currentTrack.albumArtUri) ) // Duration // If duration isn't set, such as for live broadcasts, then the progress // indicator won't be shown on the seekbar. .putLong(MediaMetadata.METADATA_KEY_DURATION, currentTrack.duration) .build() )
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { mediaSession.setMetadata( new MediaMetadataCompat.Builder() // Title .putString(MediaMetadata.METADATA_KEY_TITLE, currentTrack.title) // Artist // Could also be the channel name or TV series. .putString(MediaMetadata.METADATA_KEY_ARTIST, currentTrack.artist) // Album art // Could also be a screenshot or hero image for video content // The URI scheme needs to be "content", "file", or "android.resource". .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, currentTrack.albumArtUri) // Duration // If duration isn't set, such as for live broadcasts, then the progress // indicator won't be shown on the seekbar. .putLong(MediaMetadata.METADATA_KEY_DURATION, currentTrack.duration) .build() ); }
برای افزودن حالت پخش به MediaSession
، از setPlaybackState()
استفاده کنید و تمام ثابت های PlaybackStateCompat
مربوطه را برای رسانه خود در PlaybackStateCompat.Builder()
ارائه دهید.
mediaSession.setPlaybackState( PlaybackStateCompat.Builder() .setState( PlaybackStateCompat.STATE_PLAYING, // Playback position // Used to update the elapsed time and the progress bar. mediaPlayer.currentPosition.toLong(), // Playback speed // Determines the rate at which the elapsed time changes. playbackSpeed ) // isSeekable // Adding the SEEK_TO action indicates that seeking is supported // and makes the seekbar position marker draggable. If this is not // supplied seek will be disabled but progress will still be shown. .setActions(PlaybackStateCompat.ACTION_SEEK_TO) .build() )
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { mediaSession.setPlaybackState( new PlaybackStateCompat.Builder() .setState( PlaybackStateCompat.STATE_PLAYING, // Playback position // Used to update the elapsed time and the progress bar. mediaPlayer.currentPosition.toLong(), // Playback speed // Determines the rate at which the elapsed time changes. playbackSpeed ) // isSeekable // Adding the SEEK_TO action indicates that seeking is supported // and makes the seekbar position marker draggable. If this is not // supplied seek will be disabled but progress will still be shown. .setActions(PlaybackStateCompat.ACTION_SEEK_TO) .build() ); }
رفتار اعلان برنامه ویدیویی
برنامههای ویدیویی یا برنامههای صوتی که از پخش محلی در پسزمینه پشتیبانی نمیکنند، باید رفتار خاصی برای اعلانهای رسانه داشته باشند تا در شرایطی که پخش پشتیبانی نمیشود، مشکلی در ارسال دستورات رسانهای ایجاد نشود:
- هنگام پخش رسانه به صورت محلی، اعلان رسانه را ارسال کنید و برنامه در پیش زمینه است.
- پخش محلی را متوقف کنید و وقتی برنامه در پسزمینه است، اعلان را رد کنید.
- وقتی برنامه به پیشزمینه برمیگردد، پخش محلی باید از سر گرفته شود و اعلان دوباره ارسال شود.
گزینه Output Switcher را در AndroidManifest.xml فعال کنید
برای فعال کردن Output Switcher، MediaTransferReceiver
باید به AndroidManifest.xml
برنامه اضافه شود. اگر اینطور نباشد، این ویژگی فعال نخواهد شد و پرچم ویژگی از راه دور به محلی نیز نامعتبر خواهد بود.
<application>
...
<receiver
android:name="androidx.mediarouter.media.MediaTransferReceiver"
android:exported="true">
</receiver>
...
</application>
MediaTransferReceiver
یک گیرنده پخش است که انتقال رسانه را بین دستگاه های دارای رابط کاربری سیستم امکان پذیر می کند. برای اطلاعات بیشتر به مرجع MediaTransferReceiver مراجعه کنید.
محلی به راه دور
هنگامی که کاربر پخش را از محلی به راه دور تغییر می دهد، Cast SDK به طور خودکار جلسه Cast را شروع می کند. با این حال، برنامهها باید جابجایی از محلی به راه دور را انجام دهند، برای مثال پخش محلی را متوقف کنند و رسانه را در دستگاه Cast بارگیری کنند. برنامهها باید با استفاده از تماسهای onSessionStarted()
و onSessionEnded()
به Cast SessionManagerListener
گوش دهند و هنگام دریافت تماسهای Cast SessionManager
این عمل را انجام دهند. برنامهها باید اطمینان حاصل کنند که وقتی کادر گفتگوی «تغییرگر خروجی» باز میشود و برنامه در پیشزمینه نیست، این تماسها همچنان زنده هستند.
SessionManagerListener را برای پخش پسزمینه بهروزرسانی کنید
وقتی برنامه در پیشزمینه است، تجربه Cast قدیمی از حالت محلی به راه دور پشتیبانی میکند. زمانی که کاربران روی نماد Cast در برنامه کلیک میکنند و دستگاهی را برای پخش جریانی رسانه انتخاب میکنند، یک تجربه Cast معمولی شروع میشود. در این مورد، برنامه باید در SessionManagerListener
، در onCreate()
یا onStart()
ثبت نام کند و شنونده را در onStop()
یا onDestroy()
فعالیت برنامه لغو ثبت کند.
با تجربه جدید ارسال محتوا با استفاده از Output Switcher، برنامهها میتوانند زمانی که در پسزمینه هستند شروع به ارسال محتوا کنند. این به ویژه برای برنامه های صوتی که هنگام پخش در پس زمینه اعلان ارسال می کنند مفید است. برنامه ها می توانند شنوندگان SessionManager
را در onCreate()
سرویس ثبت کنند و در onDestroy()
سرویس لغو ثبت کنند. وقتی برنامه در پسزمینه است، برنامهها همیشه باید تماسهای محلی به راه دور (مانند onSessionStarted
) را دریافت کنند.
اگر برنامه از MediaBrowserService
استفاده می کند، توصیه می شود SessionManagerListener
در آنجا ثبت کنید.
class MyService : Service() { private var castContext: CastContext? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) } protected fun onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) } } }
public class MyService extends Service { private CastContext castContext; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); } @Override protected void onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); } } }
با این بهروزرسانی، زمانی که برنامه در پسزمینه است و برای جابهجایی از دستگاههای بلوتوث به دستگاههای Cast، نیازی به کار اضافی نیست، «لکهبهراهدور» همانند ارسال محتوا معمولی عمل میکند.
از راه دور به محلی
سوئیچر خروجی توانایی انتقال از پخش از راه دور به بلندگوی تلفن یا دستگاه بلوتوث محلی را فراهم می کند. این را می توان با تنظیم پرچم setRemoteToLocalEnabled
روی true
در CastOptions
فعال کرد.
برای مواردی که دستگاه فرستنده فعلی به یک جلسه موجود با چندین فرستنده ملحق می شود و برنامه باید بررسی کند که آیا رسانه فعلی مجاز به انتقال محلی است یا خیر، برنامه ها باید از پاسخ به تماس onTransferred
SessionTransferCallback
برای بررسی SessionState
استفاده کنند.
پرچم setRemoteToLocalEnabled را تنظیم کنید
CastOptions.Builder
یک setRemoteToLocalEnabled
برای نشان دادن یا پنهان کردن بلندگوی تلفن و دستگاههای بلوتوث محلی به عنوان اهداف انتقال به اهداف در گفتگوی Output Switcher در زمانی که یک جلسه Cast فعال وجود دارد، ارائه میکند.
class CastOptionsProvider : OptionsProvider { fun getCastOptions(context: Context?): CastOptions { ... return Builder() ... .setRemoteToLocalEnabled(true) .build() } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { ... return new CastOptions.Builder() ... .setRemoteToLocalEnabled(true) .build() } }
پخش محلی را ادامه دهید
برنامههایی که از راه دور به محلی پشتیبانی میکنند باید SessionTransferCallback
را ثبت کنند تا هنگام وقوع رویداد مطلع شوند تا بتوانند بررسی کنند که آیا رسانه باید مجاز به انتقال و ادامه پخش به صورت محلی باشد.
CastContext#addSessionTransferCallback(SessionTransferCallback)
به برنامه اجازه می دهد تا SessionTransferCallback
خود را ثبت کند و هنگامی که فرستنده به پخش محلی منتقل می شود، به تماس های onTransferred
و onTransferFailed
گوش دهد.
پس از اینکه برنامه SessionTransferCallback
خود را لغو ثبت کرد، برنامه دیگر SessionTransferCallback
s را دریافت نخواهد کرد.
SessionTransferCallback
یک فرمت از تماس های SessionManagerListener
موجود است و پس از راه اندازی onSessionEnded
فعال می شود. ترتیب تماس های تماس از راه دور به محلی به شرح زیر است:
-
onTransferring
-
onSessionEnding
-
onSessionEnded
-
onTransferred
از آنجایی که وقتی برنامه در پسزمینه است و در حال ارسال است، میتوان Output Switcher را توسط تراشه اعلان رسانه باز کرد، برنامهها بسته به اینکه از پخش پسزمینه پشتیبانی میکنند یا نه، باید انتقال به محلی را متفاوت انجام دهند. در مورد انتقال ناموفق، onTransferFailed
در هر زمانی که خطا رخ دهد فعال می شود.
برنامه هایی که از پخش پس زمینه پشتیبانی می کنند
برای برنامههایی که از پخش در پسزمینه پشتیبانی میکنند (معمولاً برنامههای صوتی)، توصیه میشود از یک Service
(به عنوان مثال MediaBrowserService
) استفاده کنید. سرویسها باید به تماسهای onTransferred
گوش دهند و پخش را به صورت محلی از سر بگیرند، هم زمانی که برنامه در پیشزمینه یا پسزمینه است.
class MyService : Service() { private var castContext: CastContext? = null private var sessionTransferCallback: SessionTransferCallback? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) sessionTransferCallback = MySessionTransferCallback() castContext.addSessionTransferCallback(sessionTransferCallback) } protected fun onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback) } } } class MySessionTransferCallback : SessionTransferCallback() { fun onTransferring(@SessionTransferCallback.TransferType transferType: Int) { // Perform necessary steps prior to onTransferred } fun onTransferred(@SessionTransferCallback.TransferType transferType: Int, sessionState: SessionState?) { if (transferType == SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } fun onTransferFailed(@SessionTransferCallback.TransferType transferType: Int, @SessionTransferCallback.TransferFailedReason transferFailedReason: Int) { // Handle transfer failure. } } }
public class MyService extends Service { private CastContext castContext; private SessionTransferCallback sessionTransferCallback; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); sessionTransferCallback = new MySessionTransferCallback(); castContext.addSessionTransferCallback(sessionTransferCallback); } @Override protected void onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback); } } } public static class MySessionTransferCallback extends SessionTransferCallback { public MySessionTransferCallback() {} @Override public void onTransferring(@SessionTransferCallback.TransferType int transferType) { // Perform necessary steps prior to onTransferred } @Override public void onTransferred(@SessionTransferCallback.TransferType int transferType, SessionState sessionState) { if (transferType==SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } @Override public void onTransferFailed(@SessionTransferCallback.TransferType int transferType, @SessionTransferCallback.TransferFailedReason int transferFailedReason) { // Handle transfer failure. } } }
برنامه هایی که از پخش پس زمینه پشتیبانی نمی کنند
برای برنامههایی که از پخش پسزمینه (معمولاً برنامههای ویدیویی) پشتیبانی نمیکنند، توصیه میشود به تماسهای onTransferred
گوش دهید و اگر برنامه در پیشزمینه است، پخش را به صورت محلی از سر بگیرید.
اگر برنامه در پسزمینه باشد، باید پخش را متوقف کند و اطلاعات لازم را از SessionState
(به عنوان مثال، ابرداده رسانه و موقعیت پخش) ذخیره کند. هنگامی که برنامه از پس زمینه پیش زمینه می شود، پخش محلی باید با اطلاعات ذخیره شده ادامه یابد.
class MyActivity : AppCompatActivity() { private var castContext: CastContext? = null private var sessionTransferCallback: SessionTransferCallback? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) sessionTransferCallback = MySessionTransferCallback() castContext.addSessionTransferCallback(sessionTransferCallback) } protected fun onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback) } } } class MySessionTransferCallback : SessionTransferCallback() { fun onTransferring(@SessionTransferCallback.TransferType transferType: Int) { // Perform necessary steps prior to onTransferred } fun onTransferred(@SessionTransferCallback.TransferType transferType: Int, sessionState: SessionState?) { if (transferType == SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } fun onTransferFailed(@SessionTransferCallback.TransferType transferType: Int, @SessionTransferCallback.TransferFailedReason transferFailedReason: Int) { // Handle transfer failure. } } }
public class MyActivity extends AppCompatActivity { private CastContext castContext; private SessionTransferCallback sessionTransferCallback; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); sessionTransferCallback = new MySessionTransferCallback(); castContext.addSessionTransferCallback(sessionTransferCallback); } @Override protected void onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback); } } } public static class MySessionTransferCallback extends SessionTransferCallback { public MySessionTransferCallback() {} @Override public void onTransferring(@SessionTransferCallback.TransferType int transferType) { // Perform necessary steps prior to onTransferred } @Override public void onTransferred(@SessionTransferCallback.TransferType int transferType, SessionState sessionState) { if (transferType==SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } @Override public void onTransferFailed(@SessionTransferCallback.TransferType int transferType, @SessionTransferCallback.TransferFailedReason int transferFailedReason) { // Handle transfer failure. } } }
از راه دور به ریموت
Output Switcher از قابلیت گسترش به چند دستگاه بلندگوی دارای Cast برای برنامه های صوتی با استفاده از Stream Expansion پشتیبانی می کند.
برنامههای صوتی برنامههایی هستند که از Google Cast for Audio در تنظیمات برنامه گیرنده در کنسول برنامهنویس Google Cast SDK پشتیبانی میکنند.
گسترش جریان با بلندگو
برنامههای صوتی که از «Switcher خروجی» استفاده میکنند، میتوانند صدا را به چندین دستگاه بلندگوی دارای Cast در طول جلسه Cast با استفاده از «گسترش جریان» گسترش دهند.
این ویژگی توسط پلتفرم Cast پشتیبانی میشود و اگر برنامه از رابط کاربری پیشفرض استفاده میکند، نیازی به تغییر بیشتری ندارد. اگر از یک رابط کاربری سفارشی استفاده میشود، برنامه باید رابط کاربری را بهروزرسانی کند تا نشان دهد که برنامه در حال ارسال به یک گروه است.
برای دریافت نام گروه گسترشیافته جدید در طول گسترش جریان، یک Cast.Listener
با استفاده از CastSession#addCastListener
ثبت کنید. سپس در حین پاسخ به تماس onDeviceNameChanged
CastSession#getCastDevice()
را فراخوانی کنید.
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 val mCastListener = CastListener() private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> { override fun onSessionStarting(session: CastSession?) {} override fun onSessionStarted(session: CastSession?, sessionId: String) { addCastListener(session) } override fun onSessionStartFailed(session: CastSession?, error: Int) {} override fun onSessionSuspended(session: CastSession?, reason Int) { removeCastListener() } override fun onSessionResuming(session: CastSession?, sessionId: String) {} override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) { addCastListener(session) } override fun onSessionResumeFailed(session: CastSession?, error: Int) {} override fun onSessionEnding(session: CastSession?) {} override fun onSessionEnded(session: CastSession?, error: Int) { removeCastListener() } } private inner class CastListener : Cast.Listener() { override fun onDeviceNameChanged() { mCastSession?.let { val castDevice = it.castDevice val deviceName = castDevice.friendlyName // Update UIs with the new cast device name. } } } private fun addCastListener(castSession: CastSession) { mCastSession = castSession mCastSession?.addCastListener(mCastListener) } private fun removeCastListener() { mCastSession?.removeCastListener(mCastListener) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mCastContext = CastContext.getSharedInstance(this) mSessionManager = mCastContext.sessionManager mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } 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 Cast.Listener mCastListener = new CastListener(); private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> { @Override public void onSessionStarting(CastSession session) {} @Override public void onSessionStarted(CastSession session, String sessionId) { addCastListener(session); } @Override public void onSessionStartFailed(CastSession session, int error) {} @Override public void onSessionSuspended(CastSession session, int reason) { removeCastListener(); } @Override public void onSessionResuming(CastSession session, String sessionId) {} @Override public void onSessionResumed(CastSession session, boolean wasSuspended) { addCastListener(session); } @Override public void onSessionResumeFailed(CastSession session, int error) {} @Override public void onSessionEnding(CastSession session) {} @Override public void onSessionEnded(CastSession session, int error) { removeCastListener(); } } private class CastListener extends Cast.Listener { @Override public void onDeviceNameChanged() { if (mCastSession == null) { return; } CastDevice castDevice = mCastSession.getCastDevice(); String deviceName = castDevice.getFriendlyName(); // Update UIs with the new cast device name. } } private void addCastListener(CastSession castSession) { mCastSession = castSession; mCastSession.addCastListener(mCastListener); } private void removeCastListener() { if (mCastSession != null) { mCastSession.removeCastListener(mCastListener); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCastContext = CastContext.getSharedInstance(this); mSessionManager = mCastContext.getSessionManager(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onDestroy() { super.onDestroy(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); } }
تست ریموت به ریموت
برای تست ویژگی:
- محتوای خود را با استفاده از ارسال محتوا یا از راه دور محلی به یک دستگاه دارای قابلیت Cast ارسال کنید.
- کلید خروجی را با استفاده از یکی از نقاط ورودی باز کنید.
- روی دستگاه دیگری با قابلیت Cast ضربه بزنید، برنامههای صوتی محتوا را به دستگاه اضافی گسترش میدهند و یک گروه پویا ایجاد میکنند.
- دوباره روی دستگاه دارای Cast-enabled ضربه بزنید، از گروه پویا حذف خواهد شد.