Loading api/current.txt +20 −0 Original line number Original line Diff line number Diff line Loading @@ -15330,6 +15330,8 @@ package android.media { method public void removeKeys(byte[]); method public void removeKeys(byte[]); method public void restoreKeys(byte[], byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler); method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); method public void setPropertyString(java.lang.String, java.lang.String); field public static final int EVENT_KEY_EXPIRED = 3; // 0x3 field public static final int EVENT_KEY_EXPIRED = 3; // 0x3 Loading @@ -15337,6 +15339,11 @@ package android.media { field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int KEY_STATUS_EXPIRED = 1; // 0x1 field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4 field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2 field public static final int KEY_STATUS_PENDING = 3; // 0x3 field public static final int KEY_STATUS_USABLE = 0; // 0x0 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 Loading @@ -15363,6 +15370,11 @@ package android.media { method public int getRequestType(); method public int getRequestType(); } } public static final class MediaDrm.KeyStatus { method public byte[] getKeyId(); method public int getStatusCode(); } public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { method public java.lang.String getDiagnosticInfo(); method public java.lang.String getDiagnosticInfo(); } } Loading @@ -15371,6 +15383,14 @@ package android.media { method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); } } public static abstract interface MediaDrm.OnExpirationUpdateListener { method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long); } public static abstract interface MediaDrm.OnKeysChangeListener { method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean); } public static final class MediaDrm.ProvisionRequest { public static final class MediaDrm.ProvisionRequest { method public byte[] getData(); method public byte[] getData(); method public java.lang.String getDefaultUrl(); method public java.lang.String getDefaultUrl(); api/system-current.txt +20 −0 Original line number Original line Diff line number Diff line Loading @@ -16539,6 +16539,8 @@ package android.media { method public void removeKeys(byte[]); method public void removeKeys(byte[]); method public void restoreKeys(byte[], byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler); method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); method public void setPropertyString(java.lang.String, java.lang.String); method public void unprovisionDevice(); method public void unprovisionDevice(); Loading @@ -16547,6 +16549,11 @@ package android.media { field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int KEY_STATUS_EXPIRED = 1; // 0x1 field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4 field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2 field public static final int KEY_STATUS_PENDING = 3; // 0x3 field public static final int KEY_STATUS_USABLE = 0; // 0x0 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 Loading @@ -16573,6 +16580,11 @@ package android.media { method public int getRequestType(); method public int getRequestType(); } } public static final class MediaDrm.KeyStatus { method public byte[] getKeyId(); method public int getStatusCode(); } public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { method public java.lang.String getDiagnosticInfo(); method public java.lang.String getDiagnosticInfo(); } } Loading @@ -16581,6 +16593,14 @@ package android.media { method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); } } public static abstract interface MediaDrm.OnExpirationUpdateListener { method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long); } public static abstract interface MediaDrm.OnKeysChangeListener { method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean); } public static final class MediaDrm.ProvisionRequest { public static final class MediaDrm.ProvisionRequest { method public byte[] getData(); method public byte[] getData(); method public java.lang.String getDefaultUrl(); method public java.lang.String getDefaultUrl(); media/java/android/media/MediaDrm.java +206 −12 Original line number Original line Diff line number Diff line Loading @@ -17,9 +17,10 @@ package android.media; package android.media; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.UUID; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.UUID; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; Loading Loading @@ -98,12 +99,14 @@ import android.util.Log; */ */ public final class MediaDrm { public final class MediaDrm { private final static String TAG = "MediaDrm"; private static final String TAG = "MediaDrm"; private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private EventHandler mEventHandler; private EventHandler mEventHandler; private OnEventListener mOnEventListener; private OnEventListener mOnEventListener; private OnKeysChangeListener mOnKeysChangeListener; private OnExpirationUpdateListener mOnExpirationUpdateListener; private long mNativeContext; private long mNativeContext; Loading Loading @@ -226,6 +229,148 @@ public final class MediaDrm { } } } } /** * Register a callback to be invoked when a session expiration update * occurs. The app's OnExpirationUpdateListener will be notified * when the expiration time of the keys in the session have changed. * @param listener the callback that will be run * @param handler the handler on which the listener should be invoked, or * null if the listener should be invoked on the calling thread's looper. */ public void setOnExpirationUpdateListener(OnExpirationUpdateListener listener, Handler handler) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper != null) { if (mEventHandler == null || mEventHandler.getLooper() != looper) { mEventHandler = new EventHandler(this, looper); } } } mOnExpirationUpdateListener = listener; } /** * Interface definition for a callback to be invoked when a drm session * expiration update occurs */ public interface OnExpirationUpdateListener { /** * Called when a session expiration update occurs, to inform the app * about the change in expiration time * * @param md the MediaDrm object on which the event occurred * @param sessionId the DRM session ID on which the event occurred * @param expirationTime the new expiration time for the keys in the session. * The time is in milliseconds, relative to the Unix epoch. */ void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expirationTime); } /** * Register a callback to be invoked when the state of keys in a session * change, e.g. when a license update occurs or when a license expires. * * @param listener the callback that will be run when key status changes * @param handler the handler on which the listener should be invoked, or * null if the listener should be invoked on the calling thread's looper. */ public void setOnKeysChangeListener(OnKeysChangeListener listener, Handler handler) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper != null) { if (mEventHandler == null || mEventHandler.getLooper() != looper) { mEventHandler = new EventHandler(this, looper); } } } mOnKeysChangeListener = listener; } /** * Interface definition for a callback to be invoked when the keys in a drm * session change states. */ public interface OnKeysChangeListener { /** * Called when the keys in a session change status, such as when the license * is renewed or expires. * * @param md the MediaDrm object on which the event occurred * @param sessionId the DRM session ID on which the event occurred * @param keyInformation a list of {@link MediaDrm.KeyStatus} * instances indicating the status for each key in the session * @param hasNewUsableKey indicates if a key has been added that is usable, * which may trigger an attempt to resume playback on the media stream * if it is currently blocked waiting for a key. */ void onKeysChange(MediaDrm md, byte[] sessionId, List<KeyStatus> keyInformation, boolean hasNewUsableKey); } /** * The key is currently usable to decrypt media data */ public static final int KEY_STATUS_USABLE = 0; /** * The key is no longer usable to decrypt media data because its * expiration time has passed. */ public static final int KEY_STATUS_EXPIRED = 1; /** * The key is not currently usable to decrypt media data because its * output requirements cannot currently be met. */ public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; /** * The status of the key is not yet known and is being determined. * The status will be updated with the actual status when it has * been determined. */ public static final int KEY_STATUS_PENDING = 3; /** * The key is not currently usable to decrypt media data because of an * internal error in processing unrelated to input parameters. This error * is not actionable by an app. */ public static final int KEY_STATUS_INTERNAL_ERROR = 4; /** * Defines the status of a key. * A KeyStatus for each key in a session is provided to the * {@link OnKeysChangeListener#onKeysChange} * listener. */ public static final class KeyStatus { private final byte[] mKeyId; private final int mStatusCode; KeyStatus(byte[] keyId, int statusCode) { mKeyId = keyId; mStatusCode = statusCode; } /** * Returns the status code for the key */ public int getStatusCode() { return mStatusCode; } /** * Returns the id for the key */ public byte[] getKeyId() { return mKeyId; } } /** /** * Register a callback to be invoked when an event occurs * Register a callback to be invoked when an event occurs * * Loading Loading @@ -289,6 +434,8 @@ public final class MediaDrm { public static final int EVENT_SESSION_RECLAIMED = 5; public static final int EVENT_SESSION_RECLAIMED = 5; private static final int DRM_EVENT = 200; private static final int DRM_EVENT = 200; private static final int EXPIRATION_UPDATE = 201; private static final int KEYS_CHANGE = 202; private class EventHandler extends Handler private class EventHandler extends Handler { { Loading @@ -308,8 +455,6 @@ public final class MediaDrm { switch(msg.what) { switch(msg.what) { case DRM_EVENT: case DRM_EVENT: Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")"); if (mOnEventListener != null) { if (mOnEventListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; Parcel parcel = (Parcel)msg.obj; Loading @@ -321,11 +466,46 @@ public final class MediaDrm { if (data.length == 0) { if (data.length == 0) { data = null; data = null; } } Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")"); mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data); mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data); } } } } return; return; case KEYS_CHANGE: if (mOnKeysChangeListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; byte[] sessionId = parcel.createByteArray(); if (sessionId.length > 0) { List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel); boolean hasNewUsableKey = (parcel.readInt() != 0); Log.i(TAG, "Drm keys change"); mOnKeysChangeListener.onKeysChange(mMediaDrm, sessionId, keyStatusList, hasNewUsableKey); } } } return; case EXPIRATION_UPDATE: if (mOnExpirationUpdateListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; byte[] sessionId = parcel.createByteArray(); if (sessionId.length > 0) { long expirationTime = parcel.readLong(); Log.i(TAG, "Drm key expiration update: " + expirationTime); mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId, expirationTime); } } } return; default: default: Log.e(TAG, "Unknown message type " + msg.what); Log.e(TAG, "Unknown message type " + msg.what); return; return; Loading @@ -333,7 +513,21 @@ public final class MediaDrm { } } } } /* /** * Parse a list of KeyStatus objects from an event parcel */ private List<KeyStatus> keyStatusListFromParcel(Parcel parcel) { int nelems = parcel.readInt(); List<KeyStatus> keyStatusList = new ArrayList(nelems); while (nelems-- > 0) { byte[] keyId = parcel.createByteArray(); int keyStatusCode = parcel.readInt(); keyStatusList.add(new KeyStatus(keyId, keyStatusCode)); } return keyStatusList; } /** * This method is called from native code when an event occurs. This method * This method is called from native code when an event occurs. This method * just uses the EventHandler system to post the event back to the main app thread. * just uses the EventHandler system to post the event back to the main app thread. * We use a weak reference to the original MediaPlayer object so that the native * We use a weak reference to the original MediaPlayer object so that the native Loading @@ -341,14 +535,14 @@ public final class MediaDrm { * the cookie passed to native_setup().) * the cookie passed to native_setup().) */ */ private static void postEventFromNative(Object mediadrm_ref, private static void postEventFromNative(Object mediadrm_ref, int eventType, int extra, Object obj) int what, int eventType, int extra, Object obj) { { MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get(); MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get(); if (md == null) { if (md == null) { return; return; } } if (md.mEventHandler != null) { if (md.mEventHandler != null) { Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj); Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj); md.mEventHandler.sendMessage(m); md.mEventHandler.sendMessage(m); } } } } Loading Loading @@ -404,7 +598,7 @@ public final class MediaDrm { /** /** * Contains the opaque data an app uses to request keys from a license server * Contains the opaque data an app uses to request keys from a license server */ */ public final static class KeyRequest { public static final class KeyRequest { private byte[] mData; private byte[] mData; private String mDefaultUrl; private String mDefaultUrl; private int mRequestType; private int mRequestType; Loading Loading @@ -521,7 +715,7 @@ public final class MediaDrm { * Contains the opaque data an app uses to request a certificate from a provisioning * Contains the opaque data an app uses to request a certificate from a provisioning * server * server */ */ public final static class ProvisionRequest { public static final class ProvisionRequest { ProvisionRequest() {} ProvisionRequest() {} /** /** Loading Loading @@ -812,7 +1006,7 @@ public final class MediaDrm { * * * @hide - not part of the public API at this time * @hide - not part of the public API at this time */ */ public final static class CertificateRequest { public static final class CertificateRequest { private byte[] mData; private byte[] mData; private String mDefaultUrl; private String mDefaultUrl; Loading Loading @@ -860,7 +1054,7 @@ public final class MediaDrm { * * * @hide - not part of the public API at this time * @hide - not part of the public API at this time */ */ public final static class Certificate { public static final class Certificate { Certificate() {} Certificate() {} /** /** Loading media/jni/android_media_MediaDrm.cpp +29 −4 Original line number Original line Diff line number Diff line Loading @@ -96,6 +96,12 @@ struct EventTypes { jint kEventSessionReclaimed; jint kEventSessionReclaimed; } gEventTypes; } gEventTypes; struct EventWhat { jint kWhatDrmEvent; jint kWhatExpirationUpdate; jint kWhatKeysChange; } gEventWhat; struct KeyTypes { struct KeyTypes { jint kKeyTypeStreaming; jint kKeyTypeStreaming; jint kKeyTypeOffline; jint kKeyTypeOffline; Loading Loading @@ -186,25 +192,37 @@ JNIDrmListener::~JNIDrmListener() void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) const Parcel *obj) { { jint jeventType; jint jwhat; jint jeventType = 0; // translate DrmPlugin event types into their java equivalents // translate DrmPlugin event types into their java equivalents switch (eventType) { switch (eventType) { case DrmPlugin::kDrmPluginEventProvisionRequired: case DrmPlugin::kDrmPluginEventProvisionRequired: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventProvisionRequired; jeventType = gEventTypes.kEventProvisionRequired; break; break; case DrmPlugin::kDrmPluginEventKeyNeeded: case DrmPlugin::kDrmPluginEventKeyNeeded: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventKeyRequired; jeventType = gEventTypes.kEventKeyRequired; break; break; case DrmPlugin::kDrmPluginEventKeyExpired: case DrmPlugin::kDrmPluginEventKeyExpired: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventKeyExpired; jeventType = gEventTypes.kEventKeyExpired; break; break; case DrmPlugin::kDrmPluginEventVendorDefined: case DrmPlugin::kDrmPluginEventVendorDefined: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventVendorDefined; jeventType = gEventTypes.kEventVendorDefined; break; break; case DrmPlugin::kDrmPluginEventSessionReclaimed: case DrmPlugin::kDrmPluginEventSessionReclaimed: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventSessionReclaimed; jeventType = gEventTypes.kEventSessionReclaimed; break; break; case DrmPlugin::kDrmPluginEventExpirationUpdate: jwhat = gEventWhat.kWhatExpirationUpdate; break; case DrmPlugin::kDrmPluginEventKeysChange: jwhat = gEventWhat.kWhatKeysChange; break; default: default: ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); return; return; Loading @@ -217,7 +235,7 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, Parcel* nativeParcel = parcelForJavaObject(env, jParcel); Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, gFields.post_event, mObject, env->CallStaticVoidMethod(mClass, gFields.post_event, mObject, jeventType, extra, jParcel); jwhat, jeventType, extra, jParcel); env->DeleteLocalRef(jParcel); env->DeleteLocalRef(jParcel); } } } } Loading Loading @@ -573,7 +591,7 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { FIND_CLASS(clazz, "android/media/MediaDrm"); FIND_CLASS(clazz, "android/media/MediaDrm"); GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", "(Ljava/lang/Object;IILjava/lang/Object;)V"); "(Ljava/lang/Object;IIILjava/lang/Object;)V"); jfieldID field; jfieldID field; GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); Loading @@ -587,6 +605,13 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I"); GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I"); gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field); gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I"); gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I"); gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEYS_CHANGE", "I"); gEventWhat.kWhatKeysChange = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); Loading Loading @@ -837,7 +862,7 @@ static jobject android_media_MediaDrm_getKeyRequest( env->SetIntField(keyObj, gFields.keyRequest.requestType, env->SetIntField(keyObj, gFields.keyRequest.requestType, gKeyRequestTypes.kKeyRequestTypeRelease); gKeyRequestTypes.kKeyRequestTypeRelease); break; break; case DrmPlugin::kKeyRequestType_Unknown: default: throwStateException(env, "DRM plugin failure: unknown key request type", throwStateException(env, "DRM plugin failure: unknown key request type", ERROR_DRM_UNKNOWN); ERROR_DRM_UNKNOWN); break; break; Loading Loading
api/current.txt +20 −0 Original line number Original line Diff line number Diff line Loading @@ -15330,6 +15330,8 @@ package android.media { method public void removeKeys(byte[]); method public void removeKeys(byte[]); method public void restoreKeys(byte[], byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler); method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); method public void setPropertyString(java.lang.String, java.lang.String); field public static final int EVENT_KEY_EXPIRED = 3; // 0x3 field public static final int EVENT_KEY_EXPIRED = 3; // 0x3 Loading @@ -15337,6 +15339,11 @@ package android.media { field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int KEY_STATUS_EXPIRED = 1; // 0x1 field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4 field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2 field public static final int KEY_STATUS_PENDING = 3; // 0x3 field public static final int KEY_STATUS_USABLE = 0; // 0x0 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 Loading @@ -15363,6 +15370,11 @@ package android.media { method public int getRequestType(); method public int getRequestType(); } } public static final class MediaDrm.KeyStatus { method public byte[] getKeyId(); method public int getStatusCode(); } public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { method public java.lang.String getDiagnosticInfo(); method public java.lang.String getDiagnosticInfo(); } } Loading @@ -15371,6 +15383,14 @@ package android.media { method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); } } public static abstract interface MediaDrm.OnExpirationUpdateListener { method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long); } public static abstract interface MediaDrm.OnKeysChangeListener { method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean); } public static final class MediaDrm.ProvisionRequest { public static final class MediaDrm.ProvisionRequest { method public byte[] getData(); method public byte[] getData(); method public java.lang.String getDefaultUrl(); method public java.lang.String getDefaultUrl();
api/system-current.txt +20 −0 Original line number Original line Diff line number Diff line Loading @@ -16539,6 +16539,8 @@ package android.media { method public void removeKeys(byte[]); method public void removeKeys(byte[]); method public void restoreKeys(byte[], byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler); method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); method public void setPropertyString(java.lang.String, java.lang.String); method public void unprovisionDevice(); method public void unprovisionDevice(); Loading @@ -16547,6 +16549,11 @@ package android.media { field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 field public static final int KEY_STATUS_EXPIRED = 1; // 0x1 field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4 field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2 field public static final int KEY_STATUS_PENDING = 3; // 0x3 field public static final int KEY_STATUS_USABLE = 0; // 0x0 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 Loading @@ -16573,6 +16580,11 @@ package android.media { method public int getRequestType(); method public int getRequestType(); } } public static final class MediaDrm.KeyStatus { method public byte[] getKeyId(); method public int getStatusCode(); } public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { method public java.lang.String getDiagnosticInfo(); method public java.lang.String getDiagnosticInfo(); } } Loading @@ -16581,6 +16593,14 @@ package android.media { method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]); } } public static abstract interface MediaDrm.OnExpirationUpdateListener { method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long); } public static abstract interface MediaDrm.OnKeysChangeListener { method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean); } public static final class MediaDrm.ProvisionRequest { public static final class MediaDrm.ProvisionRequest { method public byte[] getData(); method public byte[] getData(); method public java.lang.String getDefaultUrl(); method public java.lang.String getDefaultUrl();
media/java/android/media/MediaDrm.java +206 −12 Original line number Original line Diff line number Diff line Loading @@ -17,9 +17,10 @@ package android.media; package android.media; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.UUID; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.UUID; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; Loading Loading @@ -98,12 +99,14 @@ import android.util.Log; */ */ public final class MediaDrm { public final class MediaDrm { private final static String TAG = "MediaDrm"; private static final String TAG = "MediaDrm"; private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private EventHandler mEventHandler; private EventHandler mEventHandler; private OnEventListener mOnEventListener; private OnEventListener mOnEventListener; private OnKeysChangeListener mOnKeysChangeListener; private OnExpirationUpdateListener mOnExpirationUpdateListener; private long mNativeContext; private long mNativeContext; Loading Loading @@ -226,6 +229,148 @@ public final class MediaDrm { } } } } /** * Register a callback to be invoked when a session expiration update * occurs. The app's OnExpirationUpdateListener will be notified * when the expiration time of the keys in the session have changed. * @param listener the callback that will be run * @param handler the handler on which the listener should be invoked, or * null if the listener should be invoked on the calling thread's looper. */ public void setOnExpirationUpdateListener(OnExpirationUpdateListener listener, Handler handler) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper != null) { if (mEventHandler == null || mEventHandler.getLooper() != looper) { mEventHandler = new EventHandler(this, looper); } } } mOnExpirationUpdateListener = listener; } /** * Interface definition for a callback to be invoked when a drm session * expiration update occurs */ public interface OnExpirationUpdateListener { /** * Called when a session expiration update occurs, to inform the app * about the change in expiration time * * @param md the MediaDrm object on which the event occurred * @param sessionId the DRM session ID on which the event occurred * @param expirationTime the new expiration time for the keys in the session. * The time is in milliseconds, relative to the Unix epoch. */ void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expirationTime); } /** * Register a callback to be invoked when the state of keys in a session * change, e.g. when a license update occurs or when a license expires. * * @param listener the callback that will be run when key status changes * @param handler the handler on which the listener should be invoked, or * null if the listener should be invoked on the calling thread's looper. */ public void setOnKeysChangeListener(OnKeysChangeListener listener, Handler handler) { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper != null) { if (mEventHandler == null || mEventHandler.getLooper() != looper) { mEventHandler = new EventHandler(this, looper); } } } mOnKeysChangeListener = listener; } /** * Interface definition for a callback to be invoked when the keys in a drm * session change states. */ public interface OnKeysChangeListener { /** * Called when the keys in a session change status, such as when the license * is renewed or expires. * * @param md the MediaDrm object on which the event occurred * @param sessionId the DRM session ID on which the event occurred * @param keyInformation a list of {@link MediaDrm.KeyStatus} * instances indicating the status for each key in the session * @param hasNewUsableKey indicates if a key has been added that is usable, * which may trigger an attempt to resume playback on the media stream * if it is currently blocked waiting for a key. */ void onKeysChange(MediaDrm md, byte[] sessionId, List<KeyStatus> keyInformation, boolean hasNewUsableKey); } /** * The key is currently usable to decrypt media data */ public static final int KEY_STATUS_USABLE = 0; /** * The key is no longer usable to decrypt media data because its * expiration time has passed. */ public static final int KEY_STATUS_EXPIRED = 1; /** * The key is not currently usable to decrypt media data because its * output requirements cannot currently be met. */ public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; /** * The status of the key is not yet known and is being determined. * The status will be updated with the actual status when it has * been determined. */ public static final int KEY_STATUS_PENDING = 3; /** * The key is not currently usable to decrypt media data because of an * internal error in processing unrelated to input parameters. This error * is not actionable by an app. */ public static final int KEY_STATUS_INTERNAL_ERROR = 4; /** * Defines the status of a key. * A KeyStatus for each key in a session is provided to the * {@link OnKeysChangeListener#onKeysChange} * listener. */ public static final class KeyStatus { private final byte[] mKeyId; private final int mStatusCode; KeyStatus(byte[] keyId, int statusCode) { mKeyId = keyId; mStatusCode = statusCode; } /** * Returns the status code for the key */ public int getStatusCode() { return mStatusCode; } /** * Returns the id for the key */ public byte[] getKeyId() { return mKeyId; } } /** /** * Register a callback to be invoked when an event occurs * Register a callback to be invoked when an event occurs * * Loading Loading @@ -289,6 +434,8 @@ public final class MediaDrm { public static final int EVENT_SESSION_RECLAIMED = 5; public static final int EVENT_SESSION_RECLAIMED = 5; private static final int DRM_EVENT = 200; private static final int DRM_EVENT = 200; private static final int EXPIRATION_UPDATE = 201; private static final int KEYS_CHANGE = 202; private class EventHandler extends Handler private class EventHandler extends Handler { { Loading @@ -308,8 +455,6 @@ public final class MediaDrm { switch(msg.what) { switch(msg.what) { case DRM_EVENT: case DRM_EVENT: Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")"); if (mOnEventListener != null) { if (mOnEventListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; Parcel parcel = (Parcel)msg.obj; Loading @@ -321,11 +466,46 @@ public final class MediaDrm { if (data.length == 0) { if (data.length == 0) { data = null; data = null; } } Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")"); mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data); mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data); } } } } return; return; case KEYS_CHANGE: if (mOnKeysChangeListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; byte[] sessionId = parcel.createByteArray(); if (sessionId.length > 0) { List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel); boolean hasNewUsableKey = (parcel.readInt() != 0); Log.i(TAG, "Drm keys change"); mOnKeysChangeListener.onKeysChange(mMediaDrm, sessionId, keyStatusList, hasNewUsableKey); } } } return; case EXPIRATION_UPDATE: if (mOnExpirationUpdateListener != null) { if (msg.obj != null && msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; byte[] sessionId = parcel.createByteArray(); if (sessionId.length > 0) { long expirationTime = parcel.readLong(); Log.i(TAG, "Drm key expiration update: " + expirationTime); mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId, expirationTime); } } } return; default: default: Log.e(TAG, "Unknown message type " + msg.what); Log.e(TAG, "Unknown message type " + msg.what); return; return; Loading @@ -333,7 +513,21 @@ public final class MediaDrm { } } } } /* /** * Parse a list of KeyStatus objects from an event parcel */ private List<KeyStatus> keyStatusListFromParcel(Parcel parcel) { int nelems = parcel.readInt(); List<KeyStatus> keyStatusList = new ArrayList(nelems); while (nelems-- > 0) { byte[] keyId = parcel.createByteArray(); int keyStatusCode = parcel.readInt(); keyStatusList.add(new KeyStatus(keyId, keyStatusCode)); } return keyStatusList; } /** * This method is called from native code when an event occurs. This method * This method is called from native code when an event occurs. This method * just uses the EventHandler system to post the event back to the main app thread. * just uses the EventHandler system to post the event back to the main app thread. * We use a weak reference to the original MediaPlayer object so that the native * We use a weak reference to the original MediaPlayer object so that the native Loading @@ -341,14 +535,14 @@ public final class MediaDrm { * the cookie passed to native_setup().) * the cookie passed to native_setup().) */ */ private static void postEventFromNative(Object mediadrm_ref, private static void postEventFromNative(Object mediadrm_ref, int eventType, int extra, Object obj) int what, int eventType, int extra, Object obj) { { MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get(); MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get(); if (md == null) { if (md == null) { return; return; } } if (md.mEventHandler != null) { if (md.mEventHandler != null) { Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj); Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj); md.mEventHandler.sendMessage(m); md.mEventHandler.sendMessage(m); } } } } Loading Loading @@ -404,7 +598,7 @@ public final class MediaDrm { /** /** * Contains the opaque data an app uses to request keys from a license server * Contains the opaque data an app uses to request keys from a license server */ */ public final static class KeyRequest { public static final class KeyRequest { private byte[] mData; private byte[] mData; private String mDefaultUrl; private String mDefaultUrl; private int mRequestType; private int mRequestType; Loading Loading @@ -521,7 +715,7 @@ public final class MediaDrm { * Contains the opaque data an app uses to request a certificate from a provisioning * Contains the opaque data an app uses to request a certificate from a provisioning * server * server */ */ public final static class ProvisionRequest { public static final class ProvisionRequest { ProvisionRequest() {} ProvisionRequest() {} /** /** Loading Loading @@ -812,7 +1006,7 @@ public final class MediaDrm { * * * @hide - not part of the public API at this time * @hide - not part of the public API at this time */ */ public final static class CertificateRequest { public static final class CertificateRequest { private byte[] mData; private byte[] mData; private String mDefaultUrl; private String mDefaultUrl; Loading Loading @@ -860,7 +1054,7 @@ public final class MediaDrm { * * * @hide - not part of the public API at this time * @hide - not part of the public API at this time */ */ public final static class Certificate { public static final class Certificate { Certificate() {} Certificate() {} /** /** Loading
media/jni/android_media_MediaDrm.cpp +29 −4 Original line number Original line Diff line number Diff line Loading @@ -96,6 +96,12 @@ struct EventTypes { jint kEventSessionReclaimed; jint kEventSessionReclaimed; } gEventTypes; } gEventTypes; struct EventWhat { jint kWhatDrmEvent; jint kWhatExpirationUpdate; jint kWhatKeysChange; } gEventWhat; struct KeyTypes { struct KeyTypes { jint kKeyTypeStreaming; jint kKeyTypeStreaming; jint kKeyTypeOffline; jint kKeyTypeOffline; Loading Loading @@ -186,25 +192,37 @@ JNIDrmListener::~JNIDrmListener() void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) const Parcel *obj) { { jint jeventType; jint jwhat; jint jeventType = 0; // translate DrmPlugin event types into their java equivalents // translate DrmPlugin event types into their java equivalents switch (eventType) { switch (eventType) { case DrmPlugin::kDrmPluginEventProvisionRequired: case DrmPlugin::kDrmPluginEventProvisionRequired: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventProvisionRequired; jeventType = gEventTypes.kEventProvisionRequired; break; break; case DrmPlugin::kDrmPluginEventKeyNeeded: case DrmPlugin::kDrmPluginEventKeyNeeded: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventKeyRequired; jeventType = gEventTypes.kEventKeyRequired; break; break; case DrmPlugin::kDrmPluginEventKeyExpired: case DrmPlugin::kDrmPluginEventKeyExpired: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventKeyExpired; jeventType = gEventTypes.kEventKeyExpired; break; break; case DrmPlugin::kDrmPluginEventVendorDefined: case DrmPlugin::kDrmPluginEventVendorDefined: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventVendorDefined; jeventType = gEventTypes.kEventVendorDefined; break; break; case DrmPlugin::kDrmPluginEventSessionReclaimed: case DrmPlugin::kDrmPluginEventSessionReclaimed: jwhat = gEventWhat.kWhatDrmEvent; jeventType = gEventTypes.kEventSessionReclaimed; jeventType = gEventTypes.kEventSessionReclaimed; break; break; case DrmPlugin::kDrmPluginEventExpirationUpdate: jwhat = gEventWhat.kWhatExpirationUpdate; break; case DrmPlugin::kDrmPluginEventKeysChange: jwhat = gEventWhat.kWhatKeysChange; break; default: default: ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); return; return; Loading @@ -217,7 +235,7 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, Parcel* nativeParcel = parcelForJavaObject(env, jParcel); Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, gFields.post_event, mObject, env->CallStaticVoidMethod(mClass, gFields.post_event, mObject, jeventType, extra, jParcel); jwhat, jeventType, extra, jParcel); env->DeleteLocalRef(jParcel); env->DeleteLocalRef(jParcel); } } } } Loading Loading @@ -573,7 +591,7 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { FIND_CLASS(clazz, "android/media/MediaDrm"); FIND_CLASS(clazz, "android/media/MediaDrm"); GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", "(Ljava/lang/Object;IILjava/lang/Object;)V"); "(Ljava/lang/Object;IIILjava/lang/Object;)V"); jfieldID field; jfieldID field; GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); Loading @@ -587,6 +605,13 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I"); GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I"); gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field); gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I"); gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I"); gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEYS_CHANGE", "I"); gEventWhat.kWhatKeysChange = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); Loading Loading @@ -837,7 +862,7 @@ static jobject android_media_MediaDrm_getKeyRequest( env->SetIntField(keyObj, gFields.keyRequest.requestType, env->SetIntField(keyObj, gFields.keyRequest.requestType, gKeyRequestTypes.kKeyRequestTypeRelease); gKeyRequestTypes.kKeyRequestTypeRelease); break; break; case DrmPlugin::kKeyRequestType_Unknown: default: throwStateException(env, "DRM plugin failure: unknown key request type", throwStateException(env, "DRM plugin failure: unknown key request type", ERROR_DRM_UNKNOWN); ERROR_DRM_UNKNOWN); break; break; Loading