From 1bb6c63e103115254b4372ae1e98c138a96f363a Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 23 Oct 2018 09:58:14 -0700 Subject: [PATCH] MediaPlayer2: make prepareDrm asynchronous only Test: MediaPlayer2DrmTest Bug: 112549021 Change-Id: I680f1d9e3d02635d1f90f73b4dc33359a8a4c7c7 --- media/java/android/media/MediaPlayer2.java | 113 +++--- .../java/android/media/MediaPlayer2Impl.java | 350 +++++++----------- 2 files changed, 184 insertions(+), 279 deletions(-) diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index e94413cd90fcc..54b5ab19b0186 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -1361,7 +1361,7 @@ public abstract class MediaPlayer2 implements AutoCloseable } /** - * Sets the callback to be invoked when the media source is ready for playback. + * Registers the callback to be invoked for various events covered by {@link EventCallback}. * * @param executor the executor through which the callback should be invoked * @param eventCallback the callback that will be run @@ -1378,7 +1378,6 @@ public abstract class MediaPlayer2 implements AutoCloseable // This is a synchronous call. public abstract void unregisterEventCallback(EventCallback eventCallback); - /* Do not change these values without updating their counterparts * in include/media/mediaplayer2.h! */ @@ -1387,7 +1386,8 @@ public abstract class MediaPlayer2 implements AutoCloseable */ public static final int MEDIA_ERROR_UNKNOWN = 1; - /** The video is streamed and its container is not valid for progressive + /** + * The video is streamed and its container is not valid for progressive * playback i.e the video's index (e.g moov atom) is not at the start of the * file. * @see EventCallback#onError @@ -1698,19 +1698,33 @@ public abstract class MediaPlayer2 implements AutoCloseable * @see EventCallback#onCallCompleted * @hide */ - public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 1001; + public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31; - /** The player just completed a call {@code setVideoScalingMode}. + /** The player just completed a call {@link #setVideoScalingMode}. * @see EventCallback#onCallCompleted * @hide */ - public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 1002; + public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 32; - /** The player just completed a call {@code notifyWhenCommandLabelReached}. + /** + * The start of the methods which have separate call complete callback. + * @hide + */ + public static final int SEPARATE_CALL_COMPLETED_CALLBACK_START = 1000; + + /** The player just completed a call {@link #notifyWhenCommandLabelReached}. * @see EventCallback#onCommandLabelReached * @hide */ - public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED = 1003; + public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED = + SEPARATE_CALL_COMPLETED_CALLBACK_START; + + /** The player just completed a call {@link #prepareDrm}. + * @see DrmEventCallback#onDrmPrepared + * @hide + */ + public static final int CALL_COMPLETED_PREPARE_DRM = + SEPARATE_CALL_COMPLETED_CALLBACK_START + 1; /** * @hide @@ -1740,7 +1754,8 @@ public abstract class MediaPlayer2 implements AutoCloseable CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, CALL_COMPLETED_SET_BUFFERING_PARAMS, CALL_COMPLETED_SET_VIDEO_SCALING_MODE, - CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED + CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, + CALL_COMPLETED_PREPARE_DRM, }) @Retention(RetentionPolicy.SOURCE) public @interface CallCompleted {} @@ -1864,20 +1879,22 @@ public abstract class MediaPlayer2 implements AutoCloseable } /** - * Sets the callback to be invoked when the media source is ready for playback. + * Registers the callback to be invoked for various DRM events. * * @param eventCallback the callback that will be run * @param executor the executor through which the callback should be invoked */ // This is a synchronous call. - public abstract void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor, + public abstract void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor, @NonNull DrmEventCallback eventCallback); /** - * Clears the {@link DrmEventCallback}. + * Unregisters the {@link DrmEventCallback}. + * + * @param eventCallback the callback to be unregistered */ // This is a synchronous call. - public abstract void clearDrmEventCallback(); + public abstract void unregisterDrmEventCallback(DrmEventCallback eventCallback); /** * The status codes for {@link DrmEventCallback#onDrmPrepared} listener. @@ -1902,6 +1919,15 @@ public abstract class MediaPlayer2 implements AutoCloseable */ public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; + /** + * The crypto scheme UUID is not supported by the device. + */ + public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4; + + /** + * The hardware resources are not available, due to being in use. + */ + public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5; /** @hide */ @IntDef(flag = false, prefix = "PREPARE_DRM_STATUS", value = { @@ -1909,6 +1935,8 @@ public abstract class MediaPlayer2 implements AutoCloseable PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR, PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR, PREPARE_DRM_STATUS_PREPARATION_ERROR, + PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME, + PREPARE_DRM_STATUS_RESOURCE_BUSY, }) @Retention(RetentionPolicy.SOURCE) public @interface PrepareDrmStatusCode {} @@ -1925,41 +1953,28 @@ public abstract class MediaPlayer2 implements AutoCloseable *

* If {@link 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 - * {@link #prepareDrm}. It should be used only for a series of {@code getDrmPropertyString} - * and {@code setDrmPropertyString} calls and refrain from any lengthy operation. + * DRM session. It should be used only for a series of {@link #getDrmPropertyString} + * and {@link #setDrmPropertyString} calls and refrain from any lengthy operation. *

* If the device has not been provisioned before, this call also provisions the device * which involves accessing the provisioning server and can take a variable time to * 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 preparation has finished. If a - * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning - * and preparation has finished, i.e., runs in blocking mode. + * When needed, the provisioning will be launched in the background. + * The listener {@link DrmEventCallback#onDrmPrepared} + * will be called when provisioning and preparation are finished. The application should + * check the status code returned with {@link DrmEventCallback#onDrmPrepared} to proceed. *

- * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM + * The registered {@link DrmEventCallback#onDrmPrepared} is called to indicate the DRM * session being ready. The application should not make any assumption about its call - * sequence (e.g., before or after prepareDrm returns), or the thread context that will - * execute the listener (unless the listener is registered with a handler thread). + * sequence (e.g., before or after prepareDrm returns). *

* * @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 being prepared 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 + * from the source through {@code getDrmInfo} or registering a + * {@link DrmEventCallback#onDrmInfo}. */ - // This is a synchronous call. - public abstract void prepareDrm(@NonNull UUID uuid) - throws UnsupportedSchemeException, ResourceBusyException, - ProvisioningNetworkErrorException, ProvisioningServerErrorException; + // This is an asynchronous call. + public abstract void prepareDrm(@NonNull UUID uuid); /** * Releases the DRM session @@ -2107,28 +2122,6 @@ public abstract class MediaPlayer2 implements AutoCloseable } } - /** - * Thrown when the device requires DRM provisioning but the provisioning attempt has - * failed due to a network error (Internet reachability, timeout, etc.). - * Extends MediaDrm.MediaDrmException - */ - public abstract static class ProvisioningNetworkErrorException extends MediaDrmException { - protected 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 abstract static class ProvisioningServerErrorException extends MediaDrmException { - protected ProvisioningServerErrorException(String detailMessage) { - super(detailMessage); - } - } - public static final class MetricsConstants { private MetricsConstants() {} diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index 6263e5d65b6e0..a5eb1fb126742 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -2409,7 +2409,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - public static void checkArgument(boolean expression, String errorMessage) { + private static void checkArgument(boolean expression, String errorMessage) { if (!expression) { throw new IllegalArgumentException(errorMessage); } @@ -2473,15 +2473,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private ArrayList > mDrmEventCallbackRecords = new ArrayList >(); - /** - * Register a callback to be invoked when the media source is ready - * for playback. - * - * @param eventCallback the callback that will be run - * @param executor the executor through which the callback should be invoked - */ @Override - public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor, + public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor, @NonNull DrmEventCallback eventCallback) { if (eventCallback == null) { throw new IllegalArgumentException("Illegal null EventCallback"); @@ -2495,17 +2488,17 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Clears the {@link DrmEventCallback}. - */ @Override - public void clearDrmEventCallback() { + public void unregisterDrmEventCallback(DrmEventCallback eventCallback) { synchronized (mDrmEventCbLock) { - mDrmEventCallbackRecords.clear(); + for (Pair cb : mDrmEventCallbackRecords) { + if (cb.second == eventCallback) { + mDrmEventCallbackRecords.remove(cb); + } + } } } - /** * Retrieves the DRM Info associated with the current source * @@ -2532,54 +2525,80 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return drmInfo; } - - /** - * Prepares the DRM for the current source - *

- * 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} - * and {@code setDrmPropertyString} calls and refrain from any lengthy operation. - *

- * If the device has not been provisioned before, this call also provisions the device - * which involves accessing the provisioning server and can take a variable time to - * 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 preparation has finished. If a - * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning - * and preparation has finished, i.e., runs in blocking mode. - *

- * 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 - * sequence (e.g., before or after prepareDrm returns), or the thread context that will - * execute the listener (unless the listener is registered with a handler thread). - *

- * - * @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 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 - */ @Override - public void prepareDrm(@NonNull UUID uuid) + public void prepareDrm(@NonNull UUID uuid) { + addTask(new Task(CALL_COMPLETED_PREPARE_DRM, true) { + @Override + void process() { + int status = PREPARE_DRM_STATUS_SUCCESS; + boolean sendEvent = true; + + try { + doPrepareDrm(uuid); + } catch (ResourceBusyException e) { + status = PREPARE_DRM_STATUS_RESOURCE_BUSY; + } catch (UnsupportedSchemeException e) { + status = PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME; + } catch (NotProvisionedException e) { + Log.w(TAG, "prepareDrm: NotProvisionedException"); + + // handle provisioning internally; it'll reset mPrepareDrmInProgress + status = HandleProvisioninig(uuid); + + if (status == PREPARE_DRM_STATUS_SUCCESS) { + // DrmEventCallback will be fired in provisioning + sendEvent = false; + } else { + synchronized (mDrmLock) { + cleanDrmObj(); + } + + switch (status) { + case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR: + Log.e(TAG, "prepareDrm: Provisioning was required but failed " + + "due to a network error."); + break; + + case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR: + Log.e(TAG, "prepareDrm: Provisioning was required but the request " + + "was denied by the server."); + break; + + case PREPARE_DRM_STATUS_PREPARATION_ERROR: + default: + Log.e(TAG, "prepareDrm: Post-provisioning preparation failed."); + break; + } + } + } catch (Exception e) { + status = PREPARE_DRM_STATUS_PREPARATION_ERROR; + } + + if (sendEvent) { + final int prepareDrmStatus = status; + sendDrmEvent(new DrmEventNotifier() { + @Override + public void notify(DrmEventCallback callback) { + callback.onDrmPrepared( + MediaPlayer2Impl.this, mCurrentDSD, prepareDrmStatus); + } + }); + + synchronized (mTaskLock) { + mCurrentTask = null; + processPendingTask_l(); + } + } + } + }); + } + + private void doPrepareDrm(@NonNull UUID uuid) throws UnsupportedSchemeException, ResourceBusyException, - ProvisioningNetworkErrorException, ProvisioningServerErrorException - { + NotProvisionedException { Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper); - boolean allDoneWithoutProvisioning = false; - synchronized (mDrmLock) { - // only allowing if tied to a protected source; might relax for releasing offline keys if (mDrmInfoImpl == null) { final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " + @@ -2623,8 +2642,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } mDrmConfigAllowed = true; - } // synchronized - + } // synchronized // call the callback outside the lock if (mOnDrmConfigHelper != null) { @@ -2640,74 +2658,28 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mDrmUUID = uuid; mActiveDrmScheme = true; - - allDoneWithoutProvisioning = true; + mPrepareDrmInProgress = false; } catch (IllegalStateException e) { final String msg = "prepareDrm(): Wrong usage: The player must be " + "in the prepared state to call prepareDrm()."; Log.e(TAG, msg); earlyExit = true; + mPrepareDrmInProgress = false; throw new IllegalStateException(msg); } catch (NotProvisionedException e) { - Log.w(TAG, "prepareDrm: NotProvisionedException"); - - // handle provisioning internally; it'll reset mPrepareDrmInProgress - int result = HandleProvisioninig(uuid); - - // if blocking mode, we're already done; - // if non-blocking mode, we attempted to launch background provisioning - if (result != PREPARE_DRM_STATUS_SUCCESS) { - earlyExit = true; - 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 ProvisioningNetworkErrorExceptionImpl(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 ProvisioningServerErrorExceptionImpl(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 + Log.w(TAG, "prepareDrm: NotProvisionedException", e); + throw e; } catch (Exception e) { Log.e(TAG, "prepareDrm: Exception " + e); earlyExit = true; + mPrepareDrmInProgress = false; throw e; } finally { - if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception - mPrepareDrmInProgress = false; - } - if (earlyExit) { // cleaning up object if didn't succeed + if (earlyExit) { // clean up object if didn't succeed cleanDrmObj(); } - } // finally - } // synchronized - - - // if finished successfully without provisioning, call the callback outside the lock - if (allDoneWithoutProvisioning) { - sendDrmEvent(new DrmEventNotifier() { - @Override - public void notify(DrmEventCallback callback) { - callback.onDrmPrepared( - MediaPlayer2Impl.this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS); - } - }); - } - + } // finally + } // synchronized } @@ -3164,31 +3136,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Thrown when the device requires DRM provisioning but the provisioning attempt has - * failed due to a network error (Internet reachability, timeout, etc.). - * Extends MediaDrm.MediaDrmException - */ - public static final class ProvisioningNetworkErrorExceptionImpl - extends ProvisioningNetworkErrorException { - public ProvisioningNetworkErrorExceptionImpl(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 ProvisioningServerErrorExceptionImpl - extends ProvisioningServerErrorException { - public ProvisioningServerErrorExceptionImpl(String detailMessage) { - super(detailMessage); - } - } - - private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId); // Modular DRM helpers @@ -3296,7 +3243,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private Object drmLock; private MediaPlayer2Impl mediaPlayer; private int status; - private boolean finished; public int status() { return status; } @@ -3362,38 +3308,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { boolean succeeded = false; - boolean hasCallback = false; - synchronized (mDrmEventCbLock) { - hasCallback = !mDrmEventCallbackRecords.isEmpty(); - } - // non-blocking mode needs the lock - if (hasCallback) { - - synchronized (drmLock) { - // 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; - if (!succeeded) { - cleanDrmObj(); // cleaning up if it hasn't gone through while in the lock - } - } // synchronized - - // calling the callback outside the lock - sendDrmEvent(new DrmEventNotifier() { - @Override - public void notify(DrmEventCallback callback) { - callback.onDrmPrepared( - mediaPlayer, mCurrentDSD, status); - } - }); - } else { // blocking mode already has the lock - + synchronized (drmLock) { // continuing with prepareDrm if (provisioningSucceeded) { succeeded = mediaPlayer.resumePrepareDrm(uuid); @@ -3404,12 +3319,28 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; if (!succeeded) { - cleanDrmObj(); // cleaning up if it hasn't gone through + cleanDrmObj(); // cleaning up if it hasn't gone through while in the lock + } + } // synchronized + + // calling the callback outside the lock + sendDrmEvent(new DrmEventNotifier() { + @Override + public void notify(DrmEventCallback callback) { + callback.onDrmPrepared( + mediaPlayer, mCurrentDSD, status); + } + }); + + synchronized (mTaskLock) { + if (mCurrentTask != null + && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE_DRM + && mCurrentTask.mNeedToWaitForEventToComplete) { + mCurrentTask = null; + processPendingTask_l(); } } - - finished = true; - } // run() + } /** * Returns a byte[] containing the remainder of 'in', closing it when done. @@ -3437,50 +3368,29 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } // ProvisioningThread private int HandleProvisioninig(UUID uuid) { - // the lock is already held by the caller - - if (mDrmProvisioningInProgress) { - Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress"); - return PREPARE_DRM_STATUS_PREPARATION_ERROR; - } - - MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest(); - if (provReq == null) { - Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null."); - return PREPARE_DRM_STATUS_PREPARATION_ERROR; - } - - Log.v(TAG, "HandleProvisioninig provReq " + - " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl()); - - // networking in a background thread - mDrmProvisioningInProgress = true; - - mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this); - mDrmProvisioningThread.start(); - - int result; - - // non-blocking: this is not the final result - boolean hasCallback = false; - synchronized (mDrmEventCbLock) { - hasCallback = !mDrmEventCallbackRecords.isEmpty(); - } - if (hasCallback) { - result = PREPARE_DRM_STATUS_SUCCESS; - } else { - // if blocking mode, wait till provisioning is done - try { - mDrmProvisioningThread.join(); - } catch (Exception e) { - Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e); + synchronized (mDrmLock) { + if (mDrmProvisioningInProgress) { + Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress"); + return PREPARE_DRM_STATUS_PREPARATION_ERROR; } - result = mDrmProvisioningThread.status(); - // no longer need the thread - mDrmProvisioningThread = null; - } - return result; + MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest(); + if (provReq == null) { + Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null."); + return PREPARE_DRM_STATUS_PREPARATION_ERROR; + } + + Log.v(TAG, "HandleProvisioninig provReq " + + " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl()); + + // networking in a background thread + mDrmProvisioningInProgress = true; + + mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this); + mDrmProvisioningThread.start(); + + return PREPARE_DRM_STATUS_SUCCESS; + } } private boolean resumePrepareDrm(UUID uuid) { @@ -3691,7 +3601,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private void sendCompleteNotification(int status) { // In {@link #notifyWhenCommandLabelReached} case, a separate callback // {@link #onCommandLabelReached} is already called in {@code process()}. - if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) { + // CALL_COMPLETED_PREPARE_DRM is sent via DrmEventCallback + if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED + || mMediaCallType == CALL_COMPLETED_PREPARE_DRM) { return; } sendEvent(new EventNotifier() {