MediaRouteProvider 總覽

Android 媒體路由器架構可讓製造商在裝置上啟用播放功能 經由名為 MediaRouteProvider 的標準化介面取得。 路徑提供者定義了在接收器裝置上播放媒體的通用介面 透過任何支援媒體的 Android 應用程式,在您的設備上播放媒體 路徑。

本指南將說明如何為接收器裝置建立媒體路線提供者,並為其建立 適用於在 Android 上執行的其他媒體播放應用程式。如要使用這個 API,您 應該熟悉這些主要類別 MediaRouteProviderMediaRouteProviderDescriptorRouteController

總覽

Android 媒體路由器架構可讓媒體應用程式開發人員和媒體播放裝置 ,透過通用 API 和常見的使用者介面進行連結。符合以下條件的應用程式開發人員 實作 MediaRouter 介面,即可連線至 並向參與媒體路由器架構的裝置播放內容。媒體 播放裝置製造商可以發布 MediaRouteProvider 參與架構,讓其他應用程式可以 在接收器裝置上播放媒體。圖 1 說明應用程式如何連線至接收端 從媒體路由器架構存取裝置

圖 1. 媒體轉送提供者類別如何提供通訊總覽 或從媒體應用程式傳至接收器裝置

為接收器裝置建構媒體路徑供應商時,供應商會 用於以下目的:

  • 說明並發布接收器裝置的功能,讓其他應用程式可以找到該裝置 並使用其播放功能
  • 納入接收器裝置的程式設計介面及其通訊 確保裝置與媒體路由器架構相容。

路線提供者分佈情形

媒體路線供應商屬於 Android 應用程式的一環,路徑供應商可以是 讓其他應用程式使用 MediaRouteProviderService 或納入 將 MediaRouteProvider 替換為您自己的服務並宣告意圖 媒體轉送供應商篩選器這些步驟可讓其他應用程式探索及使用 媒體路徑

注意:含有媒體路線供應商的應用程式也可以加入 MediaRouter 介面 路徑供應商,但這不是必要步驟

MediaRouter 支援資料庫

媒體路由器 API 的定義是在 AndroidX MediaRouter 程式庫 您必須將這個程式庫新增至應用程式開發專案。 如要進一步瞭解如何在 請參閱支援資料庫設定

注意:請務必使用 AndroidX 實作媒體路由器架構 請勿使用舊版 android.media 套件。

建立提供者服務

媒體路由器架構必須能夠探索及連線至你的媒體路由供應商 ,允許其他應用程式使用路線。而媒體路由器架構 尋找宣告媒體路線供應商意圖動作的應用程式。其他應用程式想要 連線至您的供應商,架構必須能夠叫用及連結該架構,確保您的供應商 必須在 Service 中封裝。

以下範例程式碼顯示媒體路由供應商服務的宣告,以及 意圖篩選器,讓媒體路由器發現及使用意圖篩選器 架構:

<service android:name=".provider.SampleMediaRouteProviderService"
    android:label="@string/sample_media_route_provider_service"
    android:process=":mrp">
    <intent-filter>
        <action android:name="android.media.MediaRouteProviderService" />
    </intent-filter>
</service>

這個資訊清單範例宣告的服務納入實際媒體路徑提供者類別。 Android 媒體路由器架構提供 MediaRouteProviderService 類別可做為以下項目的服務包裝函式使用: 媒體路線供應商。以下範例程式碼示範如何使用這個包裝函式 類別:

Kotlin

class SampleMediaRouteProviderService : MediaRouteProviderService() {

    override fun onCreateMediaRouteProvider(): MediaRouteProvider {
        return SampleMediaRouteProvider(this)
    }
}

Java

public class SampleMediaRouteProviderService extends MediaRouteProviderService {

    @Override
    public MediaRouteProvider onCreateMediaRouteProvider() {
        return new SampleMediaRouteProvider(this);
    }
}

指定路徑功能

連結至媒體路由器架構的應用程式可以透過 應用程式的資訊清單宣告,但您也必須知道媒體路徑的功能 不必停下腳步媒體路徑可分成多種類型,具有不同的功能和其他應用程式 必須能夠查閱這些詳細資料,以判斷它們是否與您的路線相容。

媒體路由器架構可讓您定義及發布媒體功能 經過 IntentFilter 物件、MediaRouteDescriptor 物件和 MediaRouteProviderDescriptor 的路線。本節將說明如何運用 類別,用於發布其他應用程式的媒體路徑詳細資料。

路線類別

媒體轉送供應商的程式輔助說明時,您必須指定 您的供應商是否支援遠端播放和/或次要輸出。以下是路徑 媒體路由器架構提供的各種類別

如要在媒體路徑說明中加入這些設定,請插入這些設定 IntentFilter 物件,稍後您必須加入 MediaRouteDescriptor 物件:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {
        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run {
            addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            arrayListOf(this)
        }
    }
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {
    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
    static {
        IntentFilter videoPlayback = new IntentFilter();
        videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
    }
}

