MediaRouter 總覽

您必須取得執行個體,才能在應用程式中使用 MediaRouter 架構 MediaRouter 物件的結構,並附加 用於監聽轉送事件的 MediaRouter.Callback 物件。 透過媒體路徑傳送的內容會通過路徑的 相關聯的 MediaRouteProvider (除了少數特殊情況外) 例如藍牙輸出裝置)。圖 1 概略說明瞭 用來在裝置之間轉送內容的類別。

圖 1. 應用程式使用的主要媒體路由器類別總覽。

注意:要讓應用程式提供支援服務 Google Cast 裝置、 您應使用 Cast SDK 並將應用程式建構為 Cast 發送端請依照 投放說明文件 而不是直接使用 MediaRouter 架構

媒體路徑按鈕

Android 應用程式應使用媒體路徑按鈕控制媒體轉送功能。MediaRouter 架構 提供標準按鈕介面,方便使用者辨識及使用 並設為「優先」媒體路徑按鈕通常位於 應用程式的動作列,如圖 2 所示。

圖 2. 「媒體路徑」按鈕的 動作列。

使用者按下媒體路線按鈕時,可用的媒體路線就會顯示在清單中,如圖 3 所示。

圖 3. 按下媒體路徑按鈕後顯示可用的媒體路徑清單。

請按照下列步驟建立媒體路徑按鈕:

  1. 使用 AppCompatActivity
  2. 定義媒體路徑按鈕選單項目
  3. 建立 MediaRouteSelector
  4. 在動作列中新增媒體路徑按鈕
  5. 在活動生命週期中建立及管理 MediaRouter.Callback 方法

本節將說明前四個步驟。下一節將說明回呼方法。

使用 AppCompatActivity

在活動中使用媒體路由器架構時 然後匯入 AppCompatActivity 中的活動 androidx.appcompat.app 套件。您必須將 androidx.appcompat:appcompatandroidx.mediarouter:mediarouter 支援程式庫。進一步瞭解如何新增支援資料庫 。請參閱「開始使用 Android Jetpack」。

注意:請務必使用 androidx 實作媒體路由器架構請勿使用舊版 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="androidx.mediarouter.app.MediaRouteActionProvider"
        app:showAsAction="always"
    />
</menu>

建立 MediaRouteSelector

媒體路徑按鈕選單中顯示的路徑是由 MediaRouteSelector 決定。 延長 AppCompatActivity 的活動記錄 並在活動建立時呼叫 MediaRouteSelector.Builder 時建立選取器 呼叫 onCreate() 方法 所能呼叫的函式請注意,選取器會儲存在類別變數中,而且已指定允許的路線類型 方法是新增 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。這個路徑類型會將執行應用程式的裝置視為遙控器。 已連結的接收端裝置可處理所有內容資料擷取、解碼和播放作業。 瞭解支援 Google Cast 的應用程式 (例如 Chromecast,工作。

部分製造商支援名為「次要輸出」的特殊轉送選項。有了這個轉送方式 媒體應用程式會擷取、算繪及串流播放影片或音樂,並直接串流至所選遠端接收器裝置的螢幕和/或喇叭。 使用次要輸出將內容傳送到支援無線功能的音樂系統或視訊顯示器。如要探索 挑選所需裝置,您需要將 CATEGORY_LIVE_AUDIOCATEGORY_LIVE_VIDEO 控制 MediaRouteSelector。此外,您也需要建立和處理自己的 Presentation 對話方塊。

在動作列中新增媒體路徑按鈕

定義媒體路徑選單和 MediaRouteSelector 後,您現在可將媒體路徑按鈕新增至活動。 為每個活動覆寫 onCreateOptionsMenu() 方法,即可新增選項 或前往 Google 試算表選單

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 回呼

在相同裝置上執行的所有應用程式會共用單一 MediaRouter 執行個體及其路徑 (根據應用程式的 MediaRouteSelector 依應用程式篩選)。每個活動都會與 MediaRouter 通訊 使用自己的 MediaRouter.Callback 實作 方法。每當使用者選取、變更或中斷路線時,MediaRouter 就會呼叫回呼方法。

回呼中有幾種方法,您可以覆寫該方法,以接收 轉送事件實作的 MediaRouter.Callback 類別至少應覆寫 「onRouteSelected()」和 onRouteUnselected()

MediaRouter 是共用資源,因此應用程式必須管理其 MediaRouter 回呼 回應一般的活動生命週期回呼:

  • 活動建立後 (onCreate(Bundle)) 會擷取 MediaRouter 指標,然後在應用程式的生命週期內按住該指標。
  • 在活動顯示時將回呼附加至 MediaRouter (onStart()),並在活動隱藏時卸離 (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 才能播放 並從服務的生命週期回呼中呼叫媒體路由器架構。

控制遠端播放路徑

選取遠端播放路徑時,您的應用程式會充當遙控器。路線另一端的裝置 會處理所有內容資料擷取、解碼和播放功能。應用程式使用者介面中的控制項會使用 RemotePlaybackClient 物件。

RemotePlaybackClient 類別提供其他方法 管理內容播放方式以下是一些 RemotePlaybackClient 類別的主要播放方法:

  • play() - 播放特定媒體 Uri 所指定的媒體檔案。
  • pause() - 暫停 目前正在播放媒體曲目。
  • resume() - 繼續 暫停播放目前的曲目。
  • seek():移至特定 位於目前播放軌中的位置。
  • release() - 卸除 連結應用程式與遠端播放裝置。

你可以使用上述方法,將動作附加至你在 應用程式。這些方法大多都允許納入回呼物件,方便您監控 播放工作或控制要求的進度。

RemotePlaybackClient 類別也支援將 多個媒體項目用於播放及管理媒體佇列。

程式碼範例

Android BasicMediaRouterMediaRouter 範例,進一步示範如何使用 MediaRouter API。