diff options
-rw-r--r-- | api/current.txt | 23 | ||||
-rw-r--r-- | api/system-current.txt | 23 | ||||
-rw-r--r-- | api/test-current.txt | 23 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 353 |
4 files changed, 258 insertions, 164 deletions
diff --git a/api/current.txt b/api/current.txt index 5697b3970851..1098b781b356 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22775,7 +22775,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; @@ -22789,7 +22789,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; @@ -22816,7 +22816,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); @@ -22857,6 +22857,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 @@ -22866,7 +22870,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(); } @@ -22898,7 +22901,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); } @@ -22907,7 +22910,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 { @@ -22938,8 +22941,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 { diff --git a/api/system-current.txt b/api/system-current.txt index 8b2ac55b3374..5277ef083d4b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24608,7 +24608,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; @@ -24622,7 +24622,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; @@ -24649,7 +24649,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); @@ -24690,6 +24690,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 @@ -24699,7 +24703,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(); } @@ -24731,7 +24734,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); } @@ -24740,7 +24743,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 { @@ -24771,8 +24774,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 { diff --git a/api/test-current.txt b/api/test-current.txt index 86227a770648..0d3de3824492 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -22882,7 +22882,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; @@ -22896,7 +22896,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; @@ -22923,7 +22923,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); @@ -22964,6 +22964,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 @@ -22973,7 +22977,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(); } @@ -23005,7 +23008,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); } @@ -23014,7 +23017,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 { @@ -23045,8 +23048,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 { diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 9386246bd128..d5efc971d1fd 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -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; } |