Sélecteur de sortie

Le sélecteur de sortie est une fonctionnalité du SDK Cast qui permet de transférer facilement 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:

Le sélecteur de sortie doit être activé pour prendre en charge les connexions locales/distantes, distantes/locales 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 l'audio en local (lecture locale) dans l'angle supérieur droit de la notification affiche un chip de notification indiquant le nom de l'appareil (par exemple, le haut-parleur du téléphone) le contenu est en cours de lecture. 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 en appuyant sur "Mets <App Name> sur l'<appareil Cast>" du texte.

Résumé des étapes

Prérequis

  1. Migrez votre application Android existante vers AndroidX.
  2. 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'
      ...
    }
  3. L'appli est compatible avec les notifications multimédias.
  4. 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:

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

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 informations des constantes MediaMetadata pour vos contenus multimédias MediaMetadataCompat.Builder().

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

Pour ajouter l'état de lecture à MediaSession, utilisez setPlaybackState() et fournissez toutes les informations PlaybackStateCompat constantes pour vos contenus multimédias PlaybackStateCompat.Builder().

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

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 republiée.

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. Consultez le MediaTransferReceiver référence pour en savoir plus.

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 inscrivez-vous au SessionManagerListener, dans onCreate() ou onStart() puis annulez l'enregistrement de l'écouteur 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 s'enregistrer la SessionManager les écouteurs dans le onCreate() du service et se désinscrire 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, nous vous recommandons d'enregistrer SessionManagerListener ici.

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

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 permettant d'afficher ou de masquer le haut-parleur du téléphone et les appareils Bluetooth locaux pour le transfert vers cibles dans la boîte de dialogue du sélecteur de sortie lorsqu'une session Cast est active.

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()
  }
}

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 est 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 des rappels distants au local est la suivante:

  1. onTransferring
  2. onSessionEnding
  3. onSessionEnded
  4. 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.

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

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 exécutée en arrière-plan, elle doit mettre la lecture en pause et stocker le contenu les informations nécessaires auprès 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.

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

À 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 compatibles avec Google Cast pour l'audio dans l'application du récepteur. dans la section "Développeur du SDK Google Cast" Console

Diffusion étendue avec les enceintes

Les applications audio qui utilisent le sélecteur de sortie peuvent étendre l'audio sur plusieurs enceintes compatibles Cast lors d'une session Cast à l'aide du flux. Expansion.

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'interface utilisateur pour indiquer que l'application 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 Ensuite, appelez CastSession#getCastDevice() lors du rappel onDeviceNameChanged.

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

Tester la connexion à distance

Pour tester la fonctionnalité:

  1. Castez vos contenus sur un appareil compatible Cast en utilisant les fonctionnalités de diffusion conventionnelles ou avec local-to-remote
  2. Ouvrez le sélecteur de sortie à l'aide de l'un des points d'entrée.
  3. Appuyez sur un autre appareil compatible Cast pour afficher le contenu un appareil supplémentaire, créant ainsi un groupe dynamique.
  4. Appuyez de nouveau sur l'appareil compatible Cast. Il est alors supprimé de l'environnement dynamique. groupe.