从 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,请执行以下步骤:
- 如果您希望应用执行自定义配置,请定义
OnDrmConfigHelper
接口,并使用setOnDrmConfigHelper()
将其附加到播放器。 - 调用
prepare()
。 - 调用
getDrmInfo()
。如果来源具有 DRM 内容,则该方法会返回一个非 nullMediaPlayer.DrmInfo
值。
如果 MediaPlayer.DrmInfo
存在:
- 检查可用 UUID 的映射,然后选择一个。
- 通过调用
prepareDrm()
为当前来源准备 DRM 配置。- 如果您创建并注册了
OnDrmConfigHelper
回调,则系统会在执行prepareDrm()
时调用该回调。这样一来,您就能够在打开 DRM 会话之前执行 DRM 属性的自定义配置。该回调会在调用prepareDrm()
的线程中同步调用。如需访问 DRM 属性,请调用getDrmPropertyString()
和setDrmPropertyString()
。避免执行冗长的操作。 - 如果尚未配置设备,
prepareDrm()
还会访问配置服务器来配置该设备。所需的时间因网络连接而有所不同。
- 如果您创建并注册了
- 如需获取不透明的密钥请求字节数组以发送到许可服务器,请调用
getKeyRequest()
。 - 如需向 DRM 引擎告知从许可服务器接收到的密钥响应,请调用
provideKeyResponse()
。结果取决于密钥请求的类型:- 如果响应针对的是离线密钥请求,则结果为密钥组标识符。您可以将此密钥组标识符与
restoreKeys()
结合使用,以将这些密钥恢复到新的会话中。 - 如果响应针对的是流式传输或发布请求,则结果为 null。
- 如果响应针对的是离线密钥请求,则结果为密钥组标识符。您可以将此密钥组标识符与
异步准备 DRM
默认情况下,prepareDrm()
会同步运行,阻塞会持续到准备工作完成。不过,在新设备上进行的首次 DRM 准备可能还需要进行配置,该问题由 prepareDrm()
在内部进行处理,并且由于涉及网络操作,可能需要一些时间才能完成。您可以通过定义和设置 MediaPlayer.OnDrmPreparedListener
来避免阻塞 prepareDrm()
。
设置 OnDrmPreparedListener
。prepareDrm()
会在后台执行配置(如果需要)和准备工作。配置和准备工作完成后,系统会调用监听器。请勿对调用顺序或运行监听器的线程做任何假设(除非您将监听器注册到处理程序线程)。系统可以在 prepareDrm()
返回前后调用该监听器。
异步设置 DRM
您可以创建和注册用于进行 DRM 准备的 MediaPlayer.OnDrmInfoListener
以及用于启动播放器的 MediaPlayer.OnDrmPreparedListener
,从而异步初始化 DRM。它们能够与 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
还可以为基本的流类型 H.264 和 AAC 解密通用加密方案 (CENC) 和 HLS 样本级加密媒体 (METHOD=SAMPLE-AES)。之前支持全分段加密媒体 (METHOD=AES-128)。
了解详情
Jetpack Media3 是应用中播放媒体的推荐解决方案。了解详情。
以下页面介绍了有关录制、存储以及播放音频和视频的主题: