使用 MediaPlayer 和數位版權管理 (DRM)

從 Android 8.0 (API 級別 26) 開始,MediaPlayer 包含支援播放 DRM 保護內容的 API。MediaPlayer DRM API 與 MediaDrm 提供的低階 API 類似,但運作層級較高,不會公開基礎擷取器、DRM 和加密物件。

雖然 MediaPlayer DRM API 並未提供 MediaDrm 的完整功能,但支援最常見的用途。目前的實作項目可處理下列內容類型:

  • 受 Widevine 保護的本機媒體檔案
  • 受 Widevine 保護的遠端或串流媒體檔案

下列程式碼片段示範如何在同步實作中,使用新的 DRM MediaPlayer 方法。

如要管理 DRM 控制的媒體,您必須在 MediaPlayer 呼叫的正常流程中加入新方法,如下例所示:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

首先,請照常初始化 MediaPlayer 物件,並使用 setDataSource() 設定來源。接著,如要使用 DRM,請按照下列步驟操作:

  1. 如要讓應用程式執行自訂設定,請定義 OnDrmConfigHelper 介面,並使用 setOnDrmConfigHelper() 將其附加至播放器。
  2. 呼叫 prepare()
  3. 呼叫 getDrmInfo()。如果來源含有 DRM 內容,這個方法會傳回非空值的 MediaPlayer.DrmInfo 值。

如果 MediaPlayer.DrmInfo 存在:

  1. 查看可用 UUID 的對應表,然後選擇一個。
  2. 呼叫 prepareDrm(),準備目前來源的 DRM 設定。
    • 如果您建立並註冊 OnDrmConfigHelper 回呼,系統會在 prepareDrm() 執行時呼叫該回呼。這樣一來,您就能在開啟 DRM 工作階段前,自訂 DRM 屬性。回呼會在呼叫 prepareDrm() 的執行緒中同步呼叫。如要存取 DRM 屬性,請呼叫 getDrmPropertyString()setDrmPropertyString()。避免執行耗時的作業。
    • 如果裝置尚未佈建,prepareDrm() 也會存取佈建伺服器來佈建裝置。視網路連線而定,這項作業可能需要一段時間才能完成。
  3. 如要取得不透明金鑰要求位元組陣列,並傳送至授權伺服器,請呼叫 getKeyRequest()
  4. 如要將授權伺服器傳回的金鑰回應告知 DRM 引擎,請呼叫 provideKeyResponse()。結果取決於金鑰要求類型:
    • 如果回應是針對離線金鑰要求,結果會是金鑰集 ID。您可以使用這個金鑰集 ID 和 restoreKeys(),將金鑰還原至新工作階段。
    • 如果是串流或發行要求的回應,結果會是空值。

以非同步方式準備 DRM

根據預設,prepareDrm() 會同步執行,並封鎖直到準備完成為止。不過,在新裝置上首次準備 DRM 時,可能也需要佈建,這項作業由 prepareDrm() 內部處理,且由於涉及網路作業,可能需要一段時間才能完成。如要避免 prepareDrm() 發生封鎖,請定義並設定 MediaPlayer.OnDrmPreparedListener

設定 OnDrmPreparedListenerprepareDrm() 會在背景執行佈建 (如有需要) 和準備作業。當佈建和準備完成時,系統會呼叫接聽程式。請勿對呼叫順序或執行監聽器的執行緒做出任何假設 (除非您使用處理常式執行緒註冊監聽器)。系統可以在 prepareDrm() 傳回之前或之後呼叫監聽器。

以非同步方式設定 DRM

您可以建立及註冊 MediaPlayer.OnDrmInfoListener,以非同步方式初始化 DRM,準備 DRM 並啟動播放器 MediaPlayer.OnDrmPreparedListener這些參數會與 prepareAsync() 搭配運作,如以下範例所示:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

處理加密媒體

從 Android 8.0 (API 級別 26) 開始,MediaPlayer 也可以解密通用加密配置 (CENC) 和 HLS 樣本層級加密媒體 (METHOD=SAMPLE-AES),適用於基本串流類型 H.264 和 AAC。先前支援全區段加密媒體 (METHOD=AES-128)。

瞭解詳情

建議您使用 Jetpack Media3 在應用程式中播放媒體。進一步瞭解

這些頁面涵蓋音訊和影片的錄製、儲存及播放相關主題: