Le sélecteur de sortie est une fonctionnalité du SDK Cast qui facilite le transfert
entre la lecture locale et à distance du contenu à partir d'Android 13. L’objectif
permet aux applications émettrices de contrôler facilement et rapidement la lecture du contenu.
Le sélecteur de sortie utilise
bibliothèque MediaRouter
pour
activer ou désactiver la lecture du contenu sur le haut-parleur du téléphone, sur les appareils Bluetooth associés
et les appareils compatibles Cast distants. Les cas d'utilisation peuvent être répartis comme suit :
scénarios:
Téléchargez et utilisez l'application exemple CastVideos-pour 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 le passage du local au local à distance, et inversement et de la télécommande à la télécommande en suivant les étapes décrites dans ce guide. Il n'y a aucun étapes supplémentaires nécessaires pour permettre le transfert entre l'appareil local haut-parleurs et appareils Bluetooth associés.
UI du sélecteur de sortie
Le sélecteur de sortie affiche les appareils locaux et distants disponibles. ainsi que l'état actuel de l'appareil, y compris si l'appareil est sélectionné, se connecte, le niveau de volume actuel. S'il existe d'autres appareils en plus vers l'appareil actuel, cliquez sur "Autre appareil" pour transférer le contenu multimédia lecture sur l'appareil sélectionné.
Problèmes connus
- Les sessions multimédias créées pour une lecture locale seront ignorées et recréées lorsque vous passez à 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, un chip de notification s'affiche en haut à droite de la notification multimédia avec le nom de l'appareil (comme le haut-parleur du téléphone) sur lequel le contenu est actuellement lu. Un appui sur le chip de notification s'ouvre
l'UI du système de la boîte de dialogue
"Output Switcher" (Sélecteur de sortie).
Paramètres de volume
L'interface utilisateur du système de sélection de sortie peut également être déclenchée en cliquant sur boutons de volume physiques sur l'appareil, en appuyant sur l'icône des paramètres en bas, et appuyez sur le bouton "Play <App Name> sur l'<appareil Cast>" texte.
Résumé des étapes
- Vérifier que les conditions préalables sont remplies
- Activer le sélecteur de sortie dans le fichier AndroidManifest.xml
- Mettre à jour SessionManagerListener pour la diffusion en arrière-plan
- Compatibilité avec Remote-to-Remote
- Définir l'indicateur setRemoteToLocalEnabled
- Poursuivre la lecture en local
Prérequis
- Migrez votre application Android existante vers AndroidX.
- Mettez à jour le
build.gradle
de votre application afin d'utiliser la version minimale requise de SDK Android Sender pour le sélecteur de sortie:dependencies { ... implementation 'com.google.android.gms:play-services-cast-framework:21.2.0' ... }
- L'appli est compatible avec les notifications multimédias.
- Appareil équipé d'Android 13.
Configurer les notifications multimédias
Pour utiliser le sélecteur de sortie,
audio et
applications vidéo
sont nécessaires pour créer une notification multimédia permettant d'afficher l'état de la lecture et
des commandes de lecture locale pour leurs contenus multimédias. Pour cela, vous devez créer
MediaSession
en paramétrant le
MediaStyle
avec le jeton de MediaSession
, et en configurant les commandes multimédias sur
.
Si vous n'utilisez pas MediaStyle
ni MediaSession
actuellement, l'extrait
ci-dessous montre comment les configurer. Des guides sont disponibles pour configurer le média
des rappels de session
audio et
vidéo
applications:
// 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 concernant votre contenu multimédia,
vous devez ajouter
les métadonnées et l'état de la lecture
à MediaSession
.
Pour ajouter des métadonnées à MediaSession
, utilisez setMetaData()
et fournissez toutes les constantes MediaMetadata
pertinentes pour vos contenus multimédias dans 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 à MediaSession
, utilisez setPlaybackState()
et fournissez toutes les constantes PlaybackStateCompat
pertinentes pour vos contenus multimédias dans 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 de l'application vidéo
Applications vidéo ou audio qui ne sont pas compatibles avec la lecture en arrière-plan en local doivent adopter un comportement spécifique pour les notifications multimédias afin d'éviter tout problème avec envoi de commandes multimédias lorsque la lecture n'est pas possible:
- Publier la notification multimédia lors de la lecture du contenu multimédia en local et que l'application est en cours d'exécution au premier plan.
- Mettez en pause la lecture locale et fermez la notification lorsque l'application est dans en arrière-plan.
- Lorsque l'application revient au premier plan, la lecture locale doit reprendre et la notification doit être publiée à nouveau.
Activer le sélecteur de sortie dans AndroidManifest.xml
Pour activer le sélecteur de sortie,
MediaTransferReceiver
doit être ajouté au AndroidManifest.xml
de l'application. Si ce n'est pas le cas, la fonctionnalité
ne sera pas activé et l'indicateur de fonctionnalité distant/local ne sera pas non plus valide.
<application>
...
<receiver
android:name="androidx.mediarouter.media.MediaTransferReceiver"
android:exported="true">
</receiver>
...
</application>
La
MediaTransferReceiver
est un broadcast receiver qui permet le transfert multimédia entre des appareils
UI. Pour en savoir plus, consultez la documentation de référence sur MediaTransferReceiver.
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 cette migration
"local" vers la version distante (par exemple, arrêter la lecture en local)
et chargez le contenu multimédia sur l'appareil Cast. Les applications doivent écouter Cast
SessionManagerListener
à l'aide du
onSessionStarted()
et
onSessionEnded()
et gérer l'action à la réception de l'objet Cast
SessionManager
. 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 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 stockage local/à distance lorsque l'application est
au premier plan. En général, l'expérience Cast commence lorsque l'utilisateur clique sur l'icône Cast.
dans l'application, puis sélectionnez un appareil sur lequel diffuser le contenu multimédia. Dans ce cas, l'application doit s'enregistrer auprès de SessionManagerListener
, dans onCreate()
ou onStart()
, et désenregistrer l'écouteur dans onStop()
ou onDestroy()
de l'activité de l'application.
Grâce à la nouvelle expérience de diffusion basée sur le sélecteur de sortie, les applications peuvent
si elles sont diffusées en arrière-plan. C'est particulièrement utile pour les fichiers audio
Applications qui publient des notifications lorsqu'elles sont lues en arrière-plan Les applications peuvent enregistrer les écouteurs SessionManager
dans le onCreate()
du service et se désenregistrer dans le onDestroy()
du service. Les applications doivent toujours recevoir les rappels locaux vers distants (tels que
en tant que onSessionStarted
)
lorsque l'application est exécutée en arrière-plan.
Si l'application utilise MediaBrowserService
, il est recommandé d'y enregistrer 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 mode local vers distant fonctionne de la même manière que la diffusion traditionnelle lorsque le est exécutée en arrière-plan. Aucun travail supplémentaire n'est requis pour passer de les appareils Bluetooth vers les appareils Cast ;
Du distant au local
Le sélecteur de sortie permet de passer de la lecture à distance
le haut-parleur du téléphone ou un appareil Bluetooth local. Vous pouvez activer cette fonctionnalité en paramétrant le
setRemoteToLocalEnabled
l'indicateur sur true
sur CastOptions
.
Dans les cas où l'appareil émetteur actuel rejoint une session existante avec
plusieurs expéditeurs et l'application doit vérifier si le contenu multimédia actuel est autorisé à
être transférées localement, les applications doivent utiliser le onTransferred
rappel de SessionTransferCallback
pour vérifier le SessionState
.
Définir l'indicateur setRemoteToLocalEnabled
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() } }
Continuer la lecture en local
Les applications qui prennent en charge le passage à distance à distance doivent enregistrer le SessionTransferCallback
pour recevoir une notification lorsque l'événement se produit et vérifier si les contenus multimédias doivent être
autorisé à transférer et poursuivre la lecture en local.
CastContext#addSessionTransferCallback(SessionTransferCallback)
permet à une application d'enregistrer ses SessionTransferCallback
et écouter les rappels onTransferred
et onTransferFailed
lorsqu'un expéditeur
transféré vers la lecture locale.
Une fois que l'application a annulé l'enregistrement de ses SessionTransferCallback
,
l'application ne recevra plus SessionTransferCallback
.
SessionTransferCallback
est une extension de la propriété SessionManagerListener
existante
et est déclenché après le déclenchement de onSessionEnded
. L'ordre des rappels à distance vers le local est le suivant :
onTransferring
onSessionEnding
onSessionEnded
onTransferred
Le sélecteur de sortie pouvant être ouvert par le chip de notification multimédia lorsque
est exécutée en arrière-plan et caste, les applications doivent gérer le transfert en local
selon qu'ils sont compatibles ou non avec la lecture en arrière-plan. Dans l'étui
d'un échec de transfert, onTransferFailed
se déclenche chaque fois que l'erreur se produit.
Applis compatibles avec la lecture en arrière-plan
Pour les applications qui prennent en charge la lecture en arrière-plan (généralement des applications audio), il est
il est recommandé d'utiliser un Service
(par exemple, MediaBrowserService
). Services
doit écouter onTransferred
et reprendre la lecture localement lorsque l'application est exécutée 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. } } }
Applis non compatibles avec la lecture en arrière-plan
Pour les applications qui ne prennent pas en charge la lecture en arrière-plan (généralement des applications vidéo), il est
recommandé d'écouter onTransferred
et reprendre la lecture localement si l'application est exécutée 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
avec l'arrière-plan au premier plan, la lecture locale doit se poursuivre
des 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. } } }
À distance
Le sélecteur de sortie permet d'étendre la sortie à plusieurs appareils compatibles Cast. enceintes pour les applications audio qui utilisent la fonctionnalité d'expansion du flux.
Les applications audio sont celles qui prennent en charge Google Cast pour l'audio dans les paramètres de l'application réceptrice dans la console développeur du SDK Google Cast.
Diffusion étendue avec les enceintes
Les applications audio qui utilisent le sélecteur de sortie peuvent diffuser l'audio sur plusieurs appareils de haut-parleurs compatibles avec Cast lors d'une session Cast à l'aide de l'extension de flux.
Cette fonctionnalité est compatible avec la plate-forme Cast et ne nécessite aucune autre action change si l'application utilise l'interface utilisateur par défaut. Si une UI personnalisée est utilisée, l'application doit mettre à jour l'UI pour indiquer qu'elle diffuse du contenu vers un groupe.
Pour obtenir le nouveau nom de groupe développé lors du développement du streaming, procédez comme suit :
enregistrer un
Cast.Listener
à l'aide du
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 un transfert à distance à distance
Pour tester la fonctionnalité :
- Castez vos contenus sur un appareil compatible Cast en utilisant les fonctionnalités de diffusion conventionnelles ou avec local-to-remote
- Ouvrez le sélecteur de sortie à l'aide de l'un des points d'entrée.
- Appuyez sur un autre appareil compatible Cast pour afficher le contenu un appareil supplémentaire, créant ainsi un groupe dynamique.
- Appuyez de nouveau sur l'appareil compatible Cast. Il est alors supprimé de l'environnement dynamique. groupe.