出力切り替えは、Android 13 以降でコンテンツのローカル再生とリモート再生をシームレスに切り替えることができる Cast SDK の機能です。その目的は、送信側アプリがコンテンツの再生場所を簡単かつ迅速に制御できるようにすることです。出力切り替えは、MediaRouter ライブラリを使用して、スマートフォンのスピーカー、ペア設定された Bluetooth デバイス、リモートの Cast 対応デバイスの間でコンテンツの再生を切り替えます。ユースケースは、次のシナリオに分類できます。
CastVideos-android サンプルアプリをダウンロードして使用し、アプリに音声出力切り替えを実装する方法を確認します。
このガイドで説明する手順に沿って、出力切り替えを有効にして、ローカルからリモート、リモートからローカル、リモートからリモートへの切り替えをサポートする必要があります。ローカル デバイスのスピーカーとペア設定された Bluetooth デバイス間の転送をサポートするために、追加の手順は必要ありません。
出力スイッチャーの UI
出力スイッチャーには、利用可能なローカル デバイスとリモート デバイス、および現在のデバイスの状態(デバイスが選択されているかどうか、接続中かどうか、現在の音量レベルなど)が表示されます。現在のデバイス以外に他のデバイスがある場合、他のデバイスをクリックすると、選択したデバイスにメディアの再生を転送できます。

既知の問題
- ローカル再生用に作成されたメディア セッションは、Cast SDK の通知に切り替えるときに破棄され、再作成されます。
エントリ ポイント
メディア通知
アプリがローカル再生(ローカルで再生)用に MediaSession を含むメディア通知を投稿すると、メディア通知の右上隅に、コンテンツが現在再生されているデバイスの名前(スマートフォンのスピーカーなど)を含む通知チップが表示されます。通知チップをタップすると、出力切り替えダイアログのシステム UI が開きます。

音量の設定
出力切り替えツールのダイアログ システム UI は、デバイスの物理的な音量ボタンをクリックし、下部の設定アイコンをタップして、[<キャスト デバイス> で <アプリ名> を再生] というテキストをタップすることでもトリガーできます。

ステップの概要
- 前提条件が満たされていることを確認する
- AndroidManifest.xml で出力切り替えを有効にする
- バックグラウンド キャスト用に SessionManagerListener を更新する
- リモート間サポートを追加する
- setRemoteToLocalEnabled フラグを設定する
- ローカルで再生を続ける
前提条件
- 既存の Android アプリを AndroidX に移行します。
- 出力切り替え機能に必要な Android Sender SDK の最小バージョンを使用するように、アプリの
build.gradleを更新します。dependencies { ... implementation 'com.google.android.gms:play-services-cast-framework:21.2.0' ... }
- アプリがメディア通知をサポートしている。
- Android 13 を搭載したデバイス。
メディア通知を設定する
出力切り替えを使用するには、オーディオ アプリと動画アプリで、ローカル再生用のメディアの再生ステータスとコントロールを表示するメディア通知を作成する必要があります。これには、MediaSession を作成し、MediaSession のトークンを使用して MediaStyle を設定し、通知にメディア コントロールを設定する必要があります。
現在 MediaStyle と MediaSession を使用していない場合は、以下のスニペットで設定方法を確認できます。また、オーディオ アプリと動画アプリのメディア セッション コールバックを設定するためのガイドも用意されています。
// Create a media session. NotificationCompat.MediaStyle // PlayerService is your own Service or Activity responsible for media playback. val mediaSession = MediaSessionCompat(this, "PlayerService") // Create a MediaStyle object and supply your media session token to it. val mediaStyle = Notification.MediaStyle().setMediaSession(mediaSession.sessionToken) // Create a Notification which is styled by your MediaStyle object. // This connects your media session to the media controls. // Don't forget to include a small icon. val notification = Notification.Builder(this@PlayerService, CHANNEL_ID) .setStyle(mediaStyle) .setSmallIcon(R.drawable.ic_app_logo) .build() // Specify any actions which your users can perform, such as pausing and skipping to the next track. val pauseAction: Notification.Action = Notification.Action.Builder( pauseIcon, "Pause", pauseIntent ).build() notification.addAction(pauseAction)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { // Create a media session. NotificationCompat.MediaStyle // PlayerService is your own Service or Activity responsible for media playback. MediaSession mediaSession = new MediaSession(this, "PlayerService"); // Create a MediaStyle object and supply your media session token to it. Notification.MediaStyle mediaStyle = new Notification.MediaStyle().setMediaSession(mediaSession.getSessionToken()); // Specify any actions which your users can perform, such as pausing and skipping to the next track. Notification.Action pauseAction = Notification.Action.Builder(pauseIcon, "Pause", pauseIntent).build(); // Create a Notification which is styled by your MediaStyle object. // This connects your media session to the media controls. // Don't forget to include a small icon. String CHANNEL_ID = "CHANNEL_ID"; Notification notification = new Notification.Builder(this, CHANNEL_ID) .setStyle(mediaStyle) .setSmallIcon(R.drawable.ic_app_logo) .addAction(pauseAction) .build(); }

