アプリ内で MediaRouter フレームワークを使用するには、MediaRouter
オブジェクトのインスタンスを取得し、MediaRouter.Callback
オブジェクトをアタッチしてルーティング イベントをリッスンする必要があります。
メディアルート経由で送信されるコンテンツは、そのルートに関連付けられた MediaRouteProvider
を通過します(Bluetooth 出力デバイスなどのいくつかの特別な場合を除く)。図 1 は、デバイス間でのコンテンツのルーティングに使用されるクラスの概要を示しています。

図 1. アプリで使用する主要なメディア ルーター クラスの概要。
注: アプリで Google Cast デバイスをサポートする場合は、Cast SDK を使用して、アプリを Cast センダーとしてビルドする必要があります。直接 MediaRouter フレームワークを使用せず、Cast ドキュメントの手順を行ってください。
メディアルート ボタン
Android アプリでは、メディアルート ボタンを使用してメディアのルーティングを制御します。MediaRouter フレームワークには、このボタン用の標準インターフェースが用意されています。これにより、ユーザーはルーティングが利用可能な場合にそれを認識して使用できます。メディアルート ボタンは、通常、アプリのアクションバーの右端に配置されます(図 2 参照)。

図 2. アクションバーのメディアルート ボタン
ユーザーがメディアルート ボタンを選択すると、利用可能なメディアルートのリストが表示されます(図 3 参照)。

