Çıkış Değiştirici

Çıkış Değiştirici, Android 13'ten itibaren içeriğin yerel ve uzak oynatımı arasında sorunsuz geçiş yapmanızı sağlayan Cast SDK'sının bir özelliğidir. Amaç, gönderen uygulamaların içeriğin nerede oynatıldığını kolay ve hızlı bir şekilde kontrol etmesine yardımcı olmaktır. Çıkış değiştirici, içerik oynatmayı telefon hoparlörü, eşlenen Bluetooth cihazlar ve uzak Cast uyumlu cihazlar arasında geçiş yapmak için MediaRouter kitaplığını kullanır. Kullanım alanları aşağıdaki senaryolara ayrılabilir:

Çıkış Değiştirici'yi uygulamanıza nasıl uygulayacağınızla ilgili referans için CastVideos-android örnek uygulamasını indirip kullanın.

Bu kılavuzda açıklanan adımları uygulayarak çıkış değiştirici, yerelden uzaktan, uzaktan yerele ve uzaktan uzaktan bağlantıları desteklemek için etkinleştirilmelidir. Yerel cihaz hoparlörleri ile eşlenen Bluetooth cihazlar arasında aktarımı desteklemek için ek adımlar gerekmez.

Çıkış Değiştirici kullanıcı arayüzü

Çıkış Değiştirici, kullanılabilir yerel ve uzak cihazların yanı sıra cihazın seçili olup olmadığı, bağlanıp bağlanmadığı ve mevcut ses seviyesi gibi mevcut cihaz durumlarını gösterir. Mevcut cihaza ek olarak başka cihazlar varsa diğer cihazı tıklayarak medya oynatmayı seçili cihaza aktarabilirsiniz.

Bilinen sorunlar

  • Yerel oynatma için oluşturulan medya oturumları, Cast SDK bildirimine geçiş yapıldığında kapatılır ve yeniden oluşturulur.

Giriş noktaları

Medya bildirimi

Bir uygulama, yerel oynatma (yerel olarak oynatma) için MediaSession içeren bir medya bildirimi yayınlarsa medya bildiriminin sağ üst köşesinde, içeriğin şu anda oynatıldığı cihazın adını (ör. telefon hoparlörü) içeren bir bildirim çipi gösterilir. Bildirim çipine dokunduğunuzda Çıkış Değiştirici iletişim kutusu sistem kullanıcı arayüzü açılır.

Ses düzeyi ayarları

Çıkış Değiştirici iletişim kutusu sistem kullanıcı arayüzü, cihazdaki fiziksel ses düğmelerini tıklayarak, alt kısımdaki ayarlar simgesine ve "<Uygulama Adı>yı <Yayınlama Cihazı>nda oynat" metnine dokunarak da tetiklenebilir.

Adımların özeti

Ön koşullar

  1. Mevcut Android uygulamanızı AndroidX'e taşıyın.
  2. Çıkış Değiştirici için Android Gönderen SDK'sının minimum gerekli sürümünü kullanacak şekilde uygulamanızın build.gradle dosyasını güncelleyin:
    dependencies {
      ...
      implementation 'com.google.android.gms:play-services-cast-framework:21.2.0'
      ...
    }
  3. Uygulama, medya bildirimlerini desteklemelidir.
  4. Android 13 yüklü cihaz.

Medya Bildirimleri'ni ayarlama

Çıkış Değiştirici'yi kullanmak için ses ve video uygulamalarının, yerel oynatma için medyalarının oynatma durumunu ve kontrollerini gösteren bir medya bildirimi oluşturması gerekir. Bunun için bir MediaSession oluşturmanız, MediaSession jetonuyla MediaStyle ayarlarını yapmanız ve bildirimdeki medya denetimlerini ayarlamanız gerekir.

Şu anda MediaStyle ve MediaSession kullanmıyorsanız bunların nasıl ayarlanacağını aşağıdaki snippet'te görebilirsiniz. Ses ve video uygulamaları için medya oturumu geri çağırma işlevlerini ayarlamayla ilgili kılavuzlar da mevcuttur:

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

Ayrıca, bildirimi medyanızla ilgili bilgilerle doldurmak için MediaSession alanına medyanızın meta verilerini ve oynatma durumunu eklemeniz gerekir.

MediaSession öğesine meta veri eklemek için setMetaData() kullanın ve medyanızla ilgili tüm ilgili MediaMetadata sabitlerini MediaMetadataCompat.Builder() içinde sağlayın.

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

Oynatma durumunu MediaSession öğesine eklemek için setPlaybackState() öğesini kullanın ve medyanızla ilgili tüm ilgili PlaybackStateCompat sabitlerini PlaybackStateCompat.Builder() içinde sağlayın.

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

Video uygulaması bildirim davranışı

Arka planda yerel oynatmayı desteklemeyen video veya ses uygulamaları, oynatmanın desteklenmediği durumlarda medya komutları göndermeyle ilgili sorunları önlemek için medya bildirimleri için belirli bir davranışa sahip olmalıdır:

  • Medya yerel olarak oynatılırken ve uygulama ön plandayken medya bildirimini gönderin.
  • Uygulama arka plandayken yerel oynatmayı duraklatın ve bildirimi kapatın.
  • Uygulama ön plana geri döndüğünde yerel oynatma devam eder ve bildirim yeniden yayınlanır.

AndroidManifest.xml dosyasında Çıkış Değiştirici'yi etkinleştirme

Çıkış değiştiriciyi etkinleştirmek için MediaTransferReceiver, uygulamanın AndroidManifest.xml dosyasına eklenmelidir. Aksi takdirde özellik etkinleştirilmez ve uzaktan yerele özellik işareti de geçersiz olur.

<application>
    ...
    <receiver
         android:name="androidx.mediarouter.media.MediaTransferReceiver"
         android:exported="true">
    </receiver>
    ...
</application>

MediaTransferReceiver, sistem kullanıcı arayüzü olan cihazlar arasında medya aktarımını sağlayan bir yayın alıcısıdır. Daha fazla bilgi için MediaTransferReceiver referansını inceleyin.

Yerelden uzaktan

Kullanıcı oynatmayı yerelden uzaktan oynatmaya geçirdiğinde Cast SDK'sı Cast oturumunu otomatik olarak başlatır. Ancak uygulamaların yerelden uzaktan yayına geçişi yönetmesi gerekir. Örneğin, yerel oynatmayı durdurup medyayı Cast cihazına yüklemelidir. Uygulamalar, onSessionStarted() ve onSessionEnded() geri çağırma işlevlerini kullanarak Cast SessionManagerListener'i dinlemeli ve Cast SessionManager geri çağırma işlevlerini aldığında işlemi gerçekleştirmelidir. Uygulamalar, Çıkış Değiştirici iletişim kutusu açıldığında ve uygulama ön planda olmadığında bu geri çağırmaların etkin kalmasını sağlamalıdır.

Arka planda yayınlama için SessionManagerListener'ı güncelleme

Eski Cast deneyimi, uygulama ön plandayken yerelden uzaktan yayını zaten destekliyor. Tipik bir Cast deneyimi, kullanıcılar uygulamadaki Cast simgesini tıklayıp medya aktarmak için bir cihaz seçtiğinde başlar. Bu durumda, uygulamanın onCreate() veya onStart() bölümünde SessionManagerListener'e kaydolması ve uygulama etkinliğinin onStop() veya onDestroy() bölümünde dinleyicinin kaydını iptal etmesi gerekir.

Çıkış değiştiriciyi kullanarak yayınlama özelliğinin yeni deneyimiyle uygulamalar arka plandayken yayınlamaya başlayabilir. Bu özellik, özellikle arka planda oynatıldığında bildirim yayınlayan ses uygulamaları için kullanışlıdır. Uygulamalar, SessionManager dinleyicilerini hizmetin onCreate() bölümünde kaydedebilir ve hizmetin onDestroy() bölümünden kaydını iptal edebilir. Uygulamalar, arka plandayken yerelden uzaktan geri çağırma çağrılarını (ör. onSessionStarted) her zaman almalıdır.

Uygulama MediaBrowserService kullanıyorsa SessionManagerListener'i oraya kaydetmeniz önerilir.

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

Bu güncellemeyle birlikte, uygulama arka plandayken yerelden uzak cihaza aktarma işlemi geleneksel yayınlama işlemiyle aynı şekilde çalışır ve Bluetooth cihazlardan Cast cihazlara geçiş için ek işlem gerekmez.

Uzaktan yerele

Çıkış değiştirici, uzaktan oynatmayı telefon hoparlörüne veya yerel Bluetooth cihazına aktarma olanağı sunar. Bu özellik, CastOptions üzerinde setRemoteToLocalEnabled işaretini true olarak ayarlayarak etkinleştirilebilir.

Mevcut gönderen cihazın birden fazla gönderenin bulunduğu mevcut bir oturuma katılması ve uygulamanın mevcut medyanın yerel olarak aktarılmasına izin verilip verilmediğini kontrol etmesi gereken durumlarda, uygulamalar SessionState değerini kontrol etmek için SessionTransferCallback onTransferred geri çağırma işlevini kullanmalıdır.

setRemoteToLocalEnabled işaretini ayarlama

CastOptions.Builder, etkin bir Yayınlama oturumu olduğunda Çıkış Değiştirici iletişim kutusunda telefon hoparlörünü ve yerel Bluetooth cihazlarını aktarma hedefleri olarak göstermek veya gizlemek için bir setRemoteToLocalEnabled sağlar.

Kotlin
class CastOptionsProvider : OptionsProvider {
    fun getCastOptions(context: Context?): CastOptions {
        ...
        return Builder()
            ...
            .setRemoteToLocalEnabled(true)
            .build()
    }
}
Java
public class CastOptionsProvider implements OptionsProvider {
    @Override
    public CastOptions getCastOptions(Context context) {
        ...
        return new CastOptions.Builder()
            ...
            .setRemoteToLocalEnabled(true)
            .build()
  }
}

Yerel olarak oynatmaya devam etme

Uzaktan yerele aktarımı destekleyen uygulamalar, medya aktarımına izin verilip verilmeyeceğini ve oynatmaya yerel olarak devam edilip edilemeyeceğini kontrol edebilmek için etkinlik gerçekleştiğinde bildirim almak üzere SessionTransferCallback öğesini kaydetmelidir.

CastContext#addSessionTransferCallback(SessionTransferCallback), bir gönderen yerel oynatmaya aktarıldığında uygulamanın SessionTransferCallback kaydetmesine ve onTransferred ile onTransferFailed geri çağırma çağrılarını dinlemesine olanak tanır.

Uygulama, SessionTransferCallback kimliğinin kaydını iptal ettikten sonra artık SessionTransferCallback almaz.

SessionTransferCallback, mevcut SessionManagerListener geri çağırmalarının bir uzantısıdır ve onSessionEnded tetiklendikten sonra tetiklenir. Uzaktan yerele geri aramaların sırası:

  1. onTransferring
  2. onSessionEnding
  3. onSessionEnded
  4. onTransferred

Çıkış Değiştirici, uygulama arka plandayken ve yayın yaparken medya bildirim çipi tarafından açılabildiğinden, uygulamaların yerele aktarma işlemini arka planda oynatmayı destekleyip desteklemediklerine göre farklı şekilde ele alması gerekir. Aktarım başarısız olursa hata oluştuğunda onTransferFailed tetiklenir.

Arka planda oynatmayı destekleyen uygulamalar

Arka planda oynatmayı destekleyen uygulamalar (genellikle ses uygulamaları) için Service (ör. MediaBrowserService) kullanılması önerilir. Hizmetler, onTransferred geri çağırma işlevini dinlemeli ve oynatmayı hem uygulama ön plandayken hem de arka plandayken yerel olarak devam ettirmelidir.

Kotlin
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.
        }
    }
}
Java
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.
        }
    }
}

Arka planda oynatmayı desteklemeyen uygulamalar

Arka planda oynatmayı desteklemeyen uygulamalarda (genellikle video uygulamaları) onTransferred geri çağırma işlevini dinlemeniz ve uygulama ön plandaysa oynatmayı yerel olarak devam ettirmeniz önerilir.

Uygulama arka plandaysa oynatmayı duraklatmalı ve SessionState'dan gerekli bilgileri (ör. medya meta verileri ve oynatma konumu) kaydetmelidir. Uygulama arka plandan ön plana getirildiğinde yerel oynatma, depolanan bilgilerle devam eder.

Kotlin
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.
        }
    }
}
Java
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.
    }
  }
}

Uzaktan-uzaktan

Çıkış değiştirici, Akış Genişlemesi'ni kullanarak ses uygulamaları için birden fazla Cast özellikli hoparlör cihazına genişletmeyi destekler.

Ses uygulamaları, Google Cast SDK Geliştirici Konsolu'ndaki Alıcı Uygulaması ayarlarında Ses için Google Cast'i destekleyen uygulamalardır.

Hoparlörlerle akış genişletme

Çıkış Değiştirici'yi kullanan ses uygulamaları, Akış Genişlemesi'ni kullanarak Cast oturumu sırasında sesi birden fazla Cast özellikli hoparlör cihazına genişletebilir.

Bu özellik Cast platformu tarafından desteklenir ve uygulama varsayılan kullanıcı arayüzünü kullanıyorsa başka bir değişiklik gerekmez. Özel bir kullanıcı arayüzü kullanılıyorsa uygulama, kullanıcı arayüzünü bir gruba yayın yaptığını yansıtacak şekilde güncellemelidir.

Yayın genişletmesi sırasında yeni genişletilmiş grup adını almak için CastSession#addCastListener simgesini kullanarak bir Cast.Listener kaydedin. Ardından, onDeviceNameChanged geri arama sırasında CastSession#getCastDevice() numaralı telefonu arayın.

Kotlin
class MyActivity : Activity() {
    private var mCastSession: CastSession? = null
    private lateinit var mCastContext: CastContext
    private lateinit var mSessionManager: SessionManager
    private val mSessionManagerListener: SessionManagerListener<CastSession> =
        SessionManagerListenerImpl()
    private 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)
    }
}
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);
    }
}

Uzaktan-uzaktan test etme

Özelliği test etmek için:

  1. İçeriğinizi geleneksel yayınlama veya yerelden uzak cihaza yayınlama özelliğini kullanarak Cast uyumlu bir cihaza yayınlayın.
  2. Giriş noktalarından birini kullanarak Çıkış Değiştirici'yi açın.
  3. Başka bir Cast uyumlu cihaza dokunduğunuzda ses uygulamaları içeriği ek cihaza genişleterek dinamik bir grup oluşturur.
  4. Cast uyumlu cihaza tekrar dokunun. Cihaz, dinamik gruptan kaldırılır.