Merge "MediaPlayer2: make prepareDrm asynchronous only"

This commit is contained in:
TreeHugger Robot
2018-10-28 01:16:42 +00:00
committed by Android (Google) Code Review
2 changed files with 184 additions and 279 deletions

View File

@@ -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
* <p>
* 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.
* <p>
* 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.
* <p>
* 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).
* <p>
*
* @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() {}

View File

@@ -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<Pair<Executor, DrmEventCallback> > mDrmEventCallbackRecords
= new ArrayList<Pair<Executor, DrmEventCallback> >();
/**
* 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<Executor, DrmEventCallback> 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
* <p>
* 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.
* <p>
* 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.
* <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
* 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).
* <p>
*
* @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() {