从 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 是在应用中播放媒体的推荐解决方案。详细了解 该解决方案。
以下页面介绍了与录制、存储和播放音频和视频相关的主题: