Merge "MediaPlayer/ModularDrm API review" into oc-dev

This commit is contained in:
Hassan Shojania
2017-04-18 18:41:23 +00:00
committed by Android (Google) Code Review
4 changed files with 258 additions and 164 deletions

View File

@@ -22774,7 +22774,7 @@ package android.media {
method public android.media.MediaPlayer.DrmInfo getDrmInfo();
method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -22788,7 +22788,7 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -22815,7 +22815,7 @@ package android.media {
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22856,6 +22856,10 @@ package android.media {
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0
field public static final int SEEK_CLOSEST = 3; // 0x3
field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_NEXT_SYNC = 1; // 0x1
@@ -22865,7 +22869,6 @@ package android.media {
}
public static final class MediaPlayer.DrmInfo {
method public java.lang.String[] getMimes();
method public java.util.Map<java.util.UUID, byte[]> getPssh();
method public java.util.UUID[] getSupportedSchemes();
}
@@ -22897,7 +22900,7 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
public static abstract interface MediaPlayer.OnDrmConfigListener {
public static abstract interface MediaPlayer.OnDrmConfigHelper {
method public abstract void onDrmConfig(android.media.MediaPlayer);
}
@@ -22906,7 +22909,7 @@ package android.media {
}
public static abstract interface MediaPlayer.OnDrmPreparedListener {
method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
method public abstract void onDrmPrepared(android.media.MediaPlayer, int);
}
public static abstract interface MediaPlayer.OnErrorListener {
@@ -22937,8 +22940,12 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String);
}
public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String);
}
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {

View File

@@ -24610,7 +24610,7 @@ package android.media {
method public android.media.MediaPlayer.DrmInfo getDrmInfo();
method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -24624,7 +24624,7 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -24651,7 +24651,7 @@ package android.media {
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -24692,6 +24692,10 @@ package android.media {
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0
field public static final int SEEK_CLOSEST = 3; // 0x3
field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_NEXT_SYNC = 1; // 0x1
@@ -24701,7 +24705,6 @@ package android.media {
}
public static final class MediaPlayer.DrmInfo {
method public java.lang.String[] getMimes();
method public java.util.Map<java.util.UUID, byte[]> getPssh();
method public java.util.UUID[] getSupportedSchemes();
}
@@ -24733,7 +24736,7 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
public static abstract interface MediaPlayer.OnDrmConfigListener {
public static abstract interface MediaPlayer.OnDrmConfigHelper {
method public abstract void onDrmConfig(android.media.MediaPlayer);
}
@@ -24742,7 +24745,7 @@ package android.media {
}
public static abstract interface MediaPlayer.OnDrmPreparedListener {
method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
method public abstract void onDrmPrepared(android.media.MediaPlayer, int);
}
public static abstract interface MediaPlayer.OnErrorListener {
@@ -24773,8 +24776,12 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String);
}
public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String);
}
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {

View File

@@ -22881,7 +22881,7 @@ package android.media {
method public android.media.MediaPlayer.DrmInfo getDrmInfo();
method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
method public int getDuration();
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -22895,7 +22895,7 @@ package android.media {
method public void pause() throws java.lang.IllegalStateException;
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -22922,7 +22922,7 @@ package android.media {
method public void setNextMediaPlayer(android.media.MediaPlayer);
method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22963,6 +22963,10 @@ package android.media {
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0
field public static final int SEEK_CLOSEST = 3; // 0x3
field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_NEXT_SYNC = 1; // 0x1
@@ -22972,7 +22976,6 @@ package android.media {
}
public static final class MediaPlayer.DrmInfo {
method public java.lang.String[] getMimes();
method public java.util.Map<java.util.UUID, byte[]> getPssh();
method public java.util.UUID[] getSupportedSchemes();
}
@@ -23004,7 +23007,7 @@ package android.media {
method public abstract void onCompletion(android.media.MediaPlayer);
}
public static abstract interface MediaPlayer.OnDrmConfigListener {
public static abstract interface MediaPlayer.OnDrmConfigHelper {
method public abstract void onDrmConfig(android.media.MediaPlayer);
}
@@ -23013,7 +23016,7 @@ package android.media {
}
public static abstract interface MediaPlayer.OnDrmPreparedListener {
method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean);
method public abstract void onDrmPrepared(android.media.MediaPlayer, int);
}
public static abstract interface MediaPlayer.OnErrorListener {
@@ -23044,8 +23047,12 @@ package android.media {
method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
}
public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningErrorException(java.lang.String);
public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String);
}
public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException {
ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String);
}
public static class MediaPlayer.TrackInfo implements android.os.Parcelable {

View File

@@ -1007,13 +1007,14 @@ public class MediaPlayer extends PlayerBase
* @param context the Context to use when resolving the Uri
* @param uri the Content URI of the data you want to play
* @param headers the headers to be sent together with the request for the data
* Note that the cross domain redirection is allowed by default, but that can be
* changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
* to disallow or allow cross domain redirection.
* The headers must not include cookies. Instead, use the cookies param.
* @param cookies the cookies to be sent together with the request
* @throws IllegalStateException if it is called in an invalid state
*
* <p><strong>Note</strong> that the cross domain redirection is allowed by default,
* but that can be changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
* disallow or allow cross domain redirection.
*/
public void setDataSource(@NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
@@ -1056,11 +1057,12 @@ public class MediaPlayer extends PlayerBase
* @param context the Context to use when resolving the Uri
* @param uri the Content URI of the data you want to play
* @param headers the headers to be sent together with the request for the data
* Note that the cross domain redirection is allowed by default, but that can be
* changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
* to disallow or allow cross domain redirection.
* @throws IllegalStateException if it is called in an invalid state
*
* <p><strong>Note</strong> that the cross domain redirection is allowed by default,
* but that can be changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
* disallow or allow cross domain redirection.
*/
public void setDataSource(@NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers)
@@ -1981,7 +1983,7 @@ public class MediaPlayer extends PlayerBase
mOnSubtitleDataListener = null;
// Modular DRM clean up
mOnDrmConfigListener = null;
mOnDrmConfigHelper = null;
mOnDrmInfoHandlerDelegate = null;
mOnDrmPreparedHandlerDelegate = null;
resetDrmState();
@@ -3905,11 +3907,11 @@ public class MediaPlayer extends PlayerBase
* 'securityLevel', which has to be set after DRM scheme creation but
* before the DRM session is opened.
*
* The only allowed DRM calls in this listener are getDrmPropertyString
* and setDrmPropertyString.
* The only allowed DRM calls in this listener are {@code getDrmPropertyString}
* and {@code setDrmPropertyString}.
*
*/
public interface OnDrmConfigListener
public interface OnDrmConfigHelper
{
/**
* Called to give the app the opportunity to configure DRM before the session is created
@@ -3922,19 +3924,19 @@ public class MediaPlayer extends PlayerBase
/**
* Register a callback to be invoked for configuration of the DRM object before
* the session is created.
* The callback will be invoked synchronously half-way into the execution
* The callback will be invoked synchronously during the execution
* of {@link #prepareDrm(UUID uuid)}.
*
* @param listener the callback that will be run
*/
public void setOnDrmConfigListener(OnDrmConfigListener listener)
public void setOnDrmConfigHelper(OnDrmConfigHelper listener)
{
synchronized (mDrmLock) {
mOnDrmConfigListener = listener;
mOnDrmConfigHelper = listener;
} // synchronized
}
private OnDrmConfigListener mOnDrmConfigListener;
private OnDrmConfigHelper mOnDrmConfigHelper;
/**
* Interface definition of a callback to be invoked when the
@@ -3946,7 +3948,7 @@ public class MediaPlayer extends PlayerBase
* Called to indicate DRM info is available
*
* @param mp the {@code MediaPlayer} associated with this callback
* @param drmInfo DRM info of the source including PSSH, mimes, and subset
* @param drmInfo DRM info of the source including PSSH, and subset
* of crypto schemes supported by this device
*/
public void onDrmInfo(MediaPlayer mp, DrmInfo drmInfo);
@@ -3982,6 +3984,41 @@ public class MediaPlayer extends PlayerBase
private OnDrmInfoHandlerDelegate mOnDrmInfoHandlerDelegate;
/**
* The status codes for {@link OnDrmPreparedListener#onDrmPrepared} listener.
* <p>
*
* DRM preparation has succeeded.
*/
public static final int PREPARE_DRM_STATUS_SUCCESS = 0;
/**
* The device required DRM provisioning but couldn't reach the provisioning server.
*/
public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1;
/**
* The device required DRM provisioning but the provisioning server denied the request.
*/
public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2;
/**
* The DRM preparation has failed .
*/
public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
/** @hide */
@IntDef({
PREPARE_DRM_STATUS_SUCCESS,
PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
PREPARE_DRM_STATUS_PREPARATION_ERROR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PrepareDrmStatusCode {}
/**
* Interface definition of a callback to notify the app when the
* DRM is ready for key request/response
@@ -3992,9 +4029,13 @@ public class MediaPlayer extends PlayerBase
* Called to notify the app that prepareDrm is finished and ready for key request/response
*
* @param mp the {@code MediaPlayer} associated with this callback
* @param success the result of DRM preparation
* @param status the result of DRM preparation which can be
* {@link #PREPARE_DRM_STATUS_SUCCESS},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or
* {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}.
*/
public void onDrmPrepared(MediaPlayer mp, boolean success);
public void onDrmPrepared(MediaPlayer mp, @PrepareDrmStatusCode int status);
}
/**
@@ -4038,30 +4079,28 @@ public class MediaPlayer extends PlayerBase
mOnDrmInfoListener = listener;
// find the looper for our new event handler
Looper looper = null;
if (handler != null) {
looper = handler.getLooper();
}
// construct the event handler with this looper
if (looper != null) {
// implement the event handler delegate
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
DrmInfo drmInfo = (DrmInfo)msg.obj;
mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo);
}
};
mHandler = handler;
} else {
// handler == null
// Will let OnDrmInfoListener be called in mEventHandler similar to other
// legacy notifications. This is because MEDIA_DRM_INFO's notification has to be
// sent before MEDIA_PREPARED's (i.e., in the same order they are issued by
// mediaserver). As a result, the callback has to be called directly by
// EventHandler.handleMessage similar to onPrepared.
}
}
void notifyClient(DrmInfo drmInfo) {
if ( mHandler != null ) {
Message msg = new Message(); // no message type needed
msg.obj = drmInfo;
mHandler.sendMessage(msg);
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo);
}
});
}
else { // no handler: direct call
else { // no handler: direct call by mEventHandler
mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo);
}
}
@@ -4078,31 +4117,26 @@ public class MediaPlayer extends PlayerBase
mOnDrmPreparedListener = listener;
// find the looper for our new event handler
Looper looper = null;
if (handler != null) {
looper = handler.getLooper();
}
// construct the event handler with this looper
if (looper != null) {
// implement the event handler delegate
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
boolean success = (msg.arg1 == 0) ? false : true;
mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success);
}
};
mHandler = handler;
} else if (mEventHandler != null) {
// Otherwise, use mEventHandler
mHandler = mEventHandler;
} else {
Log.e(TAG, "OnDrmPreparedHandlerDelegate: Unexpected null mEventHandler");
}
}
void notifyClient(boolean success) {
if ( mHandler != null ) {
Message msg = new Message(); // no message type needed
msg.arg1 = success ? 1 : 0;
mHandler.sendMessage(msg);
}
else { // no handler: direct call
mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success);
void notifyClient(int status) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, status);
}
});
} else {
Log.e(TAG, "OnDrmPreparedHandlerDelegate:notifyClient: Unexpected null mHandler");
}
}
}
@@ -4137,7 +4171,7 @@ public class MediaPlayer extends PlayerBase
/**
* Prepares the DRM for the current source
* <p>
* If {@code OnDrmConfigListener} is registered, it will be called half-way into
* If {@code OnDrmConfigHelper} is registered, it will be called during
* preparation to allow configuration of the DRM properties before opening the
* DRM session. Note that the callback is called synchronously in the thread that called
* {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
@@ -4148,9 +4182,9 @@ public class MediaPlayer extends PlayerBase
* complete depending on the network connectivity.
* If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
* mode by launching the provisioning in the background and returning. The listener
* will be called when provisioning and preperation has finished. If a
* will be called when provisioning and preparation has finished. If a
* {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
* and preperation has finished, i.e., runs in blocking mode.
* and preparation has finished, i.e., runs in blocking mode.
* <p>
* If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
* session being ready. The application should not make any assumption about its call
@@ -4158,18 +4192,23 @@ public class MediaPlayer extends PlayerBase
* execute the listener (unless the listener is registered with a handler thread).
* <p>
*
* @param uuid The UUID of the crypto scheme.
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
*
* @throws IllegalStateException if called before prepare(), or there exists a Drm already
* @throws UnsupportedSchemeException if the crypto scheme is not supported
* @throws ResourceBusyException if required DRM resources are in use
* @throws ProvisioningErrorException if provisioning is required but an attempt failed
* @throws IllegalStateException if called before prepare(), or the DRM was
* prepared already
* @throws UnsupportedSchemeException if the crypto scheme is not supported
* @throws ResourceBusyException if required DRM resources are in use
* @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a
* network error
* @throws ProvisioningServerErrorException if provisioning is required but failed due to
* the request denied by the provisioning server
*/
public void prepareDrm(@NonNull UUID uuid)
throws UnsupportedSchemeException,
ResourceBusyException, ProvisioningErrorException
throws UnsupportedSchemeException, ResourceBusyException,
ProvisioningNetworkErrorException, ProvisioningServerErrorException
{
Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigListener: " + mOnDrmConfigListener);
Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper);
boolean allDoneWithoutProvisioning = false;
// get a snapshot as we'll use them outside the lock
@@ -4177,7 +4216,7 @@ public class MediaPlayer extends PlayerBase
synchronized (mDrmLock) {
// only allowing if tied to a protected source; might releax for releasing offline keys
// only allowing if tied to a protected source; might relax for releasing offline keys
if (mDrmInfo == null) {
final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " +
"DRM info be retrieved before this call.";
@@ -4226,8 +4265,8 @@ public class MediaPlayer extends PlayerBase
// call the callback outside the lock
if (mOnDrmConfigListener != null) {
mOnDrmConfigListener.onDrmConfig(this);
if (mOnDrmConfigHelper != null) {
mOnDrmConfigHelper.onDrmConfig(this);
}
synchronized (mDrmLock) {
@@ -4251,15 +4290,33 @@ public class MediaPlayer extends PlayerBase
Log.w(TAG, "prepareDrm: NotProvisionedException");
// handle provisioning internally; it'll reset mPrepareDrmInProgress
boolean result = HandleProvisioninig(uuid);
int result = HandleProvisioninig(uuid);
// if blocking mode, we're already done;
// if non-blocking mode, we attempted to launch background provisioning
if (result == false) {
final String msg = "prepareDrm: Provisioning was required but failed.";
Log.e(TAG, msg);
if (result != PREPARE_DRM_STATUS_SUCCESS) {
earlyExit = true;
throw new ProvisioningErrorException(msg);
String msg;
switch (result) {
case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
msg = "prepareDrm: Provisioning was required but failed " +
"due to a network error.";
Log.e(TAG, msg);
throw new ProvisioningNetworkErrorException(msg);
case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
msg = "prepareDrm: Provisioning was required but the request " +
"was denied by the server.";
Log.e(TAG, msg);
throw new ProvisioningServerErrorException(msg);
case PREPARE_DRM_STATUS_PREPARATION_ERROR:
default: // default for safeguard
msg = "prepareDrm: Post-provisioning preparation failed.";
Log.e(TAG, msg);
throw new IllegalStateException(msg);
}
}
// nothing else to do;
// if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
@@ -4281,7 +4338,7 @@ public class MediaPlayer extends PlayerBase
// if finished successfully without provisioning, call the callback outside the lock
if (allDoneWithoutProvisioning) {
if (onDrmPreparedHandlerDelegate != null)
onDrmPreparedHandlerDelegate.notifyClient(true /*success*/);
onDrmPreparedHandlerDelegate.notifyClient(PREPARE_DRM_STATUS_SUCCESS);
}
}
@@ -4291,6 +4348,10 @@ public class MediaPlayer extends PlayerBase
/**
* Releases the DRM session
* <p>
* The player has to have an active DRM session and be in stopped, or prepared
* state before this call is made.
* A {@code reset()} call will release the DRM session implicitly.
*
* @throws NoDrmSchemeException if there is no active DRM session to release
*/
@@ -4307,7 +4368,7 @@ public class MediaPlayer extends PlayerBase
try {
// we don't have the player's state in this layer. The below call raises
// exception if we're in a non-stopped/idle state.
// exception if we're in a non-stopped/prepared state.
// for cleaning native/mediaserver crypto object
_releaseDrm();
@@ -4316,9 +4377,11 @@ public class MediaPlayer extends PlayerBase
cleanDrmObj();
mActiveDrmScheme = false;
} catch (Exception e) {
} catch (IllegalStateException e) {
Log.w(TAG, "releaseDrm: Exception ", e);
throw e;
throw new IllegalStateException("releaseDrm: The player is not in a valid state.");
} catch (Exception e) {
Log.e(TAG, "releaseDrm: Exception ", e);
}
} // synchronized
}
@@ -4337,21 +4400,23 @@ public class MediaPlayer extends PlayerBase
* it should deliver to the response to the DRM engine plugin using the method
* {@link #provideKeyResponse}.
*
* @param scope may be a container-specific initialization data or a keySetId,
* depending on the specified keyType.
* When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set to
* the container-specific initialization data. Its meaning is interpreted based on the
* mime type provided in the mimeType parameter. It could contain, for example,
* the content ID, key ID or other data obtained from the content metadata that is
* required in generating the key request.
* When the keyType is KEY_TYPE_RELEASE, scope should be set to the keySetId of
* the keys being released.
* @param keySetId is the key-set identifier of the offline keys being released when keyType is
* {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
* keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
*
* @param initData is the container-specific initialization data when the keyType is
* {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
* interpreted based on the mime type provided in the mimeType parameter. It could
* contain, for example, the content ID, key ID or other data obtained from the content
* metadata that is required in generating the key request.
* When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
*
* @param mimeType identifies the mime type of the content
*
* @param keyType specifes the type of the request. The request may be to acquire
* keys for streaming or offline content, or to release previously acquired
* keys, which are identified by a keySetId.
* @param keyType specifies the type of the request. The request may be to acquire
* keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
* {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
* keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
*
* @param optionalParameters are included in the key request message to
* allow a client application to provide additional message parameters to the server.
@@ -4360,12 +4425,13 @@ public class MediaPlayer extends PlayerBase
* @throws NoDrmSchemeException if there is no active DRM session
*/
@NonNull
public MediaDrm.KeyRequest getKeyRequest(@NonNull byte[] scope, @Nullable String mimeType,
@MediaDrm.KeyType int keyType, @Nullable Map<String, String> optionalParameters)
public MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
@Nullable String mimeType, @MediaDrm.KeyType int keyType,
@Nullable Map<String, String> optionalParameters)
throws NoDrmSchemeException
{
Log.v(TAG, "getKeyRequest: " +
" scope: " + scope + " mimeType: " + mimeType +
" keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
" keyType: " + keyType + " optionalParameters: " + optionalParameters);
synchronized (mDrmLock) {
@@ -4375,20 +4441,16 @@ public class MediaPlayer extends PlayerBase
}
try {
byte[] scopeOut = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
scope; // keySetId for KEY_TYPE_RELEASE
byte[] initData = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
scope : // initData for KEY_TYPE_STREAMING/OFFLINE
null; // not used for KEY_TYPE_RELEASE
byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
keySetId; // keySetId for KEY_TYPE_RELEASE
HashMap<String, String> hmapOptionalParameters =
(optionalParameters != null) ?
new HashMap<String, String>(optionalParameters) :
null;
MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scopeOut, initData, mimeType,
MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType,
keyType, hmapOptionalParameters);
Log.v(TAG, "getKeyRequest: --> request: " + request);
@@ -4499,8 +4561,8 @@ public class MediaPlayer extends PlayerBase
* @param propertyName the property name
*
* Standard fields names are:
* {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION},
* {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS}
* {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*/
@NonNull
public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
@@ -4537,8 +4599,8 @@ public class MediaPlayer extends PlayerBase
* @param value the property value
*
* Standard fields names are:
* {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION},
* {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS}
* {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*/
public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
@NonNull String value)
@@ -4565,8 +4627,6 @@ public class MediaPlayer extends PlayerBase
public static final class DrmInfo {
private Map<UUID, byte[]> mapPssh;
private UUID[] supportedSchemes;
// TODO: Won't need this in final release. Only keeping it for the existing test app.
private String[] mimes;
public Map<UUID, byte[]> getPssh() {
return mapPssh;
@@ -4574,15 +4634,10 @@ public class MediaPlayer extends PlayerBase
public UUID[] getSupportedSchemes() {
return supportedSchemes;
}
// TODO: Won't need this in final release. Only keeping it for the existing test app.
public String[] getMimes() {
return mimes;
}
private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes, String[] Mimes) {
private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) {
mapPssh = Pssh;
supportedSchemes = SupportedSchemes;
mimes = Mimes;
}
private DrmInfo(Parcel parcel) {
@@ -4608,18 +4663,12 @@ public class MediaPlayer extends PlayerBase
supportedSchemes[i]);
}
// TODO: Won't need this in final release. Only keeping it for the test app.
mimes = parcel.readStringArray();
int mimeCount = mimes.length;
Log.v(TAG, "DrmInfo() mime: " + Arrays.toString(mimes));
Log.v(TAG, "DrmInfo() Parcel psshsize: " + psshsize +
" supportedDRMsCount: " + supportedDRMsCount +
" mimeCount: " + mimeCount);
" supportedDRMsCount: " + supportedDRMsCount);
}
private DrmInfo makeCopy() {
return new DrmInfo(this.mapPssh, this.supportedSchemes, this.mimes);
return new DrmInfo(this.mapPssh, this.supportedSchemes);
}
private String arrToHex(byte[] bytes) {
@@ -4714,11 +4763,22 @@ public class MediaPlayer extends PlayerBase
/**
* Thrown when the device requires DRM provisioning but the provisioning attempt has
* failed (for example: network timeout, provisioning server error).
* failed due to a network error (Internet reachability, timeout, etc.).
* Extends MediaDrm.MediaDrmException
*/
public static final class ProvisioningErrorException extends MediaDrmException {
public ProvisioningErrorException(String detailMessage) {
public static final class ProvisioningNetworkErrorException extends MediaDrmException {
public ProvisioningNetworkErrorException(String detailMessage) {
super(detailMessage);
}
}
/**
* Thrown when the device requires DRM provisioning but the provisioning attempt has
* failed due to the provisioning server denying the request.
* Extends MediaDrm.MediaDrmException
*/
public static final class ProvisioningServerErrorException extends MediaDrmException {
public ProvisioningServerErrorException(String detailMessage) {
super(detailMessage);
}
}
@@ -4770,14 +4830,13 @@ public class MediaPlayer extends PlayerBase
private UUID uuid;
private String urlStr;
private byte[] response;
private Object drmLock;
private OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate;
private MediaPlayer mediaPlayer;
private boolean succeeded;
private int status;
private boolean finished;
public boolean succeeded() {
return succeeded;
public int status() {
return status;
}
public ProvisioningThread initialize(MediaDrm.ProvisionRequest request,
@@ -4790,12 +4849,15 @@ public class MediaPlayer extends PlayerBase
urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
this.uuid = uuid;
status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr);
return this;
}
public void run() {
byte[] response = null;
boolean provisioningSucceeded = false;
try {
URL url = new URL(urlStr);
@@ -4813,11 +4875,13 @@ public class MediaPlayer extends PlayerBase
Log.v(TAG, "HandleProvisioninig: Thread run: response " +
response.length + " " + response);
} catch (Exception e) {
status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url);
} finally {
connection.disconnect();
}
} catch (Exception e) {
status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e);
}
@@ -4828,12 +4892,15 @@ public class MediaPlayer extends PlayerBase
"provideProvisionResponse SUCCEEDED!");
provisioningSucceeded = true;
} catch (Exception e) {
} catch (Exception e) {
status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
Log.w(TAG, "HandleProvisioninig: Thread run: " +
"provideProvisionResponse " + e);
}
}
boolean succeeded = false;
// non-blocking mode needs the lock
if (onDrmPreparedHandlerDelegate != null) {
@@ -4841,6 +4908,9 @@ public class MediaPlayer extends PlayerBase
// continuing with prepareDrm
if (provisioningSucceeded) {
succeeded = mediaPlayer.resumePrepareDrm(uuid);
status = (succeeded) ?
PREPARE_DRM_STATUS_SUCCESS :
PREPARE_DRM_STATUS_PREPARATION_ERROR;
}
mediaPlayer.mDrmProvisioningInProgress = false;
mediaPlayer.mPrepareDrmInProgress = false;
@@ -4850,12 +4920,15 @@ public class MediaPlayer extends PlayerBase
} // synchronized
// calling the callback outside the lock
onDrmPreparedHandlerDelegate.notifyClient(succeeded);
onDrmPreparedHandlerDelegate.notifyClient(status);
} else { // blocking mode already has the lock
// continuing with prepareDrm
if (provisioningSucceeded) {
succeeded = mediaPlayer.resumePrepareDrm(uuid);
status = (succeeded) ?
PREPARE_DRM_STATUS_SUCCESS :
PREPARE_DRM_STATUS_PREPARATION_ERROR;
}
mediaPlayer.mDrmProvisioningInProgress = false;
mediaPlayer.mPrepareDrmInProgress = false;
@@ -4869,19 +4942,19 @@ public class MediaPlayer extends PlayerBase
} // ProvisioningThread
private boolean HandleProvisioninig(UUID uuid)
private int HandleProvisioninig(UUID uuid)
{
// the lock is already held by the caller
if (mDrmProvisioningInProgress) {
Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
return false;
return PREPARE_DRM_STATUS_PREPARATION_ERROR;
}
MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
if (provReq == null) {
Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
return false;
return PREPARE_DRM_STATUS_PREPARATION_ERROR;
}
Log.v(TAG, "HandleProvisioninig provReq " +
@@ -4893,11 +4966,11 @@ public class MediaPlayer extends PlayerBase
mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
mDrmProvisioningThread.start();
boolean result = false;
int result;
// non-blocking
// non-blocking: this is not the final result
if (mOnDrmPreparedHandlerDelegate != null) {
result = true;
result = PREPARE_DRM_STATUS_SUCCESS;
} else {
// if blocking mode, wait till provisioning is done
try {
@@ -4905,7 +4978,7 @@ public class MediaPlayer extends PlayerBase
} catch (Exception e) {
Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e);
}
result = mDrmProvisioningThread.succeeded();
result = mDrmProvisioningThread.status();
// no longer need the thread
mDrmProvisioningThread = null;
}