図 3. メディアルート ボタンを選択することで表示される利用可能なメディアルートのリスト
メディアルート ボタンの作成手順は次のとおりです。
- AppCompatActivity を使用する
- メディアルート ボタンのメニュー項目を定義する
- MediaRouteSelector を作成する
- メディアルート ボタンをアクションバーに追加する
- アクティビティのライフサイクルで MediaRouter.Callback メソッドを作成し管理する
このセクションでは、最初の 4 つの手順について説明します。Callback メソッドについては、その次のセクションで説明します。
AppCompatActivity を使用する
アクティビティでメディア ルーター フレームワークを使用するには、アクティビティを AppCompatActivity
から拡張し、パッケージ android.support.v7.media
をインポートする必要があります。また、サポート ライブラリ v7-appcompat と v7-mediarouter を、アプリ開発プロジェクトに追加する必要があります。
サポート ライブラリをプロジェクトに追加する方法の詳細については、サポート ライブラリのセットアップをご覧ください。
注意: 必ずメディア ルーター フレームワークの android.support.v7.media
の実装を使用してください。
古い android.media
パッケージを使用しないでください。
メディアルート ボタンのメニュー項目を定義する
メディアルート ボタンのメニュー項目を定義する XML ファイルを作成します。
項目のアクションは、MediaRouteActionProvider
クラスにします。
ファイルの例を以下に示します。
// myMediaRouteButtonMenuItem.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always" /> </menu>
MediaRouteSelector を作成する
メディアルート ボタンのメニューに表示されるルートは、MediaRouteSelector
によって決まります。
以下のコードサンプルに示すように、AppCompatActivity
からアクティビティを拡張し、アクティビティを作成する際に onCreate() メソッドから MediaRouteSelector.Builder
を呼び出してセレクタを作成します。なお、セレクタはクラス変数に保存され、使用できるルートタイプを指定するには、MediaControlIntent
オブジェクトを追加します。
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mSelector: MediaRouteSelector? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create a route selector for the type of routes your app supports. mSelector = MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build() } }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouteSelector mSelector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a route selector for the type of routes your app supports. mSelector = new MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build(); } }
ほとんどのアプリでは、必要なルートタイプは CATEGORY_REMOTE_PLAYBACK
のみです。このルートタイプでは、アプリを実行しているデバイスはリモコンとして扱われます。
コンテンツ データの取得、デコード、再生のすべては、接続された受信デバイスにより処理されます。
Chromecast など、Google Cast をサポートするアプリはこの仕組みで動作します。
メーカーによっては、「セカンダリ出力」と呼ばれる特別なルーティング オプションをサポートしています。このルーティングを使用すると、メディアアプリでは、選択したリモート受信デバイスの画面やスピーカーに直接、動画や音楽を取得、レンダリング、ストリーミングできます。
セカンダリ出力を使用すれば、ワイヤレス対応の音楽システムやビデオ ディスプレイにコンテンツを送信できます。このようなデバイスの検出と選択を可能にするには、コントロール カテゴリ CATEGORY_LIVE_AUDIO
または CATEGORY_LIVE_VIDEO
を MediaRouteSelector に追加する必要があります。さらに、独自の Presentation
ダイアログを作成して処理する必要があります。
メディアルート ボタンをアクションバーに追加する
メディアルート メニューと MediaRouteSelector を定義したら、メディアルート ボタンをアクティビティに追加できます。
オプション メニューを追加するには、アクティビティごとに onCreateOptionsMenu()
メソッドをオーバーライドします。
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) // Inflate the menu and configure the media router action provider. menuInflater.inflate(R.menu.sample_media_router_menu, menu) // Attach the MediaRouteSelector to the menu item val mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item) val mediaRouteActionProvider = MenuItemCompat.getActionProvider(mediaRouteMenuItem) as MediaRouteActionProvider // Attach the MediaRouteSelector that you built in onCreate() selector?.also(mediaRouteActionProvider::setRouteSelector) // Return true to show the menu. return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Inflate the menu and configure the media router action provider. getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); // Attach the MediaRouteSelector to the menu item MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider)MenuItemCompat.getActionProvider( mediaRouteMenuItem); // Attach the MediaRouteSelector that you built in onCreate() mediaRouteActionProvider.setRouteSelector(selector); // Return true to show the menu. return true; }
アプリにアクションバーを実装する方法の詳細については、アクションバー デベロッパー ガイドをご覧ください。
メディアルート ボタンを MediaRouteButton
として任意のビューに追加することもできます。setRouteSelector()
メソッドを使用して、MediaRouteSelector をボタンにアタッチする必要があります。アプリにメディアルート ボタンを組み込む際のガイドラインについては、Google Cast 設計チェックリストをご覧ください。
MediaRouter コールバック
同じデバイスで実行されるすべてのアプリは、1 つの MediaRouter
インスタンスとそのルート(アプリの MediaRouteSelector によってアプリごとにフィルタされる)を共有します。各アクティビティと MediaRouter との通信には、MediaRouter.Callback
メソッドのアクティビティごとの実装が使用されます。ユーザーがルートを選択、変更、切断するたびに、MediaRouter によりこのコールバック メソッドが呼び出されます。
このコールバックには、ルーティング イベントに関する情報を受け取るためにオーバーライドできるメソッドがいくつかあります。MediaRouter.Callback
クラスの実装では、少なくとも onRouteSelected()
と onRouteUnselected()
をオーバーライドします。
MediaRouter は共有リソースであるため、アプリは通常のアクティビティ ライフサイクルにおけるコールバックへの応答として、次のように MediaRouter コールバックに対応する必要があります。
- アクティビティが作成されたとき(
onCreate(Bundle)
)にMediaRouter
へのポインタを取得し、アプリの有効期間中はそのポインタを保持する。 - アクティビティが表示されたとき(
onStart()
)にコールバックを MediaRouter にアタッチし、非表示になったとき(onStop()
)にデタッチする。
以下のコードサンプルは、コールバック オブジェクトを作成および保存する方法、MediaRouter
インスタンスを取得する方法、コールバックを管理する方法を示しています。
onStart()
でコールバックをアタッチするとき、CALLBACK_FLAG_REQUEST_DISCOVERY
フラグを使用していることに注意してください。これにより、メディアルート ボタンの使用可能ルートのリストが、MediaRouteSelector によって更新されます。
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mediaRouter: MediaRouter? = null private var mSelector: MediaRouteSelector? = null // Variables to hold the currently selected route and its playback client private var mRoute: MediaRouter.RouteInfo? = null private var remotePlaybackClient: RemotePlaybackClient? = null // Define the Callback object and its methods, save the object in a class variable private val mediaRouterCallback = object : MediaRouter.Callback() { override fun onRouteSelected(router: MediaRouter, route: MediaRouter.RouteInfo) { Log.d(TAG, "onRouteSelected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Stop local playback (if necessary) // ... // Save the new route mRoute = route // Attach a new playback client remotePlaybackClient = RemotePlaybackClient(this@MediaRouterPlaybackActivity, mRoute) // Start remote playback (if necessary) // ... } } override fun onRouteUnselected( router: MediaRouter, route: MediaRouter.RouteInfo, reason: Int ) { Log.d(TAG, "onRouteUnselected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Changed route: tear down previous client mRoute?.also { remotePlaybackClient?.release() remotePlaybackClient = null } // Save the new route mRoute = route when (reason) { MediaRouter.UNSELECT_REASON_ROUTE_CHANGED -> { // Resume local playback (if necessary) // ... } } } } } // Retain a pointer to the MediaRouter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Get the media router service. mediaRouter = MediaRouter.getInstance(this) ... } // Use this callback to run your MediaRouteSelector to generate the // list of available media routes override fun onStart() { mSelector?.also { selector -> mediaRouter?.addCallback(selector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY) } super.onStart() } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. override fun onStop() { mediaRouter?.removeCallback(mediaRouterCallback) super.onStop() } ... }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouter mediaRouter; private MediaRouteSelector mSelector; // Variables to hold the currently selected route and its playback client private MediaRouter.RouteInfo mRoute; private RemotePlaybackClient remotePlaybackClient; // Define the Callback object and its methods, save the object in a class variable private final MediaRouter.Callback mediaRouterCallback = new MediaRouter.Callback() { @Override public void onRouteSelected(MediaRouter router, RouteInfo route) { Log.d(TAG, "onRouteSelected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Stop local playback (if necessary) // ... // Save the new route mRoute = route; // Attach a new playback client remotePlaybackClient = new RemotePlaybackClient(this, mRoute); // Start remote playback (if necessary) // ... } } @Override public void onRouteUnselected(MediaRouter router, RouteInfo route, int reason) { Log.d(TAG, "onRouteUnselected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Changed route: tear down previous client if (mRoute != null && remotePlaybackClient != null) { remotePlaybackClient.release(); remotePlaybackClient = null; } // Save the new route mRoute = route; if (reason != MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) { // Resume local playback (if necessary) // ... } } } } // Retain a pointer to the MediaRouter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the media router service. mediaRouter = MediaRouter.getInstance(this); ... } // Use this callback to run your MediaRouteSelector to generate the list of available media routes @Override public void onStart() { mediaRouter.addCallback(mSelector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); super.onStart(); } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. @Override public void onStop() { mediaRouter.removeCallback(mediaRouterCallback); super.onStop(); } ... }
メディア ルーター フレームワークには、アクティビティに対するコールバックの追加と削除を処理する MediaRouteDiscoveryFragment
クラスも用意されています。
注: バックグラウンドに置かれた状態で音楽を再生する音楽再生アプリを開発する場合は、再生用の Service
を作成し、そのサービスのライフサイクル コールバックからメディア ルーター フレームワークを呼び出す必要があります。
リモート再生ルートの制御
リモート再生ルートを選択した場合は、アプリはリモコンとして機能します。ルートの反対側のデバイスは、コンテンツ データの取得、デコード、再生の機能をすべて処理します。アプリの UI のコントロールは、RemotePlaybackClient
オブジェクトを使用して受信デバイスと通信します。
RemotePlaybackClient
クラスには、コンテンツの再生を管理するための追加のメソッドが用意されています。以下に、RemotePlaybackClient
クラスの主要な再生メソッドをいくつか示します。
play()
-Uri
で指定された特定のメディア ファイルを再生します。pause()
- 現在再生中のメディア トラックを一時停止します。resume()
- 一時停止コマンドの後、現在のトラックの続きを再生します。seek()
- 現在のトラックの特定の位置に移動します。release()
- アプリからリモート再生デバイスへの接続を解除します。
これらのメソッドを使用して、アプリで提供する再生コントロールにアクションをアタッチできます。このうちのほとんどはコールバック オブジェクトを含めることもできるため、再生タスクやコントロール リクエストの進行状況を監視できます。
RemotePlaybackClient
クラスは、複数のメディアを再生用のキューに入れたり、そのメディアキューを管理したりする機能もサポートしています。
サンプルコード
Android BasicMediaRouter サンプルと MediaRouter サンプルには、MediaRouter API のその他の使用方法が示されています。