また、メディアの情報を通知に表示するには、メディアのメタデータと再生状態を MediaSession に追加する必要があります。
MediaSession にメタデータを追加するには、setMetaData() を使用し、MediaMetadataCompat.Builder() でメディアに関連するすべての MediaMetadata 定数を指定します。
mediaSession.setMetadata(MediaMetadataCompat.Builder() // Title .putString(MediaMetadata.METADATA_KEY_TITLE, currentTrack.title) // Artist // Could also be the channel name or TV series. .putString(MediaMetadata.METADATA_KEY_ARTIST, currentTrack.artist) // Album art // Could also be a screenshot or hero image for video content // The URI scheme needs to be "content", "file", or "android.resource". .putString( MediaMetadata.METADATA_KEY_ALBUM_ART_URI, currentTrack.albumArtUri) ) // Duration // If duration isn't set, such as for live broadcasts, then the progress // indicator won't be shown on the seekbar. .putLong(MediaMetadata.METADATA_KEY_DURATION, currentTrack.duration) .build() )
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { mediaSession.setMetadata( new MediaMetadataCompat.Builder() // Title .putString(MediaMetadata.METADATA_KEY_TITLE, currentTrack.title) // Artist // Could also be the channel name or TV series. .putString(MediaMetadata.METADATA_KEY_ARTIST, currentTrack.artist) // Album art // Could also be a screenshot or hero image for video content // The URI scheme needs to be "content", "file", or "android.resource". .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, currentTrack.albumArtUri) // Duration // If duration isn't set, such as for live broadcasts, then the progress // indicator won't be shown on the seekbar. .putLong(MediaMetadata.METADATA_KEY_DURATION, currentTrack.duration) .build() ); }

MediaSession に再生状態を追加するには、setPlaybackState() を使用し、PlaybackStateCompat.Builder() でメディアに関連するすべての PlaybackStateCompat 定数を指定します。
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() ); }

動画アプリの通知の動作
バックグラウンドでのローカル再生をサポートしていない動画アプリやオーディオ アプリでは、再生がサポートされていない状況でメディア コマンドが送信される問題を回避するために、メディア通知に特定の動作を設定する必要があります。
- メディアをローカルで再生し、アプリがフォアグラウンドにあるときに、メディア通知を投稿します。
- アプリがバックグラウンドにあるときに、ローカル再生を一時停止して通知を閉じます。
- アプリがフォアグラウンドに戻ると、ローカル再生が再開され、通知が再投稿されます。
AndroidManifest.xml で出力切り替えを有効にする
出力切り替えを有効にするには、アプリの AndroidManifest.xml に MediaTransferReceiver を追加する必要があります。そうでない場合、この機能は有効にならず、リモートからローカルへのフィーチャー トグルも無効になります。
<application>
...
<receiver
android:name="androidx.mediarouter.media.MediaTransferReceiver"
android:exported="true">
</receiver>
...
</application>
MediaTransferReceiver は、システム UI を使用してデバイス間でメディア転送を可能にするブロードキャスト レシーバです。詳細については、MediaTransferReceiver リファレンスをご覧ください。
ローカルからリモート
ユーザーが再生をローカルからリモートに切り替えると、Cast SDK は自動的に Cast セッションを開始します。ただし、アプリはローカルからリモートへの切り替えを処理する必要があります。たとえば、ローカル再生を停止し、キャスト デバイスにメディアを読み込む必要があります。アプリは、onSessionStarted() コールバックと onSessionEnded() コールバックを使用して、Cast の SessionManagerListener をリッスンし、Cast の SessionManager コールバックを受信したときにアクションを処理する必要があります。アプリは、出力切り替えダイアログが開いていて、アプリがフォアグラウンドにない場合でも、これらのコールバックが有効であることを確認する必要があります。
バックグラウンド キャスト用に SessionManagerListener を更新する
従来の Cast エクスペリエンスでは、アプリがフォアグラウンドにあるときに、ローカルからリモートへの切り替えがすでにサポートされています。一般的なキャスト エクスペリエンスは、ユーザーがアプリでキャスト アイコンをクリックし、メディアをストリーミングするデバイスを選択したときに開始されます。この場合、アプリは onCreate() または onStart() で SessionManagerListener に登録し、アプリのアクティビティの onStop() または onDestroy() でリスナーの登録を解除する必要があります。
出力切り替え機能を使用した新しいキャスト機能では、アプリがバックグラウンドにあるときにキャストを開始できます。これは、バックグラウンドで再生中に通知を投稿するオーディオ アプリで特に便利です。アプリは、サービスの onCreate() で SessionManager リスナーを登録し、サービスの onDestroy() で登録を解除できます。アプリがバックグラウンドにある場合、アプリは常にローカルからリモートへのコールバック(onSessionStarted など)を受信する必要があります。
アプリが MediaBrowserService を使用している場合は、そこに SessionManagerListener を登録することをおすすめします。
class MyService : Service() { private var castContext: CastContext? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) } protected fun onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) } } }
public class MyService extends Service { private CastContext castContext; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); } @Override protected void onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); } } }
このアップデートにより、アプリがバックグラウンドにある場合、ローカルからリモートへの切り替えは従来のキャストと同じように動作し、Bluetooth デバイスからキャスト デバイスへの切り替えに追加の作業は必要ありません。
リモートからローカル
出力スイッチャーを使用すると、リモート再生からスマートフォンのスピーカーまたはローカルの Bluetooth デバイスに転送できます。これを有効にするには、CastOptions で setRemoteToLocalEnabled フラグを true に設定します。
現在の送信側デバイスが複数の送信側を含む既存のセッションに参加し、現在のメディアをローカルに転送できるかどうかをアプリが確認する必要がある場合は、SessionTransferCallback の onTransferred コールバックを使用して SessionState を確認する必要があります。
setRemoteToLocalEnabled フラグを設定する
CastOptions.Builder は、アクティブなキャスト セッションがある場合に、出力スイッチャー ダイアログで転送先としてスマートフォンのスピーカーとローカル Bluetooth デバイスを表示または非表示にする setRemoteToLocalEnabled を提供します。
class CastOptionsProvider : OptionsProvider { fun getCastOptions(context: Context?): CastOptions { ... return Builder() ... .setRemoteToLocalEnabled(true) .build() } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { ... return new CastOptions.Builder() ... .setRemoteToLocalEnabled(true) .build() } }
ローカルで再生を続ける
リモートからローカルへの転送をサポートするアプリは、SessionTransferCallback を登録して、イベントが発生したときに通知を受け取る必要があります。これにより、メディアの転送を許可してローカルで再生を続行するかどうかを確認できます。
CastContext#addSessionTransferCallback(SessionTransferCallback) を使用すると、アプリは SessionTransferCallback を登録し、送信者がローカル再生に転送されたときに onTransferred コールバックと onTransferFailed コールバックをリッスンできます。
アプリが SessionTransferCallback の登録を解除すると、アプリは SessionTransferCallback を受信しなくなります。
SessionTransferCallback は、既存の SessionManagerListener コールバックの拡張機能であり、onSessionEnded がトリガーされた後にトリガーされます。リモートからローカルへのコールバックの順序は次のとおりです。
onTransferringonSessionEndingonSessionEndedonTransferred
アプリがバックグラウンドでキャストしているときに、メディア通知チップから出力切り替えを開くことができるため、アプリはバックグラウンド再生をサポートしているかどうかに応じて、ローカルへの転送を異なる方法で処理する必要があります。転送が失敗した場合、エラーが発生した時点で onTransferFailed が呼び出されます。
バックグラウンド再生をサポートするアプリ
バックグラウンドでの再生をサポートするアプリ(通常はオーディオ アプリ)の場合は、Service(MediaBrowserService など)を使用することをおすすめします。サービスは、onTransferred コールバックをリッスンし、アプリがフォアグラウンドまたはバックグラウンドにあるときにローカルで再生を再開する必要があります。
class MyService : Service() { private var castContext: CastContext? = null private var sessionTransferCallback: SessionTransferCallback? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) sessionTransferCallback = MySessionTransferCallback() castContext.addSessionTransferCallback(sessionTransferCallback) } protected fun onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback) } } } class MySessionTransferCallback : SessionTransferCallback() { fun onTransferring(@SessionTransferCallback.TransferType transferType: Int) { // Perform necessary steps prior to onTransferred } fun onTransferred(@SessionTransferCallback.TransferType transferType: Int, sessionState: SessionState?) { if (transferType == SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } fun onTransferFailed(@SessionTransferCallback.TransferType transferType: Int, @SessionTransferCallback.TransferFailedReason transferFailedReason: Int) { // Handle transfer failure. } } }
public class MyService extends Service { private CastContext castContext; private SessionTransferCallback sessionTransferCallback; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); sessionTransferCallback = new MySessionTransferCallback(); castContext.addSessionTransferCallback(sessionTransferCallback); } @Override protected void onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback); } } } public static class MySessionTransferCallback extends SessionTransferCallback { public MySessionTransferCallback() {} @Override public void onTransferring(@SessionTransferCallback.TransferType int transferType) { // Perform necessary steps prior to onTransferred } @Override public void onTransferred(@SessionTransferCallback.TransferType int transferType, SessionState sessionState) { if (transferType==SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } @Override public void onTransferFailed(@SessionTransferCallback.TransferType int transferType, @SessionTransferCallback.TransferFailedReason int transferFailedReason) { // Handle transfer failure. } } }
バックグラウンド再生に対応していないアプリ
バックグラウンド再生をサポートしていないアプリ(通常は動画アプリ)の場合は、onTransferred コールバックをリッスンし、アプリがフォアグラウンドにある場合はローカルで再生を再開することをおすすめします。
アプリがバックグラウンドにある場合は、再生を一時停止し、SessionState から必要な情報(メディア メタデータや再生位置など)を保存する必要があります。アプリがバックグラウンドからフォアグラウンドに切り替わったときに、保存された情報を使用してローカル再生を続行する必要があります。
class MyActivity : AppCompatActivity() { private var castContext: CastContext? = null private var sessionTransferCallback: SessionTransferCallback? = null protected fun onCreate() { castContext = CastContext.getSharedInstance(this) castContext.getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession::class.java) sessionTransferCallback = MySessionTransferCallback() castContext.addSessionTransferCallback(sessionTransferCallback) } protected fun onDestroy() { if (castContext != null) { castContext.getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession::class.java) if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback) } } } class MySessionTransferCallback : SessionTransferCallback() { fun onTransferring(@SessionTransferCallback.TransferType transferType: Int) { // Perform necessary steps prior to onTransferred } fun onTransferred(@SessionTransferCallback.TransferType transferType: Int, sessionState: SessionState?) { if (transferType == SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } fun onTransferFailed(@SessionTransferCallback.TransferType transferType: Int, @SessionTransferCallback.TransferFailedReason transferFailedReason: Int) { // Handle transfer failure. } } }
public class MyActivity extends AppCompatActivity { private CastContext castContext; private SessionTransferCallback sessionTransferCallback; @Override protected void onCreate() { castContext = CastContext.getSharedInstance(this); castContext .getSessionManager() .addSessionManagerListener(sessionManagerListener, CastSession.class); sessionTransferCallback = new MySessionTransferCallback(); castContext.addSessionTransferCallback(sessionTransferCallback); } @Override protected void onDestroy() { if (castContext != null) { castContext .getSessionManager() .removeSessionManagerListener(sessionManagerListener, CastSession.class); if (sessionTransferCallback != null) { castContext.removeSessionTransferCallback(sessionTransferCallback); } } } public static class MySessionTransferCallback extends SessionTransferCallback { public MySessionTransferCallback() {} @Override public void onTransferring(@SessionTransferCallback.TransferType int transferType) { // Perform necessary steps prior to onTransferred } @Override public void onTransferred(@SessionTransferCallback.TransferType int transferType, SessionState sessionState) { if (transferType==SessionTransferCallback.TRANSFER_TYPE_FROM_REMOTE_TO_LOCAL) { // Remote stream is transferred to the local device. // Retrieve information from the SessionState to continue playback on the local player. } } @Override public void onTransferFailed(@SessionTransferCallback.TransferType int transferType, @SessionTransferCallback.TransferFailedReason int transferFailedReason) { // Handle transfer failure. } } }
リモート間
出力スイッチャーは、ストリーム拡張機能を使用して、オーディオ アプリ用に複数の Cast 対応スピーカー デバイスに拡張する機能をサポートしています。
オーディオ アプリとは、Google Cast SDK Developer Console の受信側アプリの設定で Google Cast for Audio をサポートしているアプリです。

スピーカーでのストリーミング拡張
出力切り替えを使用するオーディオ アプリは、ストリーム拡張機能を使用して、キャスト セッション中に複数の Cast 対応スピーカー デバイスに音声を拡張できます。
この機能は Cast プラットフォームでサポートされており、アプリがデフォルトの UI を使用している場合は、これ以上の変更は必要ありません。カスタム UI を使用している場合、アプリは UI を更新して、アプリがグループにキャストしていることを反映する必要があります。

ストリームの拡張中に新しい拡張グループ名を取得するには、CastSession#addCastListener を使用して Cast.Listener を登録します。次に、onDeviceNameChanged コールバック中に CastSession#getCastDevice() を呼び出します。
class MyActivity : Activity() { private var mCastSession: CastSession? = null private lateinit var mCastContext: CastContext private lateinit var mSessionManager: SessionManager private val mSessionManagerListener: SessionManagerListener<CastSession> = SessionManagerListenerImpl() private val mCastListener = CastListener() private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> { override fun onSessionStarting(session: CastSession?) {} override fun onSessionStarted(session: CastSession?, sessionId: String) { addCastListener(session) } override fun onSessionStartFailed(session: CastSession?, error: Int) {} override fun onSessionSuspended(session: CastSession?, reason Int) { removeCastListener() } override fun onSessionResuming(session: CastSession?, sessionId: String) {} override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) { addCastListener(session) } override fun onSessionResumeFailed(session: CastSession?, error: Int) {} override fun onSessionEnding(session: CastSession?) {} override fun onSessionEnded(session: CastSession?, error: Int) { removeCastListener() } } private inner class CastListener : Cast.Listener() { override fun onDeviceNameChanged() { mCastSession?.let { val castDevice = it.castDevice val deviceName = castDevice.friendlyName // Update UIs with the new cast device name. } } } private fun addCastListener(castSession: CastSession) { mCastSession = castSession mCastSession?.addCastListener(mCastListener) } private fun removeCastListener() { mCastSession?.removeCastListener(mCastListener) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mCastContext = CastContext.getSharedInstance(this) mSessionManager = mCastContext.sessionManager mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onDestroy() { super.onDestroy() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java) } }
public class MyActivity extends Activity { private CastContext mCastContext; private CastSession mCastSession; private SessionManager mSessionManager; private SessionManagerListener<CastSession> mSessionManagerListener = new SessionManagerListenerImpl(); private Cast.Listener mCastListener = new CastListener(); private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> { @Override public void onSessionStarting(CastSession session) {} @Override public void onSessionStarted(CastSession session, String sessionId) { addCastListener(session); } @Override public void onSessionStartFailed(CastSession session, int error) {} @Override public void onSessionSuspended(CastSession session, int reason) { removeCastListener(); } @Override public void onSessionResuming(CastSession session, String sessionId) {} @Override public void onSessionResumed(CastSession session, boolean wasSuspended) { addCastListener(session); } @Override public void onSessionResumeFailed(CastSession session, int error) {} @Override public void onSessionEnding(CastSession session) {} @Override public void onSessionEnded(CastSession session, int error) { removeCastListener(); } } private class CastListener extends Cast.Listener { @Override public void onDeviceNameChanged() { if (mCastSession == null) { return; } CastDevice castDevice = mCastSession.getCastDevice(); String deviceName = castDevice.getFriendlyName(); // Update UIs with the new cast device name. } } private void addCastListener(CastSession castSession) { mCastSession = castSession; mCastSession.addCastListener(mCastListener); } private void removeCastListener() { if (mCastSession != null) { mCastSession.removeCastListener(mCastListener); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCastContext = CastContext.getSharedInstance(this); mSessionManager = mCastContext.getSessionManager(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onDestroy() { super.onDestroy(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); } }
リモート間のテスト
この機能をテストするには:
- 従来のキャストまたはローカルからリモートを使用して、Cast 対応デバイスにコンテンツをキャストします。
- いずれかのエントリ ポイントを使用して、出力切り替えを開きます。
- 別の Cast 対応デバイスをタップすると、オーディオ アプリは追加のデバイスにコンテンツを拡張し、動的グループを作成します。
- Cast 対応デバイスをもう一度タップすると、ダイナミック グループから削除されます。