如果您指定 CATEGORY_REMOTE_PLAYBACK 意圖,則必須一併定義媒體類型和 您的媒體路徑供應商支援播放控制項,下一節將說明如何 為您的裝置指定這些設定。

媒體類型和通訊協定

遠端播放裝置的媒體路徑供應商必須指定媒體類型並傳輸 系統支援的通訊協定如要指定這些設定,請使用 IntentFilter 類別,以及 addDataScheme() 和 該物件的 addDataType() 方法。 下列程式碼片段示範如何定義支援遠端影片的意圖篩選器 使用 http、https 和即時串流通訊協定 (RTSP) 播放:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {

        private fun IntentFilter.addDataTypeUnchecked(type: String) {
            try {
                addDataType(type)
            } catch (ex: IntentFilter.MalformedMimeTypeException) {
                throw RuntimeException(ex)
            }
        }

        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run {
            addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            addAction(MediaControlIntent.ACTION_PLAY)
            addDataScheme("http")
            addDataScheme("https")
            addDataScheme("rtsp")
            addDataTypeUnchecked("video/*")
            arrayListOf(this)
        }
    }
    ...
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {

    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;

    static {
        IntentFilter videoPlayback = new IntentFilter();
        videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
        videoPlayback.addDataScheme("http");
        videoPlayback.addDataScheme("https");
        videoPlayback.addDataScheme("rtsp");
        addDataTypeUnchecked(videoPlayback, "video/*");
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
    }
    ...

    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
        try {
            filter.addDataType(type);
        } catch (MalformedMimeTypeException ex) {
            throw new RuntimeException(ex);
        }
    }
}

播放控制項

提供遠端播放功能的媒體路由供應商必須指定媒體控制項類型 Kubernetes 環境以下是媒體路徑提供的一般控制項類型:

  • 播放控制項,例如播放、暫停、倒轉和快轉。
  • 排入佇列功能,可讓傳送應用程式新增及移除項目 從接收端裝置維護的播放清單中取樣。
  • 工作階段功能:避免傳送應用程式乾擾各個工作階段 另一方式是透過接收端裝置為提出要求的應用程式提供工作階段 ID,然後 並附上每個後續播放控制要求 ID

以下程式碼範例示範如何建構意圖篩選器,以支援 基本媒體路徑播放控制項:

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    companion object {
        ...
        private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = run {
            val videoPlayback: IntentFilter = ...
            ...
            val playControls = IntentFilter().apply {
                addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
                addAction(MediaControlIntent.ACTION_SEEK)
                addAction(MediaControlIntent.ACTION_GET_STATUS)
                addAction(MediaControlIntent.ACTION_PAUSE)
                addAction(MediaControlIntent.ACTION_RESUME)
                addAction(MediaControlIntent.ACTION_STOP)
            }
            arrayListOf(videoPlayback, playControls)
        }
    }
    ...
}

Java

public final class SampleMediaRouteProvider extends MediaRouteProvider {
    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
    static {
        ...
        IntentFilter playControls = new IntentFilter();
        playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
        playControls.addAction(MediaControlIntent.ACTION_SEEK);
        playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
        playControls.addAction(MediaControlIntent.ACTION_PAUSE);
        playControls.addAction(MediaControlIntent.ACTION_RESUME);
        playControls.addAction(MediaControlIntent.ACTION_STOP);
        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
        CONTROL_FILTERS_BASIC.add(videoPlayback);
        CONTROL_FILTERS_BASIC.add(playControls);
    }
    ...
}

如要進一步瞭解可用的播放控制項意圖,請參閱 MediaControlIntent 類別。

MediaRouteProviderDescriptor

使用 IntentFilter 物件定義媒體路徑的功能後,即可建立用於發布於 Android 媒體路由器架構這個描述元物件包含媒體的規格 路線的功能,方便其他應用程式判斷與媒體互動的方式 路徑。

以下範例程式碼說明如何將先前建立的意圖篩選器新增至 MediaRouteProviderDescriptor,並將描述元設為 媒體路由器架構

Kotlin

class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) {

    init {
        publishRoutes()
    }

    private fun publishRoutes() {
        val resources = context.resources
        val routeName: String = resources.getString(R.string.variable_volume_basic_route_name)
        val routeDescription: String = resources.getString(R.string.sample_route_description)
        // Create a route descriptor using previously created IntentFilters
        val routeDescriptor: MediaRouteDescriptor =
                MediaRouteDescriptor.Builder(VARIABLE_VOLUME_BASIC_ROUTE_ID, routeName)
                        .setDescription(routeDescription)
                        .addControlFilters(CONTROL_FILTERS_BASIC)
                        .setPlaybackStream(AudioManager.STREAM_MUSIC)
                        .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
                        .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                        .setVolumeMax(VOLUME_MAX)
                        .setVolume(mVolume)
                        .build()
        // Add the route descriptor to the provider descriptor
        val providerDescriptor: MediaRouteProviderDescriptor =
                MediaRouteProviderDescriptor.Builder()
                        .addRoute(routeDescriptor)
                        .build()

        // Publish the descriptor to the framework
        descriptor = providerDescriptor
    }
    ...
}

