Move DRM error code assignment into DefaultDrmSession
PiperOrigin-RevId: 384280087
This commit is contained in:
parent
8451be1b0b
commit
cdaf3e4e99
@ -19,10 +19,6 @@ import static com.google.android.exoplayer2.util.Util.castNonNull;
|
|||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
import android.media.DeniedByServerException;
|
|
||||||
import android.media.MediaDrm;
|
|
||||||
import android.media.MediaDrmResetException;
|
|
||||||
import android.media.NotProvisionedException;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@ -43,9 +39,7 @@ import com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason;
|
|||||||
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
||||||
import com.google.android.exoplayer2.Player.RepeatMode;
|
import com.google.android.exoplayer2.Player.RepeatMode;
|
||||||
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
|
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
|
||||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
|
||||||
import com.google.android.exoplayer2.drm.DrmSession;
|
import com.google.android.exoplayer2.drm.DrmSession;
|
||||||
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
@ -590,27 +584,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
playbackInfo = playbackInfo.copyWithPlaybackError(e);
|
playbackInfo = playbackInfo.copyWithPlaybackError(e);
|
||||||
}
|
}
|
||||||
} catch (DrmSession.DrmSessionException e) {
|
} catch (DrmSession.DrmSessionException e) {
|
||||||
@Nullable Throwable cause = e.getCause();
|
handleIoException(e, e.errorCode);
|
||||||
@ErrorCode int errorCode;
|
|
||||||
if (Util.SDK_INT >= 21 && PlatformOperationsWrapperV21.isMediaDrmStateException(cause)) {
|
|
||||||
errorCode = PlatformOperationsWrapperV21.mediaDrmStateExceptionToErrorCode(cause);
|
|
||||||
} else if (Util.SDK_INT >= 23
|
|
||||||
&& PlatformOperationsWrapperV23.isMediaDrmResetException(cause)) {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR;
|
|
||||||
} else if (Util.SDK_INT >= 18
|
|
||||||
&& PlatformOperationsWrapperV18.isNotProvisionedException(cause)) {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED;
|
|
||||||
} else if (Util.SDK_INT >= 18
|
|
||||||
&& PlatformOperationsWrapperV18.isDeniedByServerException(cause)) {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED;
|
|
||||||
} else if (cause instanceof UnsupportedDrmException) {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED;
|
|
||||||
} else if (cause instanceof DefaultDrmSessionManager.MissingSchemeDataException) {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR;
|
|
||||||
} else {
|
|
||||||
errorCode = PlaybackException.ERROR_CODE_DRM_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
handleIoException(e, errorCode);
|
|
||||||
} catch (FileDataSource.FileDataSourceException e) {
|
} catch (FileDataSource.FileDataSourceException e) {
|
||||||
@Nullable Throwable cause = e.getCause();
|
@Nullable Throwable cause = e.getCause();
|
||||||
@ErrorCode int errorCode;
|
@ErrorCode int errorCode;
|
||||||
@ -3092,20 +3066,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(18)
|
|
||||||
private static final class PlatformOperationsWrapperV18 {
|
|
||||||
|
|
||||||
@DoNotInline
|
|
||||||
public static boolean isNotProvisionedException(@Nullable Throwable throwable) {
|
|
||||||
return throwable instanceof NotProvisionedException;
|
|
||||||
}
|
|
||||||
|
|
||||||
@DoNotInline
|
|
||||||
public static boolean isDeniedByServerException(@Nullable Throwable throwable) {
|
|
||||||
return throwable instanceof DeniedByServerException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(21)
|
@RequiresApi(21)
|
||||||
private static final class PlatformOperationsWrapperV21 {
|
private static final class PlatformOperationsWrapperV21 {
|
||||||
|
|
||||||
@ -3113,28 +3073,5 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
public static boolean isPermissionError(@Nullable Throwable e) {
|
public static boolean isPermissionError(@Nullable Throwable e) {
|
||||||
return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES;
|
return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DoNotInline
|
|
||||||
public static boolean isMediaDrmStateException(@Nullable Throwable throwable) {
|
|
||||||
return throwable instanceof MediaDrm.MediaDrmStateException;
|
|
||||||
}
|
|
||||||
|
|
||||||
@DoNotInline
|
|
||||||
@ErrorCode
|
|
||||||
public static int mediaDrmStateExceptionToErrorCode(Throwable throwable) {
|
|
||||||
@Nullable
|
|
||||||
String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) throwable).getDiagnosticInfo();
|
|
||||||
int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo);
|
|
||||||
return C.getErrorCodeForMediaDrmErrorCode(drmErrorCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(23)
|
|
||||||
private static final class PlatformOperationsWrapperV23 {
|
|
||||||
|
|
||||||
@DoNotInline
|
|
||||||
public static boolean isMediaDrmResetException(@Nullable Throwable throwable) {
|
|
||||||
return throwable instanceof MediaDrmResetException;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ import static com.google.android.exoplayer2.util.Assertions.checkState;
|
|||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.media.DeniedByServerException;
|
||||||
|
import android.media.MediaDrm;
|
||||||
|
import android.media.MediaDrmResetException;
|
||||||
import android.media.NotProvisionedException;
|
import android.media.NotProvisionedException;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
@ -26,6 +29,7 @@ import android.os.Looper;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import androidx.annotation.DoNotInline;
|
||||||
import androidx.annotation.GuardedBy;
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
@ -83,8 +87,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
* Called by a session when it fails to perform a provisioning operation.
|
* Called by a session when it fails to perform a provisioning operation.
|
||||||
*
|
*
|
||||||
* @param error The error that occurred.
|
* @param error The error that occurred.
|
||||||
|
* @param thrownByExoMediaDrm Whether the error originated in an {@link ExoMediaDrm} operation.
|
||||||
|
* False when the error originated in the provisioning request.
|
||||||
*/
|
*/
|
||||||
void onProvisionError(Exception error);
|
void onProvisionError(Exception error, boolean thrownByExoMediaDrm);
|
||||||
|
|
||||||
/** Called by a session when it successfully completes a provisioning operation. */
|
/** Called by a session when it successfully completes a provisioning operation. */
|
||||||
void onProvisionCompleted();
|
void onProvisionCompleted();
|
||||||
@ -236,8 +242,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onProvisionError(Exception error) {
|
public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) {
|
||||||
onError(error);
|
onError(error, thrownByExoMediaDrm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrmSession implementation.
|
// DrmSession implementation.
|
||||||
@ -360,7 +366,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
} catch (NotProvisionedException e) {
|
} catch (NotProvisionedException e) {
|
||||||
provisioningManager.provisionRequired(this);
|
provisioningManager.provisionRequired(this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
onError(e);
|
onError(e, /* thrownByExoMediaDrm= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -374,14 +380,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
currentProvisionRequest = null;
|
currentProvisionRequest = null;
|
||||||
|
|
||||||
if (response instanceof Exception) {
|
if (response instanceof Exception) {
|
||||||
provisioningManager.onProvisionError((Exception) response);
|
provisioningManager.onProvisionError((Exception) response, /* thrownByExoMediaDrm= */ false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mediaDrm.provideProvisionResponse((byte[]) response);
|
mediaDrm.provideProvisionResponse((byte[]) response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
provisioningManager.onProvisionError(e);
|
provisioningManager.onProvisionError(e, /* thrownByExoMediaDrm= */ true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +416,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
+ licenseDurationRemainingSec);
|
+ licenseDurationRemainingSec);
|
||||||
postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
|
postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
|
||||||
} else if (licenseDurationRemainingSec <= 0) {
|
} else if (licenseDurationRemainingSec <= 0) {
|
||||||
onError(new KeysExpiredException());
|
onError(new KeysExpiredException(), /* thrownByExoMediaDrm= */ false);
|
||||||
} else {
|
} else {
|
||||||
state = STATE_OPENED_WITH_KEYS;
|
state = STATE_OPENED_WITH_KEYS;
|
||||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored);
|
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored);
|
||||||
@ -438,7 +444,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
|
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
onError(e);
|
onError(e, /* thrownByExoMediaDrm= */ true);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -458,7 +464,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
Util.castNonNull(requestHandler)
|
Util.castNonNull(requestHandler)
|
||||||
.post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry);
|
.post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
onKeysError(e);
|
onKeysError(e, /* thrownByExoMediaDrm= */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,7 +476,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
currentKeyRequest = null;
|
currentKeyRequest = null;
|
||||||
|
|
||||||
if (response instanceof Exception) {
|
if (response instanceof Exception) {
|
||||||
onKeysError((Exception) response);
|
onKeysError((Exception) response, /* thrownByExoMediaDrm= */ false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,7 +498,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
|
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
onKeysError(e);
|
onKeysError(e, /* thrownByExoMediaDrm= */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,17 +509,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onKeysError(Exception e) {
|
private void onKeysError(Exception e, boolean thrownByExoMediaDrm) {
|
||||||
if (e instanceof NotProvisionedException) {
|
if (e instanceof NotProvisionedException) {
|
||||||
provisioningManager.provisionRequired(this);
|
provisioningManager.provisionRequired(this);
|
||||||
} else {
|
} else {
|
||||||
onError(e);
|
onError(e, thrownByExoMediaDrm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onError(final Exception e) {
|
private void onError(Exception e, boolean thrownByExoMediaDrm) {
|
||||||
// TODO(internal b/184262323): Add an argument here which takes the error code from the caller.
|
lastException =
|
||||||
lastException = new DrmSessionException(e, PlaybackException.ERROR_CODE_DRM_UNSPECIFIED);
|
new DrmSessionException(e, getErrorCodeForMediaDrmException(e, thrownByExoMediaDrm));
|
||||||
Log.e(TAG, "DRM session error", e);
|
Log.e(TAG, "DRM session error", e);
|
||||||
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
|
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
|
||||||
if (state != STATE_OPENED_WITH_KEYS) {
|
if (state != STATE_OPENED_WITH_KEYS) {
|
||||||
@ -533,6 +539,35 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PlaybackException.ErrorCode
|
||||||
|
private static int getErrorCodeForMediaDrmException(
|
||||||
|
Exception exception, boolean thrownByExoMediaDrm) {
|
||||||
|
if (Util.SDK_INT >= 21 && PlatformOperationsWrapperV21.isMediaDrmStateException(exception)) {
|
||||||
|
return PlatformOperationsWrapperV21.mediaDrmStateExceptionToErrorCode(exception);
|
||||||
|
} else if (Util.SDK_INT >= 23
|
||||||
|
&& PlatformOperationsWrapperV23.isMediaDrmResetException(exception)) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR;
|
||||||
|
} else if (Util.SDK_INT >= 18
|
||||||
|
&& PlatformOperationsWrapperV18.isNotProvisionedException(exception)) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED;
|
||||||
|
} else if (Util.SDK_INT >= 18
|
||||||
|
&& PlatformOperationsWrapperV18.isDeniedByServerException(exception)) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED;
|
||||||
|
} else if (exception instanceof UnsupportedDrmException) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED;
|
||||||
|
} else if (exception instanceof DefaultDrmSessionManager.MissingSchemeDataException) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR;
|
||||||
|
} else if (exception instanceof KeysExpiredException) {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_LICENSE_EXPIRED;
|
||||||
|
} else if (thrownByExoMediaDrm) {
|
||||||
|
// A MediaDrm exception was thrown but it was impossible to determine the cause. Because no
|
||||||
|
// better diagnosis tools were provided, we treat this as a system error.
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR;
|
||||||
|
} else {
|
||||||
|
return PlaybackException.ERROR_CODE_DRM_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Internal classes.
|
// Internal classes.
|
||||||
|
|
||||||
@SuppressLint("HandlerLeak")
|
@SuppressLint("HandlerLeak")
|
||||||
@ -678,4 +713,45 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
this.request = request;
|
this.request = request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(18)
|
||||||
|
private static final class PlatformOperationsWrapperV18 {
|
||||||
|
|
||||||
|
@DoNotInline
|
||||||
|
public static boolean isNotProvisionedException(@Nullable Throwable throwable) {
|
||||||
|
return throwable instanceof NotProvisionedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoNotInline
|
||||||
|
public static boolean isDeniedByServerException(@Nullable Throwable throwable) {
|
||||||
|
return throwable instanceof DeniedByServerException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
private static final class PlatformOperationsWrapperV21 {
|
||||||
|
|
||||||
|
@DoNotInline
|
||||||
|
public static boolean isMediaDrmStateException(@Nullable Throwable throwable) {
|
||||||
|
return throwable instanceof MediaDrm.MediaDrmStateException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoNotInline
|
||||||
|
@PlaybackException.ErrorCode
|
||||||
|
public static int mediaDrmStateExceptionToErrorCode(Throwable throwable) {
|
||||||
|
@Nullable
|
||||||
|
String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) throwable).getDiagnosticInfo();
|
||||||
|
int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo);
|
||||||
|
return C.getErrorCodeForMediaDrmErrorCode(drmErrorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(23)
|
||||||
|
private static final class PlatformOperationsWrapperV23 {
|
||||||
|
|
||||||
|
@DoNotInline
|
||||||
|
public static boolean isMediaDrmResetException(@Nullable Throwable throwable) {
|
||||||
|
return throwable instanceof MediaDrmResetException;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,14 +876,14 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProvisionError(Exception error) {
|
public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) {
|
||||||
provisioningSession = null;
|
provisioningSession = null;
|
||||||
ImmutableList<DefaultDrmSession> sessionsToNotify =
|
ImmutableList<DefaultDrmSession> sessionsToNotify =
|
||||||
ImmutableList.copyOf(sessionsAwaitingProvisioning);
|
ImmutableList.copyOf(sessionsAwaitingProvisioning);
|
||||||
// Clear the list before calling onProvisionError in case provisioning is re-requested.
|
// Clear the list before calling onProvisionError in case provisioning is re-requested.
|
||||||
sessionsAwaitingProvisioning.clear();
|
sessionsAwaitingProvisioning.clear();
|
||||||
for (DefaultDrmSession session : sessionsToNotify) {
|
for (DefaultDrmSession session : sessionsToNotify) {
|
||||||
session.onProvisionError(error);
|
session.onProvisionError(error, thrownByExoMediaDrm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user