diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/MediaCodecInfo.java | 14 | ||||
-rw-r--r-- | media/java/android/media/MediaDrm.java | 437 | ||||
-rw-r--r-- | media/java/android/media/MediaDrmException.java | 2 | ||||
-rw-r--r-- | media/java/android/media/RemoteControlClient.java | 21 | ||||
-rw-r--r-- | media/jni/android_media_MediaDrm.cpp | 69 |
5 files changed, 383 insertions, 160 deletions
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 1501c79..df87db3 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -44,7 +44,16 @@ public final class MediaCodecInfo { return MediaCodecList.getSupportedTypes(mIndex); } + /** + * Encapsulates the capabilities of a given codec component, + * i.e. what profile/level combinations it supports and what colorspaces + * it is capable of providing the decoded data in. + */ public static final class CodecCapabilities { + // Enumerates supported profile/level combinations as defined + // by the type of encoded data. These combinations impose restrictions + // on video resolution, bitrate... and limit the available encoder tools + // such as B-frame support, arithmetic coding... public CodecProfileLevel[] profileLevels; // from OMX_COLOR_FORMATTYPE @@ -219,6 +228,11 @@ public final class MediaCodecInfo { public int level; }; + /** + * Enumerates the capabilities of the codec component. Since a single + * component can support data of a variety of types, the type has to be + * specified to yield a meaningful result. + */ public final CodecCapabilities getCapabilitiesForType( String type) { return MediaCodecList.getCodecCapabilities(mIndex, type); diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 6872278..31fbc4a 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -29,25 +29,69 @@ import android.os.Parcel; import android.util.Log; /** - * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto} - * to obtain keys for decrypting protected media data. - * - * Crypto schemes are assigned 16 byte UUIDs, - * the method {@link #isCryptoSchemeSupported} can be used to query if a given - * scheme is supported on the device. - * + * MediaDrm can be used to obtain keys for decrypting protected media streams, in + * conjunction with {@link android.media.MediaCrypto}. The MediaDrm APIs + * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but + * may also be used to implement other encryption schemes. + * <p> + * Encrypted content is prepared using an encryption server and stored in a content + * library. The encrypted content is streamed or downloaded from the content library to + * client devices via content servers. Licenses to view the content are obtained from + * a License Server. + * <p> + * <p><img src="../../../images/mediadrm_overview.png" + * alt="MediaDrm Overview diagram" + * border="0" /></p> + * <p> + * Keys are requested from the license server using a key request. The key + * response is delivered to the client app, which provides the response to the + * MediaDrm API. + * <p> + * A Provisioning server may be required to distribute device-unique credentials to + * the devices. + * <p> + * Enforcing requirements related to the number of devices that may play content + * simultaneously can be performed either through key renewal or using the secure + * stop methods. + * <p> + * The following sequence diagram shows the interactions between the objects + * involved while playing back encrypted content: + * <p> + * <p><img src="../../../images/mediadrm_decryption_sequence.png" + * alt="MediaDrm Overview diagram" + * border="0" /></p> + * <p> + * The app first constructs {@link android.media.MediaExtractor} and + * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID, + * typically from metadata in the content, and uses this UUID to construct an instance + * of a MediaDrm object that is able to support the DRM scheme required by the content. + * Crypto schemes are assigned 16 byte UUIDs. The method {@link #isCryptoSchemeSupported} + * can be used to query if a given scheme is supported on the device. + * <p> + * The app calls {@link #openSession} to generate a sessionId that will uniquely identify + * the session in subsequent interactions. The app next uses the MediaDrm object to + * obtain a key request message and send it to the license server, then provide + * the server's response to the MediaDrm object. + * <p> + * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and + * sessionId. The MediaCrypto object is registered with the MediaCodec in the + * {@link MediaCodec.#configure} method to enable the codec to decrypt content. + * <p> + * When the app has constructed {@link android.media.MediaExtractor}, + * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects, + * it proceeds to pull samples from the extractor and queue them into the decoder. For + * encrypted content, the samples returned from the extractor remain encrypted, they + * are only decrypted when the samples are delivered to the decoder. + * <p> * <a name="Callbacks"></a> * <h3>Callbacks</h3> - * <p>Applications may want to register for informational events in order - * to be informed of some internal state update during playback or streaming. + * <p>Applications should register for informational events in order + * to be informed of key state updates during playback or streaming. * Registration for these events is done via a call to - * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener, - * In order to receive the respective callback - * associated with this listener, applications are required to create + * {@link #setOnEventListener}. In order to receive the respective + * callback associated with this listener, applications are required to create * MediaDrm objects on a thread with its own Looper running (main UI * thread by default has a Looper running). - * - * @hide -- don't expose yet */ public final class MediaDrm { @@ -116,7 +160,7 @@ public final class MediaDrm { /** * Interface definition for a callback to be invoked when a drm event - * occurs. + * occurs */ public interface OnEventListener { @@ -132,10 +176,30 @@ public final class MediaDrm { void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data); } - public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1; - public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2; - public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3; - public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4; + /** + * This event type indicates that the app needs to request a certificate from + * the provisioning server. The request message data is obtained using + * {@link #getProvisionRequest} + */ + public static final int EVENT_PROVISION_REQUIRED = 1; + + /** + * This event type indicates that the app needs to request keys from a license + * server. The request message data is obtained using {@link #getKeyRequest}. + */ + public static final int EVENT_KEY_REQUIRED = 2; + + /** + * This event type indicates that the licensed usage duration for keys in a session + * has expired. The keys are no longer valid. + */ + public static final int EVENT_KEY_EXPIRED = 3; + + /** + * This event may indicate some specific vendor-defined condition, see your + * DRM provider documentation for details + */ + public static final int EVENT_VENDOR_DEFINED = 4; private static final int DRM_EVENT = 200; @@ -183,7 +247,7 @@ public final class MediaDrm { } /* - * Called from native code when an interesting event happens. 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. * We use a weak reference to the original MediaPlayer object so that the native * code is safe from the object disappearing from underneath it. (This is @@ -203,89 +267,117 @@ public final class MediaDrm { } /** - * Open a new session with the MediaDrm object. A session ID is returned. + * Open a new session with the MediaDrm object. A session ID is returned. */ - public native byte[] openSession() throws MediaDrmException; + public native byte[] openSession(); /** - * Close a session on the MediaDrm object that was previously opened - * with {@link #openSession}. + * Close a session on the MediaDrm object that was previously opened + * with {@link #openSession}. */ - public native void closeSession(byte[] sessionId) throws MediaDrmException; + public native void closeSession(byte[] sessionId); - public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1; - public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2; - public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3; + /** + * This key request type species that the keys will be for online use, they will + * not be saved to the device for subsequent use when the device is not connected + * to a network. + */ + public static final int KEY_TYPE_STREAMING = 1; + + /** + * This key request type specifies that the keys will be for offline use, they + * will be saved to the device for use when the device is not connected to a network. + */ + public static final int KEY_TYPE_OFFLINE = 2; + + /** + * This key request type specifies that previously saved offline keys should be released. + */ + public static final int KEY_TYPE_RELEASE = 3; + + /** + * Contains the opaque data an app uses to request keys from a license server + */ + public final static class KeyRequest { + KeyRequest() {} + + /** + * Get the opaque message data + */ + public byte[] getData() { return mData; } + + /** + * Get the default URL to use when sending the key request message to a + * server, if known. The app may prefer to use a different license + * server URL from other sources. + */ + public String getDefaultUrl() { return mDefaultUrl; } - public final class KeyRequest { - public KeyRequest() {} - public byte[] data; - public String defaultUrl; + private byte[] mData; + private String mDefaultUrl; }; /** * A key request/response exchange occurs between the app and a license server * to obtain or release keys used to decrypt encrypted content. + * <p> * getKeyRequest() is used to obtain an opaque key request byte array that is * delivered to the license server. The opaque key request byte array is returned * in KeyRequest.data. The recommended URL to deliver the key request to is * returned in KeyRequest.defaultUrl. - * + * <p> * After the app has received the key request response from the server, * it should deliver to the response to the DRM engine plugin using the method * {@link #provideKeyResponse}. * * @param scope may be a sessionId or a keySetId, depending on the specified keyType. - * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE, + * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, * scope should be set to the sessionId the keys will be provided to. When the keyType - * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys + * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys * being released. Releasing keys from a device invalidates them for all sessions. * @param init container-specific data, its meaning is interpreted based on the * mime type provided in the mimeType parameter. It could contain, for example, * the content ID, key ID or other data obtained from the content metadata that is * required in generating the key request. init may be null when keyType is - * MEDIA_DRM_KEY_TYPE_RELEASE. + * KEY_TYPE_RELEASE. * @param mimeType identifies the mime type of the content * @param keyType specifes the type of the request. The request may be to acquire * keys for streaming or offline content, or to release previously acquired * keys, which are identified by a keySetId. - * @param optionalParameters are included in the key request message to * allow a client application to provide additional message parameters to the server. */ public native KeyRequest getKeyRequest(byte[] scope, byte[] init, String mimeType, int keyType, - HashMap<String, String> optionalParameters) - throws MediaDrmException; + HashMap<String, String> optionalParameters); + /** * A key response is received from the license server by the app, then it is * provided to the DRM engine plugin using provideKeyResponse. The byte array * returned is a keySetId that can be used to later restore the keys to a new - * session with the method {@link restoreKeys}, enabling offline key use. + * session with the method {@link #restoreKeys}, enabling offline key use. * * @param sessionId the session ID for the DRM session * @param response the byte array response from the server */ - public native byte[] provideKeyResponse(byte[] sessionId, byte[] response) - throws MediaDrmException; + public native byte[] provideKeyResponse(byte[] sessionId, byte[] response); /** * Restore persisted offline keys into a new session. keySetId identifies the - * keys to load, obtained from a prior call to {@link provideKeyResponse}. + * keys to load, obtained from a prior call to {@link #provideKeyResponse}. * * @param sessionId the session ID for the DRM session * @param keySetId identifies the saved key set to restore */ - public native void restoreKeys(byte[] sessionId, byte[] keySetId) - throws MediaDrmException; + public native void restoreKeys(byte[] sessionId, byte[] keySetId); /** * Remove the current keys from a session. * * @param sessionId the session ID for the DRM session */ - public native void removeKeys(byte[] sessionId) throws MediaDrmException; + public native void removeKeys(byte[] sessionId); /** * Request an informative description of the key status for the session. The status is @@ -296,25 +388,41 @@ public final class MediaDrm { * * @param sessionId the session ID for the DRM session */ - public native HashMap<String, String> queryKeyStatus(byte[] sessionId) - throws MediaDrmException; + public native HashMap<String, String> queryKeyStatus(byte[] sessionId); + + /** + * Contains the opaque data an app uses to request a certificate from a provisioning + * server + */ + public final static class ProvisionRequest { + ProvisionRequest() {} + + /** + * Get the opaque message data + */ + public byte[] getData() { return mData; } + + /** + * Get the default URL to use when sending the provision request + * message to a server, if known. The app may prefer to use a different + * provisioning server URL obtained from other sources. + */ + public String getDefaultUrl() { return mDefaultUrl; } - public final class ProvisionRequest { - public ProvisionRequest() {} - public byte[] data; - public String defaultUrl; + private byte[] mData; + private String mDefaultUrl; } /** * A provision request/response exchange occurs between the app and a provisioning * server to retrieve a device certificate. If provisionining is required, the - * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler. + * EVENT_PROVISION_REQUIRED event will be sent to the event handler. * getProvisionRequest is used to obtain the opaque provision request byte array that * should be delivered to the provisioning server. The provision request byte array * is returned in ProvisionRequest.data. The recommended URL to deliver the provision * request to is returned in ProvisionRequest.defaultUrl. */ - public native ProvisionRequest getProvisionRequest() throws MediaDrmException; + public native ProvisionRequest getProvisionRequest(); /** * After a provision response is received by the app, it is provided to the DRM @@ -323,92 +431,91 @@ public final class MediaDrm { * @param response the opaque provisioning response byte array to provide to the * DRM engine plugin. */ - public native void provideProvisionResponse(byte[] response) - throws MediaDrmException; + public native void provideProvisionResponse(byte[] response); /** - * A means of enforcing the contractual requirement for a concurrent stream limit - * per subscriber across devices is provided via SecureStop. SecureStop is a means - * of securely monitoring the lifetime of sessions. Since playback on a device can - * be interrupted due to reboot, power failure, etc. a means of persisting the - * lifetime information on the device is needed. - * - * A signed version of the sessionID is written to persistent storage on the device - * when each MediaCrypto object is created. The sessionID is signed by the device - * private key to prevent tampering. - * + * A means of enforcing limits on the number of concurrent streams per subscriber + * across devices is provided via SecureStop. This is achieved by securely + * monitoring the lifetime of sessions. + * <p> + * Information from the server related to the current playback session is written + * to persistent storage on the device when each MediaCrypto object is created. + * <p> * In the normal case, playback will be completed, the session destroyed and the - * Secure Stops will be queried. The App queries secure stops and forwards the + * Secure Stops will be queried. The app queries secure stops and forwards the * secure stop message to the server which verifies the signature and notifies the * server side database that the session destruction has been confirmed. The persisted * record on the client is only removed after positive confirmation that the server * received the message using releaseSecureStops(). */ - public native List<byte[]> getSecureStops() throws MediaDrmException; + public native List<byte[]> getSecureStops(); /** * Process the SecureStop server response message ssRelease. After authenticating - * the message, remove the SecureStops identiied in the response. + * the message, remove the SecureStops identified in the response. * * @param ssRelease the server response indicating which secure stops to release */ - public native void releaseSecureStops(byte[] ssRelease) - throws MediaDrmException; + public native void releaseSecureStops(byte[] ssRelease); /** - * Read a DRM engine plugin property value, given the property name string. There are - * several forms of property access functions, depending on the data type returned. - * + * String property name: identifies the maker of the DRM engine plugin + */ + public static final String PROPERTY_VENDOR = "vendor"; + + /** + * String property name: identifies the version of the DRM engine plugin + */ + public static final String PROPERTY_VERSION = "version"; + + /** + * String property name: describes the DRM engine plugin + */ + public static final String PROPERTY_DESCRIPTION = "description"; + + /** + * String property name: a comma-separated list of cipher and mac algorithms + * supported by CryptoSession. The list may be empty if the DRM engine + * plugin does not support CryptoSession operations. + */ + public static final String PROPERTY_ALGORITHM = "algorithm"; + + /** + * Read a DRM engine plugin String property value, given the property name string. + * <p> * Standard fields names are: - * vendor String - identifies the maker of the DRM engine plugin - * version String - identifies the version of the DRM engine plugin - * description String - describes the DRM engine plugin - * deviceUniqueId byte[] - The device unique identifier is established during device - * provisioning and provides a means of uniquely identifying - * each device - * algorithms String - a comma-separate list of cipher and mac algorithms supported - * by CryptoSession. The list may be empty if the DRM engine - * plugin does not support CryptoSession operations. + * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION}, + * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHM} */ - public native String getPropertyString(String propertyName) - throws MediaDrmException; + public native String getPropertyString(String propertyName); - public native byte[] getPropertyByteArray(String propertyName) - throws MediaDrmException; /** - * Write a DRM engine plugin property value. There are several forms of - * property setting functions, depending on the data type being set. + * The device unique identifier is established during device provisioning and + * provides a means of uniquely identifying each device */ - public native void setPropertyString(String propertyName, String value) - throws MediaDrmException; + public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId"; + + /** + * Read a DRM engine plugin byte array property value, given the property name string. + * <p> + * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID} + */ + public native byte[] getPropertyByteArray(String propertyName); - public native void setPropertyByteArray(String propertyName, byte[] value) - throws MediaDrmException; /** - * In addition to supporting decryption of DASH Common Encrypted Media, the - * MediaDrm APIs provide the ability to securely deliver session keys from - * an operator's session key server to a client device, based on the factory-installed - * root of trust, and provide the ability to do encrypt, decrypt, sign and verify - * with the session key on arbitrary user data. - * - * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods - * based on the established session keys. These keys are exchanged using the - * getKeyRequest/provideKeyResponse methods. - * - * Applications of this capability could include securing various types of - * purchased or private content, such as applications, books and other media, - * photos or media delivery protocols. - * - * Operators can create session key servers that are functionally similar to a - * license key server, except that instead of receiving license key requests and - * providing encrypted content keys which are used specifically to decrypt A/V media - * content, the session key server receives session key requests and provides - * encrypted session keys which can be used for general purpose crypto operations. + * Set a DRM engine plugin String property value. + */ + public native void setPropertyString(String propertyName, String value); + + /** + * Set a DRM engine plugin byte array property value. */ + public native void setPropertyByteArray(String propertyName, byte[] value); + private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId, String algorithm); @@ -429,61 +536,112 @@ public final class MediaDrm { byte[] keyId, byte[] message, byte[] signature); + /** + * In addition to supporting decryption of DASH Common Encrypted Media, the + * MediaDrm APIs provide the ability to securely deliver session keys from + * an operator's session key server to a client device, based on the factory-installed + * root of trust, and then perform encrypt, decrypt, sign and verify operations + * with the session key on arbitrary user data. + * <p> + * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods + * based on the established session keys. These keys are exchanged using the + * getKeyRequest/provideKeyResponse methods. + * <p> + * Applications of this capability could include securing various types of + * purchased or private content, such as applications, books and other media, + * photos or media delivery protocols. + * <p> + * Operators can create session key servers that are functionally similar to a + * license key server, except that instead of receiving license key requests and + * providing encrypted content keys which are used specifically to decrypt A/V media + * content, the session key server receives session key requests and provides + * encrypted session keys which can be used for general purpose crypto operations. + * <p> + * A CryptoSession is obtained using {@link #getCryptoSession} + */ public final class CryptoSession { private MediaDrm mDrm; private byte[] mSessionId; - /** - * Construct a CryptoSession which can be used to encrypt, decrypt, - * sign and verify messages or data using the session keys established - * for the session using methods {@link getKeyRequest} and - * {@link provideKeyResponse} using a session key server. - * - * @param sessionId the session ID for the session containing keys - * to be used for encrypt, decrypt, sign and/or verify - * - * @param cipherAlgorithm the algorithm to use for encryption and - * decryption ciphers. The algorithm string conforms to JCA Standard - * Names for Cipher Transforms and is case insensitive. For example - * "AES/CBC/PKCS5Padding". - * - * @param macAlgorithm the algorithm to use for sign and verify - * The algorithm string conforms to JCA Standard Names for Mac - * Algorithms and is case insensitive. For example "HmacSHA256". - * - * The list of supported algorithms for a DRM engine plugin can be obtained - * using the method {@link getPropertyString("algorithms")} - */ - - public CryptoSession(MediaDrm drm, byte[] sessionId, - String cipherAlgorithm, String macAlgorithm) - throws MediaDrmException { + CryptoSession(MediaDrm drm, byte[] sessionId, + String cipherAlgorithm, String macAlgorithm) + { mSessionId = sessionId; mDrm = drm; setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm); setMacAlgorithmNative(drm, sessionId, macAlgorithm); } + /** + * Encrypt data using the CryptoSession's cipher algorithm + * + * @param keyid specifies which key to use + * @param input the data to encrypt + * @param iv the initialization vector to use for the cipher + */ public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) { return encryptNative(mDrm, mSessionId, keyid, input, iv); } + /** + * Decrypt data using the CryptoSessions's cipher algorithm + * + * @param keyid specifies which key to use + * @param input the data to encrypt + * @param iv the initialization vector to use for the cipher + */ public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) { return decryptNative(mDrm, mSessionId, keyid, input, iv); } + /** + * Sign data using the CryptoSessions's mac algorithm. + * + * @param keyid specifies which key to use + * @param message the data for which a signature is to be computed + */ public byte[] sign(byte[] keyid, byte[] message) { return signNative(mDrm, mSessionId, keyid, message); } + + /** + * Verify a signature using the CryptoSessions's mac algorithm. Return true + * if the signatures match, false if they do no. + * + * @param keyid specifies which key to use + * @param message the data to verify + * @param signature the reference signature which will be compared with the + * computed signature + */ public boolean verify(byte[] keyid, byte[] message, byte[] signature) { return verifyNative(mDrm, mSessionId, keyid, message, signature); } }; + /** + * Obtain a CryptoSession object which can be used to encrypt, decrypt, + * sign and verify messages or data using the session keys established + * for the session using methods {@link #getKeyRequest} and + * {@link #provideKeyResponse} using a session key server. + * + * @param sessionId the session ID for the session containing keys + * to be used for encrypt, decrypt, sign and/or verify + * @param cipherAlgorithm the algorithm to use for encryption and + * decryption ciphers. The algorithm string conforms to JCA Standard + * Names for Cipher Transforms and is case insensitive. For example + * "AES/CBC/NoPadding". + * @param macAlgorithm the algorithm to use for sign and verify + * The algorithm string conforms to JCA Standard Names for Mac + * Algorithms and is case insensitive. For example "HmacSHA256". + * <p> + * The list of supported algorithms for a DRM engine plugin can be obtained + * using the method {@link #getPropertyString} with the property name + * "algorithms". + */ public CryptoSession getCryptoSession(byte[] sessionId, String cipherAlgorithm, String macAlgorithm) - throws MediaDrmException { + { return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm); } @@ -495,8 +653,7 @@ public final class MediaDrm { public native final void release(); private static native final void native_init(); - private native final void native_setup(Object mediadrm_this, byte[] uuid) - throws MediaDrmException; + private native final void native_setup(Object mediadrm_this, byte[] uuid); private native final void native_finalize(); diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java index 6f81f90..d6f5ff4 100644 --- a/media/java/android/media/MediaDrmException.java +++ b/media/java/android/media/MediaDrmException.java @@ -19,8 +19,6 @@ package android.media; /** * Exception thrown if MediaDrm object could not be instantiated for * whatever reason. - * - * @hide -- don't expose yet */ public final class MediaDrmException extends Exception { public MediaDrmException(String detailMessage) { diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 4a5e82e..61a0134 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -999,7 +999,7 @@ public class RemoteControlClient if (mEventHandler != null) { // signal new client mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN); - mEventHandler.dispatchMessage( + mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN, /*arg1*/ generationId, /*arg2, ignored*/ 0)); // send the information @@ -1007,12 +1007,12 @@ public class RemoteControlClient mEventHandler.removeMessages(MSG_REQUEST_METADATA); mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL); mEventHandler.removeMessages(MSG_REQUEST_ARTWORK); - mEventHandler.dispatchMessage( + mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE)); - mEventHandler.dispatchMessage( + mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL)); - mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA)); - mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK)); + mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA)); + mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK)); } } @@ -1020,7 +1020,7 @@ public class RemoteControlClient // only post messages, we can't block here if (mEventHandler != null) { mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN); - mEventHandler.dispatchMessage(mEventHandler.obtainMessage( + mEventHandler.sendMessage(mEventHandler.obtainMessage( MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/)); } } @@ -1028,7 +1028,7 @@ public class RemoteControlClient public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) { // only post messages, we can't block here if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.dispatchMessage(mEventHandler.obtainMessage( + mEventHandler.sendMessage(mEventHandler.obtainMessage( MSG_PLUG_DISPLAY, w, h, rcd)); } } @@ -1036,7 +1036,7 @@ public class RemoteControlClient public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) { // only post messages, we can't block here if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.dispatchMessage(mEventHandler.obtainMessage( + mEventHandler.sendMessage(mEventHandler.obtainMessage( MSG_UNPLUG_DISPLAY, rcd)); } } @@ -1044,7 +1044,7 @@ public class RemoteControlClient public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) { // only post messages, we can't block here if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.dispatchMessage(mEventHandler.obtainMessage( + mEventHandler.sendMessage(mEventHandler.obtainMessage( MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd)); } } @@ -1053,7 +1053,7 @@ public class RemoteControlClient // only post messages, we can't block here if (mEventHandler != null) { mEventHandler.removeMessages(MSG_SEEK_TO); - mEventHandler.dispatchMessage(mEventHandler.obtainMessage( + mEventHandler.sendMessage(mEventHandler.obtainMessage( MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */, new Long(timeMs))); } @@ -1145,6 +1145,7 @@ public class RemoteControlClient break; case MSG_SEEK_TO: onSeekTo(msg.arg1, ((Long)msg.obj).longValue()); + break; default: Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler"); } diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index c32ba9d..d1b499e 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -30,6 +30,7 @@ #include <media/IDrm.h> #include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaErrors.h> namespace android { @@ -191,10 +192,62 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, static bool throwExceptionAsNecessary( JNIEnv *env, status_t err, const char *msg = NULL) { + const char *drmMessage = NULL; + + switch(err) { + case ERROR_DRM_UNKNOWN: + drmMessage = "General DRM error"; + break; + case ERROR_DRM_NO_LICENSE: + drmMessage = "No license"; + break; + case ERROR_DRM_LICENSE_EXPIRED: + drmMessage = "License expired"; + break; + case ERROR_DRM_SESSION_NOT_OPENED: + drmMessage = "Session not opened"; + break; + case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED: + drmMessage = "Not initialized"; + break; + case ERROR_DRM_DECRYPT: + drmMessage = "Decrypt error"; + break; + case ERROR_DRM_CANNOT_HANDLE: + drmMessage = "Unsupported scheme or data format"; + break; + case ERROR_DRM_TAMPER_DETECTED: + drmMessage = "Invalid state"; + break; + case ERROR_DRM_NOT_PROVISIONED: + drmMessage = "Not provisioned"; + break; + case ERROR_DRM_DEVICE_REVOKED: + drmMessage = "Device revoked"; + break; + default: + break; + } + + String8 vendorMessage; + if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { + vendorMessage.format("DRM vendor-defined error: %d", err); + drmMessage = vendorMessage.string(); + } + if (err == BAD_VALUE) { jniThrowException(env, "java/lang/IllegalArgumentException", msg); return true; } else if (err != OK) { + String8 errbuf; + if (drmMessage != NULL) { + if (msg == NULL) { + msg = drmMessage; + } else { + errbuf.format("%s: %s", msg, drmMessage); + msg = errbuf.string(); + } + } jniThrowException(env, "java/lang/IllegalStateException", msg); return true; } @@ -458,22 +511,22 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { "(Ljava/lang/Object;IILjava/lang/Object;)V"); jfieldID field; - GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I"); + GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I"); + GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I"); gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I"); + GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I"); gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I"); + GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I"); gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field); FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); - GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B"); - GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;"); + GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); + GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest"); - GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B"); - GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;"); + GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); + GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); FIND_CLASS(clazz, "java/util/ArrayList"); GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); |