In Android O, MediaPlayer includes new methods implementing these new features:
- Fine-grained control when seeking to a frame
- The ability to playback DRM-protected material
MediaPlayer also now supports sample-level encryption.
Seek modes
A new, overloaded version of the
seekTo() method includes a
second argument that specifies a seek mode:
SEEK_PREVIOUS_SYNCmoves the media position to a sync (or key) frame associated with a data source that is located right before or at the given time.SEEK_NEXT_SYNCmoves the media position to a sync (or key) frame associated with a data source that is located right after or at the given time.SEEK_CLOSEST_SYNCmoves the media position to a sync (or key) frame associated with a data source that is located closest to or at the given time.SEEK_CLOSESTmoves the media position to a frame (not necessarily a sync or key frame) associated with a data source that is located closest to or at the given time.
When seeking continuously, apps should use any of the "SEEK_*_SYNC" modes
rather than SEEK_CLOSEST, which runs
relatively slower but can be more precise.
DRM support
MediaPlayer includes new APIs that support the playback of DRM-protected
material. They are similar to the low-level API provided by
MediaDrm, but they operate at a higher level and do not
expose the underlying Extractor, Drm, and Crypto objects.
Although the MediaPlayer DRM API does not provide the full functionality of
MediaDrm, it supports the most common use cases. The
current implementation can handle these content types:
- Widevine protected local media files
- Widevine protected remote/streaming media files
The following code snippet demonstrates how to use the new DRM MediaPlayer methods in a simple synchronous implementation.
To manage DRM-controlled media, you need to include the new methods alongside the usual flow of MediaPlayer calls, as shown below:
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();
Start by initializing the MediaPlayer object and setting
its source using setDataSource(),
as usual. Then, to use DRM, perform these steps:
- If you want your app to perform custom configuration, define an
MediaPlayer.OnDrmConfigHelperand attach it to the player withsetOnDrmConfigHelper(). - Call
prepare(), as usual. - Call
getDrmInfo(). If the source has DRM content, the method returns a non-nullMediaPlayer.DrmInfo.
If MediaPlayer.DrmInfo exists:
- Examine the map of available UUIDs and choose one.
- Prepare the Drm configuration for the current source by calling
prepareDrm(). - If you created and registered an OnDrmConfigHelper, it is called
while
prepareDrm()is executing. This callback lets you perform custom configuration of the DRM properties before opening the DRM session. The callback is called synchronously in the thread that calledprepareDrm(). To access the DRM properties, callgetDrmPropertyString()andsetDrmPropertyString(). Avoid performing lengthy operations. - If the device has not yet been provisioned,
prepareDrm()also accesses the provisioning server to provision the device. This can take a variable amount of time, depending on the network connectivity. - To get an opaque key request byte array to send to a license server, call
getKeyRequest(). For a full explanation of the method's arguments, see the refdocs. arguments. - To inform the DRM engine about the key response received from the license server, call
provideKeyResponse(). The result returned depends on the type of key request:- When the response is for an offline key request, a key-set identifier is returned. You can use
this key-set identifier together with
restoreKeys()to restore the keys to a new session. - When the response is for a streaming or release request, null is returned.
- When the response is for an offline key request, a key-set identifier is returned. You can use
this key-set identifier together with
Running prepareDrm() asynchronously
By default, prepareDrm()
runs synchronously, blocking until preparation is finished. However, the very
first DRM preparation on a new device may also require provisioning, which is
handled internally by
prepareDrm(), and
may take some time to finish due to the network operation involved. You can
avoid blocking on
prepareDrm() by
defining and setting a MediaPlayer.OnDrmPreparedListener.
When you set an MediaPlayer.OnDrmPreparedListener,
prepareDrm()
performs the provisioning (if needed) and preparation in the background. When
provisioning and preparation have finished, the listener is called. You should
not make any assumption about the calling sequence or the thread in which the
listener will run (unless the listener is registered with a handler thread).
The listener can be called before or after
prepareDrm()
returns.
Setting up DRM asynchronously
You can initialize the DRM asynchronously by creating and registering the
MediaPlayer.OnDrmInfoListener for DRM preparation and the
MediaPlayer.OnDrmPreparedListener to start the player.
They work in conjunction with
prepareAsync(), as shown below:
setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ....
// If the data source content is protected you'll receive the onDrmInfo() callback.
onDrmInfo() {
prepareDrm();
getKeyRequest();
provideKeyResponse();
}
// When prepareAsync() finishes, you'll receive the onPrepared() callback.
// If there is a DRM, onDrmInfo() will set it up before executing this callback, so you can start the player.
onPrepared() {
start();
}
HLS sample-level encyption
MediaPlayer now supports sample-level encryption (METHOD=SAMPLE-AES) for the elementary stream types H.264, AAC, and AC-3. Full-segment encryption (METHOD=AES-128) was previously available.