Le sélecteur de sortie est une fonctionnalité du SDK Cast qui permet de passer facilement de la lecture locale à la lecture à distance de contenus à partir d'Android 13. L'objectif est d'aider les applications émettrices à contrôler facilement et rapidement l'endroit où le contenu est lu.
Le sélecteur de sortie utilise la
MediaRouter bibliothèque pour
basculer la lecture de contenu entre le haut-parleur du téléphone, les appareils Bluetooth associés
et les appareils à distance compatibles Cast. Les cas d'utilisation peuvent être divisés en trois scénarios :
Téléchargez et utilisez l'exemple d'application CastVideos-android pour savoir comment implémenter le sélecteur de sortie dans votre application.
Le sélecteur de sortie doit être activé pour prendre en charge les scénarios local vers distant, distant vers local et distant vers distant en suivant les étapes décrites dans ce guide. Aucune étape supplémentaire n'est nécessaire pour prendre en charge le transfert entre les haut-parleurs de l'appareil local et les appareils Bluetooth associés.
Interface utilisateur du sélecteur de sortie
Le sélecteur de sortie affiche les appareils locaux et distants disponibles, ainsi que l'état actuel des appareils, y compris s'ils sont sélectionnés, en cours de connexion ou le niveau de volume actuel. Si d'autres appareils sont disponibles en plus de l'appareil actuel, vous pouvez cliquer sur un autre appareil pour transférer la lecture multimédia vers l'appareil sélectionné.

Problèmes connus
- Les sessions multimédias créées pour la lecture locale seront ignorées et recréées lors du passage à la notification du SDK Cast.
Points d'entrée
Notification multimédia
Si une application publie une notification multimédia avec
MediaSession pour
la lecture locale (lecture en local), le coin supérieur droit de la notification multimédia
affiche une puce de notification avec le nom de l'appareil (par exemple, le haut-parleur du téléphone) sur lequel
le contenu est actuellement lu. En appuyant sur la puce de notification, vous ouvrez l'interface utilisateur du système de la boîte de dialogue du sélecteur de sortie.

Paramètres de volume
L'interface utilisateur du système de la boîte de dialogue du sélecteur de sortie peut également être déclenchée en cliquant sur les boutons de volume physiques de l'appareil, en appuyant sur l'icône des paramètres en bas, puis sur le texte "Lire <Nom de l'application> sur <Appareil Cast>"

Résumé des étapes
- Vérifiez que les prérequis sont remplis.
- Activez le sélecteur de sortie dans AndroidManifest.xml.
- Mettez à jour SessionManagerListener pour la diffusion en arrière-plan.
- Ajoutez la prise en charge du scénario distant vers distant.
- Définissez l'indicateur setRemoteToLocalEnabled.
- Reprenez la lecture en local.
Prérequis
- Migrez votre application Android existante vers AndroidX.
- Mettez à jour le fichier
build.gradlede votre application pour utiliser la version minimale requise du SDK Android Sender pour le sélecteur de sortie :dependencies { ... implementation 'com.google.android.gms:play-services-cast-framework:21.2.0' ... }
- L'application est compatible avec les notifications multimédias.
- L'appareil exécute Android 13.
Configurer les notifications multimédias
Pour utiliser le sélecteur de sortie,
les applications audio et
vidéo
doivent créer une notification multimédia afin d'afficher l'état de lecture et les
commandes de leurs contenus multimédias pour la lecture locale. Pour cela, vous devez créer un
MediaSession, définir le
MediaStyle
avec le jeton du MediaSession's et définir les commandes multimédias dans la
notification.
Si vous n'utilisez pas actuellement de MediaStyle ni de MediaSession, l'extrait
ci-dessous montre comment les configurer. Des guides sont également disponibles pour configurer les rappels de session
multimédia pour les applications
audio et
vidéo
:
// 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(); }

De plus, pour renseigner la notification avec les informations de votre contenu multimédia,
vous devrez ajouter les métadonnées et l'état de lecture de votre contenu multimédia
au MediaSession.
Pour ajouter des métadonnées au MediaSession, utilisez
setMetaData()
et fournissez toutes les constantes
MediaMetadata pertinentes pour
votre contenu multimédia dans le
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() ); }

Pour ajouter l'état de lecture au MediaSession, utilisez
setPlaybackState()
et fournissez toutes les constantes
PlaybackStateCompat
pertinentes pour votre contenu multimédia dans le
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() ); }

Comportement des notifications des applications vidéo
Les applications vidéo ou audio qui ne sont pas compatibles avec la lecture locale en arrière-plan doivent avoir un comportement spécifique pour les notifications multimédias afin d'éviter les problèmes liés à l'envoi de commandes multimédias dans les situations où la lecture n'est pas prise en charge :
- Publiez la notification multimédia lorsque vous lisez du contenu multimédia en local et que l'application est au premier plan.
- Mettez en pause la lecture locale et fermez la notification lorsque l'application est en arrière-plan.
- Lorsque l'application revient au premier plan, la lecture locale doit reprendre et la notification doit être republiée.
Activer le sélecteur de sortie dans AndroidManifest.xml
Pour activer le sélecteur de sortie, le
MediaTransferReceiver
doit être ajouté au AndroidManifest.xml de l'application. Si ce n'est pas le cas, la fonctionnalité ne sera pas activée et l'indicateur de fonctionnalité distant vers local ne sera pas non plus valide.
<application>
...
<receiver
android:name="androidx.mediarouter.media.MediaTransferReceiver"
android:exported="true">
</receiver>
...
</application>
Le
MediaTransferReceiver
est un récepteur de diffusion qui permet le transfert de contenus multimédias entre des appareils avec une interface utilisateur système. Pour en savoir plus, consultez la documentation de référence sur MediaTransferReceiver
reference.
Local vers distant
Lorsque l'utilisateur passe de la lecture locale à la lecture à distance, le SDK Cast démarre automatiquement la session Cast. Toutefois, les applications doivent gérer le passage du local au distant, par exemple en arrêtant la lecture locale et en chargeant le contenu multimédia sur l'appareil Cast. Les applications doivent écouter le Cast
SessionManagerListener,
à l'aide des rappels
onSessionStarted()
et
onSessionEnded(), et gérer l'action lors de la réception des rappels
SessionManager
Cast. Les applications doivent s'assurer que ces rappels sont toujours actifs lorsque la boîte de dialogue du sélecteur de sortie est ouverte et que l'application n'est pas au premier plan.
Mettre à jour SessionManagerListener pour la diffusion en arrière-plan
L'ancienne expérience Cast est déjà compatible avec le scénario local vers distant lorsque l'application est au premier plan. Une expérience Cast typique commence lorsque les utilisateurs cliquent sur l'icône Cast dans l'application et choisissent un appareil pour diffuser du contenu multimédia. Dans ce cas, l'application doit s'
enregistrer auprès du
SessionManagerListener,
dans onCreate() ou
onStart()
et désenregistrer l'écouteur dans
onStop()
ou
onDestroy()
de l'activité de l'application.
Avec la nouvelle expérience de diffusion à l'aide du sélecteur de sortie, les applications peuvent commencer à diffuser lorsqu'elles sont en arrière-plan. Cela est particulièrement utile pour les applications audio qui publient des notifications lorsqu'elles sont lues en arrière-plan. Les applications peuvent enregistrer
les SessionManager
écouteurs dans le onCreate() du service et les désenregistrer dans le onDestroy()
du service. Les applications doivent toujours recevoir les rappels local vers distant (tels
que onSessionStarted)
lorsque l'application est en arrière-plan.
Si l'application utilise le
MediaBrowserService,
il est recommandé d'y enregistrer le 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); } } }
Avec cette mise à jour, le scénario local vers distant fonctionne de la même manière que la diffusion classique lorsque l'application est en arrière-plan, et aucun travail supplémentaire n'est requis pour passer des appareils Bluetooth aux appareils Cast.
Distant vers local
Le sélecteur de sortie permet de passer de la lecture à distance au haut-parleur du téléphone ou à un appareil Bluetooth local. Pour activer cette fonctionnalité, définissez l'
setRemoteToLocalEnabled
indicateur sur true dans le CastOptions.
Dans les cas où l'appareil émetteur actuel rejoint une session existante avec
plusieurs émetteurs et où l'application doit vérifier si le contenu multimédia actuel peut être transféré localement, les applications doivent utiliser le onTransferred
rappel du SessionTransferCallback
pour vérifier le SessionState.
Définir l'indicateur setRemoteToLocalEnabled
Le CastOptions.Builder
fournit un setRemoteToLocalEnabled pour afficher ou masquer le haut-parleur du téléphone et les appareils Bluetooth locaux en tant que cibles de transfert
dans la boîte de dialogue du sélecteur de sortie lorsqu'une session Cast est active.
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() } }
Reprendre la lecture en local
Les applications compatibles avec le scénario distant vers local doivent enregistrer le SessionTransferCallback
pour être averties lorsque l'événement se produit afin de pouvoir vérifier si le contenu multimédia doit être
autorisé à être transféré et à reprendre la lecture en local.
CastContext#addSessionTransferCallback(SessionTransferCallback)
permet à une application d'enregistrer son SessionTransferCallback
et d'écouter les rappels onTransferred et onTransferFailed lorsqu'un émetteur est
transféré vers la lecture locale.
Une fois que l'application a désenregistré son SessionTransferCallback,
elle ne recevra plus de SessionTransferCallback
s.
Le SessionTransferCallback
est une extension des rappels SessionManagerListener
existants et est déclenché après le déclenchement de onSessionEnded. L'ordre des rappels distant vers local est le suivant :
onTransferringonSessionEndingonSessionEndedonTransferred
Étant donné que le sélecteur de sortie peut être ouvert par la puce de notification multimédia lorsque l'application est en arrière-plan et en cours de diffusion, les applications doivent gérer le transfert vers le local différemment selon qu'elles sont compatibles ou non avec la lecture en arrière-plan. En cas
d'échec du transfert, onTransferFailed
se déclenchera à tout moment où l'erreur se produit.
Applications compatibles avec la lecture en arrière-plan
Pour les applications compatibles avec la lecture en arrière-plan (généralement les applications audio), il est
recommandé d'utiliser un Service (par exemple MediaBrowserService). Les services
doivent écouter le rappel onTransferred
et reprendre la lecture en local lorsque l'application est au premier plan ou
en arrière-plan.
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. } } }
Applications non compatibles avec la lecture en arrière-plan
Pour les applications non compatibles avec la lecture en arrière-plan (généralement les applications vidéo), il est
recommandé d'écouter le onTransferred
rappel et de reprendre la lecture en local si l'application est au premier plan.
Si l'application est en arrière-plan, elle doit mettre en pause la lecture et stocker les
informations nécessaires à partir de SessionState
(par exemple, les métadonnées multimédias et la position de lecture). Lorsque l'application est mise au premier plan à partir de l'arrière-plan, la lecture locale doit se poursuivre avec les informations stockées.
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. } } }
Distant vers distant
Le sélecteur de sortie permet de diffuser du contenu sur plusieurs appareils d'enceinte compatibles Cast pour les applications audio à l'aide de la diffusion étendue.
Les applications audio sont celles qui sont compatibles avec Google Cast pour l'audio dans les paramètres de l'application récepteur de la console développeur du SDK Google Cast.

Diffusion étendue avec des enceintes
Les applications audio qui utilisent le sélecteur de sortie peuvent étendre l'audio à plusieurs appareils d'enceinte compatibles Cast lors d'une session Cast à l'aide de la diffusion étendue.
Cette fonctionnalité est prise en charge par la plate-forme Cast et ne nécessite aucune autre modification si l'application utilise l'interface utilisateur par défaut. Si une interface utilisateur personnalisée est utilisée, l'application doit la mettre à jour pour indiquer qu'elle diffuse du contenu vers un groupe.

Pour obtenir le nouveau nom de groupe étendu lors d'une diffusion étendue,
enregistrez un
Cast.Listener
à l'aide de
CastSession#addCastListener.
Appelez ensuite
CastSession#getCastDevice()
lors du rappel onDeviceNameChanged.
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); } }
Tester le scénario distant vers distant
Pour tester la fonctionnalité :
- Diffusez votre contenu sur un appareil compatible Cast à l'aide de la diffusion classique ou avec le scénario local vers distant.
- Ouvrez le sélecteur de sortie à l'aide de l'un des points d'entrée.
- Appuyez sur un autre appareil compatible Cast. Les applications audio étendront le contenu à l'appareil supplémentaire, créant ainsi un groupe dynamique.
- Appuyez à nouveau sur l'appareil compatible Cast. Il sera supprimé du groupe dynamique.