Java

public SampleMediaRouteProvider(Context context) {
    super(context);
    publishRoutes();
}

private void publishRoutes() {
    Resources r = getContext().getResources();
    // Create a route descriptor using previously created IntentFilters
    MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
            VARIABLE_VOLUME_BASIC_ROUTE_ID,
            r.getString(R.string.variable_volume_basic_route_name))
            .setDescription(r.getString(R.string.sample_route_description))
            .addControlFilters(CONTROL_FILTERS_BASIC)
            .setPlaybackStream(AudioManager.STREAM_MUSIC)
            .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
            .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
            .setVolumeMax(VOLUME_MAX)
            .setVolume(mVolume)
            .build();
    // Add the route descriptor to the provider descriptor
    MediaRouteProviderDescriptor providerDescriptor =
            new MediaRouteProviderDescriptor.Builder()
            .addRoute(routeDescriptor)
            .build();

    // Publish the descriptor to the framework
    setDescriptor(providerDescriptor);
}

如要進一步瞭解可用的描述元設定,請參閱參考說明文件 MediaRouteDescriptorMediaRouteProviderDescriptor

控制路徑

應用程式連上媒體路由供應商後,供應商會接收播放內容 讓其他應用程式傳送到您的路線的媒體路由器架構。為了處理 要求,您必須提供用於處理指令的 MediaRouteProvider.RouteController 類別實作。 並處理與接收器裝置的實際通訊內容。

媒體路由器架構會呼叫 onCreateRouteController() 方法以取得這個類別的例項,然後轉送要求至該類別的例項。 以下是 MediaRouteProvider.RouteController 類別的主要方法,您必須對該類別實作這些方法 您的媒體轉送供應商:

  • onSelect() — 應用程式選擇播放路線時呼叫。您可以使用這個方法 開始播放媒體前可能需要的準備工作。
  • onControlRequest():將特定播放指令傳送至接收裝置。
  • onSetVolume():向接收裝置傳送要求,將播放音量設為 特定值。
  • onUpdateVolume():將要求傳送至接收裝置,以便修改播放內容 指定磁碟區的用量
  • onUnselect():應用程式取消選取路徑時呼叫。
  • onRelease() — 架構不再需要路線時呼叫,以釋放路線 再複習一下,機構節點 是所有 Google Cloud Platform 資源的根節點

所有播放控制項要求 (音量變更除外) 都會導向「onControlRequest()」 方法。實作此方法時必須剖析並回應控制要求 才是正確的做法以下是這個方法的實作範例,該方法會處理 遠端播放媒體路徑:

Kotlin

private class SampleRouteController : MediaRouteProvider.RouteController() {
    ...

    override fun onControlRequest(
            intent: Intent,
            callback: MediaRouter.ControlRequestCallback?
    ): Boolean {
        return if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
            val action = intent.action
            when (action) {
                MediaControlIntent.ACTION_PLAY -> handlePlay(intent, callback)
                MediaControlIntent.ACTION_ENQUEUE -> handleEnqueue(intent, callback)
                MediaControlIntent.ACTION_REMOVE -> handleRemove(intent, callback)
                MediaControlIntent.ACTION_SEEK -> handleSeek(intent, callback)
                MediaControlIntent.ACTION_GET_STATUS -> handleGetStatus(intent, callback)
                MediaControlIntent.ACTION_PAUSE -> handlePause(intent, callback)
                MediaControlIntent.ACTION_RESUME -> handleResume(intent, callback)
                MediaControlIntent.ACTION_STOP -> handleStop(intent, callback)
                MediaControlIntent.ACTION_START_SESSION -> handleStartSession(intent, callback)
                MediaControlIntent.ACTION_GET_SESSION_STATUS ->
                    handleGetSessionStatus(intent, callback)
                MediaControlIntent.ACTION_END_SESSION -> handleEndSession(intent, callback)
                else -> false
            }.also {
                Log.d(TAG, sessionManager.toString())
            }
        } else {
            false
        }
    }
    ...
}

Java

private final class SampleRouteController extends
        MediaRouteProvider.RouteController {
    ...

    @Override
    public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {

        String action = intent.getAction();

        if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
            boolean success = false;
            if (action.equals(MediaControlIntent.ACTION_PLAY)) {
                success = handlePlay(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
                success = handleEnqueue(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
                success = handleRemove(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
                success = handleSeek(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
                success = handleGetStatus(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
                success = handlePause(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
                success = handleResume(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
                success = handleStop(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
                success = handleStartSession(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
                success = handleGetSessionStatus(intent, callback);
            } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
                success = handleEndSession(intent, callback);
            }

            Log.d(TAG, sessionManager.toString());
            return success;
        }
        return false;
    }
    ...
}

請務必瞭解 MediaRouteProvider.RouteController 類別的用途是做為包裝函式 將 API 新增至媒體播放設備此類別中方法的實作方式為 完全依賴接收裝置提供的程式輔助介面。

程式碼範例

MediaRouter 範例顯示如何建立自訂媒體路線供應商。