summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaDrmBridge.java455
-rw-r--r--media/base/android/media_drm_bridge.cc95
-rw-r--r--media/base/android/media_drm_bridge.h44
3 files changed, 303 insertions, 291 deletions
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index 59044e4..16fe5028 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -21,6 +21,7 @@ import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.UUID;
@@ -32,22 +33,24 @@ import java.util.UUID;
@JNINamespace("media")
class MediaDrmBridge {
// Implementation Notes:
- // - A media crypto session (mMediaCryptoSessionId) is opened after MediaDrm
+ // - A media crypto session (mMediaCryptoSession) is opened after MediaDrm
// is created. This session will be added to mSessionIds.
- // a) In multiple session mode, this session will only be used to create
- // the MediaCrypto object and it's associated mime type is always null.
+ // a) In multiple session mode, this session will only be used to create
+ // the MediaCrypto object. It's associated mime type is always null and
+ // it's session ID is always INVALID_SESSION_ID.
// b) In single session mode, this session will be used to create the
// MediaCrypto object and will be used to call getKeyRequest() and
- // manage all keys.
- // - Each generateKeyRequest() call creates a new session. All sessions are
+ // manage all keys. The session ID will always be the lastest session
+ // ID passed by the caller.
+ // - Each createSession() call creates a new session. All sessions are
// managed in mSessionIds.
// - Whenever NotProvisionedException is thrown, we will clean up the
// current state and start the provisioning process.
// - When provisioning is finished, we will try to resume suspended
// operations:
// a) Create the media crypto session if it's not created.
- // b) Finish generateKeyRequest() if previous generateKeyRequest() was
- // interrupted by a NotProvisionedException.
+ // b) Finish createSession() if previous createSession() was interrupted
+ // by a NotProvisionedException.
// - Whenever an unexpected error occurred, we'll call release() to release
// all resources and clear all states. In that case all calls to this
// object will be no-op. All public APIs and callbacks should check
@@ -61,32 +64,35 @@ class MediaDrmBridge {
private static final String PRIVACY_MODE = "privacyMode";
private static final String SESSION_SHARING = "sessionSharing";
private static final String ENABLE = "enable";
+ private static final int INVALID_SESSION_ID = 0;
private MediaDrm mMediaDrm;
private long mNativeMediaDrmBridge;
private UUID mSchemeUUID;
private Handler mHandler;
- // In this mode, we only open one session, i.e. mMediaCryptoSessionId, and
- // mSessionIds is always empty.
+ // In this mode, we only open one session, i.e. mMediaCryptoSession.
private boolean mSingleSessionMode;
// A session only for the purpose of creating a MediaCrypto object.
- // This session is opened when generateKeyRequest is called for the first
+ // This session is opened when createSession() is called for the first
// time.
- // - In multiple session mode, all following generateKeyRequest() calls
+ // - In multiple session mode, all following createSession() calls
// should create a new session and use it to call getKeyRequest(). No
// getKeyRequest() should ever be called on this media crypto session.
- // - In single session mode, all generateKeyRequest() calls use the same
- // media crypto session. When generateKeyRequest() is called with a new
+ // - In single session mode, all createSession() calls use the same
+ // media crypto session. When createSession() is called with a new
// initData, previously added keys may not be available anymore.
- private String mMediaCryptoSessionId;
+ private ByteBuffer mMediaCryptoSession;
private MediaCrypto mMediaCrypto;
+ // The map of all opened sessions to their session reference IDs.
+ private HashMap<ByteBuffer, Integer> mSessionIds;
// The map of all opened sessions to their mime types.
- private HashMap<String, String> mSessionIds;
+ private HashMap<ByteBuffer, String> mSessionMimeTypes;
- private ArrayDeque<PendingGkrData> mPendingGkrDataQueue;
+ // The queue of all pending createSession() data.
+ private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue;
private boolean mResetDeviceCredentialsPending;
@@ -97,18 +103,21 @@ class MediaDrmBridge {
// non-native methods and only catch it in public APIs.
private boolean mProvisioningPending;
- /*
- * This class contains data needed to call generateKeyRequest().
+ /**
+ * This class contains data needed to call createSession().
*/
- private static class PendingGkrData {
+ private static class PendingCreateSessionData {
+ private final int mSessionId;
private final byte[] mInitData;
private final String mMimeType;
- private PendingGkrData(byte[] initData, String mimeType) {
+ private PendingCreateSessionData(int sessionId, byte[] initData, String mimeType) {
+ mSessionId = sessionId;
mInitData = initData;
mMimeType = mimeType;
}
+ private int sessionId() { return mSessionId; }
private byte[] initData() { return mInitData; }
private String mimeType() { return mMimeType; }
}
@@ -128,6 +137,21 @@ class MediaDrmBridge {
return new UUID(mostSigBits, leastSigBits);
}
+ /**
+ * Gets session associated with the sessionId.
+ *
+ * @return session if sessionId maps a valid opened session. Returns null
+ * otherwise.
+ */
+ private ByteBuffer getSession(int sessionId) {
+ for (ByteBuffer session : mSessionIds.keySet()) {
+ if (mSessionIds.get(session) == sessionId) {
+ return session;
+ }
+ }
+ return null;
+ }
+
private MediaDrmBridge(UUID schemeUUID, String securityLevel, long nativeMediaDrmBridge,
boolean singleSessionMode) throws android.media.UnsupportedSchemeException {
mSchemeUUID = schemeUUID;
@@ -135,8 +159,9 @@ class MediaDrmBridge {
mNativeMediaDrmBridge = nativeMediaDrmBridge;
mHandler = new Handler();
mSingleSessionMode = singleSessionMode;
- mSessionIds = new HashMap<String, String>();
- mPendingGkrDataQueue = new ArrayDeque<PendingGkrData>();
+ mSessionIds = new HashMap<ByteBuffer, Integer>();
+ mSessionMimeTypes = new HashMap<ByteBuffer, String>();
+ mPendingCreateSessionDataQueue = new ArrayDeque<PendingCreateSessionData>();
mResetDeviceCredentialsPending = false;
mProvisioningPending = false;
@@ -152,7 +177,7 @@ class MediaDrmBridge {
}
// We could open a MediaCrypto session here to support faster start of
- // clear lead (no need to wait for generateKeyRequest()). But on
+ // clear lead (no need to wait for createSession()). But on
// Android, memory and battery resources are precious and we should
// only create a session when we are sure we'll use it.
// TODO(xhwang): Investigate other options to support fast start.
@@ -167,34 +192,32 @@ class MediaDrmBridge {
if (mMediaDrm == null) {
return false;
}
- assert(!mProvisioningPending);
- assert(mMediaCryptoSessionId == null);
- assert(mMediaCrypto == null);
+ assert (!mProvisioningPending);
+ assert (mMediaCryptoSession == null);
+ assert (mMediaCrypto == null);
// Open media crypto session.
- mMediaCryptoSessionId = openSession();
- if (mMediaCryptoSessionId == null) {
+ mMediaCryptoSession = openSession();
+ if (mMediaCryptoSession == null) {
Log.e(TAG, "Cannot create MediaCrypto Session.");
return false;
}
- Log.d(TAG, "MediaCrypto Session created: " + mMediaCryptoSessionId);
+ Log.d(TAG, "MediaCrypto Session created: " + mMediaCryptoSession);
// Create MediaCrypto object.
try {
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
- final byte[] mediaCryptoSession = mMediaCryptoSessionId.getBytes("UTF-8");
+ final byte[] mediaCryptoSession = mMediaCryptoSession.array();
mMediaCrypto = new MediaCrypto(mSchemeUUID, mediaCryptoSession);
- assert(mMediaCrypto != null);
+ assert (mMediaCrypto != null);
Log.d(TAG, "MediaCrypto successfully created!");
- mSessionIds.put(mMediaCryptoSessionId, null);
+ mSessionIds.put(mMediaCryptoSession, INVALID_SESSION_ID);
// Notify the native code that MediaCrypto is ready.
nativeOnMediaCryptoReady(mNativeMediaDrmBridge);
return true;
} else {
Log.e(TAG, "Cannot create MediaCrypto for unsupported scheme.");
}
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "Cannot create MediaCrypto", e);
} catch (android.media.MediaCryptoException e) {
Log.e(TAG, "Cannot create MediaCrypto", e);
}
@@ -204,39 +227,32 @@ class MediaDrmBridge {
}
/**
- * Open a new session and return the session ID string.
+ * Open a new session..
*
- * @return null if unexpected error happened.
+ * @return the session opened. Returns null if unexpected error happened.
*/
- private String openSession() throws android.media.NotProvisionedException {
- assert(mMediaDrm != null);
- String sessionId = null;
+ private ByteBuffer openSession() throws android.media.NotProvisionedException {
+ assert (mMediaDrm != null);
try {
- final byte[] session = mMediaDrm.openSession();
- sessionId = new String(session, "UTF-8");
+ byte[] session = mMediaDrm.openSession();
+ // ByteBuffer.wrap() is backed by the byte[]. Make a clone here in
+ // case the underlying byte[] is modified.
+ return ByteBuffer.wrap(session.clone());
} catch (java.lang.RuntimeException e) { // TODO(xhwang): Drop this?
Log.e(TAG, "Cannot open a new session", e);
release();
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "Cannot open a new session", e);
- release();
+ return null;
}
- return sessionId;
}
/**
* Close a session.
*
- * @param sesstionIdString ID of the session to be closed.
+ * @param session to be closed.
*/
- private void closeSession(String sesstionIdString) {
- assert(mMediaDrm != null);
- try {
- final byte[] session = sesstionIdString.getBytes("UTF-8");
- mMediaDrm.closeSession(session);
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "Failed to close session", e);
- }
+ private void closeSession(ByteBuffer session) {
+ assert (mMediaDrm != null);
+ mMediaDrm.closeSession(session.array());
}
/**
@@ -318,17 +334,19 @@ class MediaDrmBridge {
// Do not reset mHandler and mNativeMediaDrmBridge so that we can still
// post KeyError back to native code.
- mPendingGkrDataQueue.clear();
- mPendingGkrDataQueue = null;
+ mPendingCreateSessionDataQueue.clear();
+ mPendingCreateSessionDataQueue = null;
- for (String sessionId : mSessionIds.keySet()) {
- closeSession(sessionId);
+ for (ByteBuffer session : mSessionIds.keySet()) {
+ closeSession(session);
}
mSessionIds.clear();
mSessionIds = null;
+ mSessionMimeTypes.clear();
+ mSessionMimeTypes = null;
// This session was closed in the "for" loop above.
- mMediaCryptoSessionId = null;
+ mMediaCryptoSession = null;
if (mMediaCrypto != null) {
mMediaCrypto.release();
@@ -342,62 +360,55 @@ class MediaDrmBridge {
}
/**
- * Get a key request and post an asynchronous task to the native side
- * with the response message upon success, or with the key error if
- * unexpected error happened.
+ * Get a key request.
*
- * @param sessionId ID of the session on which we need to get the key request.
+ * @param session Session on which we need to get the key request.
* @param data Data needed to get the key request.
* @param mime Mime type to get the key request.
*
- * @return whether a key request is successfully obtained.
+ * @return the key request.
*/
- private boolean getKeyRequest(String sessionId, byte[] data, String mime)
+ private MediaDrm.KeyRequest getKeyRequest(ByteBuffer session, byte[] data, String mime)
throws android.media.NotProvisionedException {
- assert(mMediaDrm != null);
- assert(mMediaCrypto != null);
- assert(!mProvisioningPending);
-
- try {
- final byte[] session = sessionId.getBytes("UTF-8");
- HashMap<String, String> optionalParameters = new HashMap<String, String>();
- final MediaDrm.KeyRequest request = mMediaDrm.getKeyRequest(
- session, data, mime, MediaDrm.KEY_TYPE_STREAMING, optionalParameters);
- Log.e(TAG, "Got key request successfully.");
- onKeyMessage(sessionId, request.getData(), request.getDefaultUrl());
- return true;
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "Cannot get key request", e);
- }
- onKeyError(sessionId);
- release();
- return false;
+ assert (mMediaDrm != null);
+ assert (mMediaCrypto != null);
+ assert (!mProvisioningPending);
+
+ HashMap<String, String> optionalParameters = new HashMap<String, String>();
+ MediaDrm.KeyRequest request = mMediaDrm.getKeyRequest(
+ session.array(), data, mime, MediaDrm.KEY_TYPE_STREAMING, optionalParameters);
+ String result = (request != null) ? "successed" : "failed";
+ Log.d(TAG, "getKeyRequest " + result + "!");
+ return request;
}
/**
- * Save |initData| and |mime| to |mPendingGkrDataQueue| so that we can
- * resume the generateKeyRequest() call later.
+ * Save data to |mPendingCreateSessionDataQueue| so that we can resume the
+ * createSession() call later.
*/
- private void savePendingGkrData(byte[] initData, String mime) {
- Log.d(TAG, "savePendingGkrData()");
- mPendingGkrDataQueue.offer(new PendingGkrData(initData, mime));
+ private void savePendingCreateSessionData(int sessionId, byte[] initData, String mime) {
+ Log.d(TAG, "savePendingCreateSessionData()");
+ mPendingCreateSessionDataQueue.offer(
+ new PendingCreateSessionData(sessionId, initData, mime));
}
/**
- * Process all pending generateKeyRequest() calls synchronously.
+ * Process all pending createSession() calls synchronously.
*/
- private void processPendingGkrData() {
- Log.d(TAG, "processPendingGkrData()");
- assert(mMediaDrm != null);
+ private void processPendingCreateSessionData() {
+ Log.d(TAG, "processPendingCreateSessionData()");
+ assert (mMediaDrm != null);
- // Check mMediaDrm != null because error may happen in generateKeyRequest().
+ // Check mMediaDrm != null because error may happen in createSession().
// Check !mProvisioningPending because NotProvisionedException may be
- // thrown in generateKeyRequest().
- while (mMediaDrm != null && !mProvisioningPending && !mPendingGkrDataQueue.isEmpty()) {
- PendingGkrData pendingGkrData = mPendingGkrDataQueue.poll();
- byte[] initData = pendingGkrData.initData();
- String mime = pendingGkrData.mimeType();
- generateKeyRequest(initData, mime);
+ // thrown in createSession().
+ while (mMediaDrm != null && !mProvisioningPending &&
+ !mPendingCreateSessionDataQueue.isEmpty()) {
+ PendingCreateSessionData pendingData = mPendingCreateSessionDataQueue.poll();
+ int sessionId = pendingData.sessionId();
+ byte[] initData = pendingData.initData();
+ String mime = pendingData.mimeType();
+ createSession(sessionId, initData, mime);
}
}
@@ -407,83 +418,89 @@ class MediaDrmBridge {
private void resumePendingOperations() {
mHandler.post(new Runnable(){
public void run() {
- processPendingGkrData();
+ processPendingCreateSessionData();
}
});
}
/**
- * Generate a key request with |initData| and |mime|, and post an
- * asynchronous task to the native side with the key request or a key error.
+ * Create a session with |sessionId|, |initData| and |mime|.
* In multiple session mode, a new session will be open. In single session
- * mode, the mMediaCryptoSessionId will be used.
+ * mode, the mMediaCryptoSession will be used.
*
+ * @param sessionId ID for the session to be created.
* @param initData Data needed to generate the key request.
* @param mime Mime type.
*/
@CalledByNative
- private void generateKeyRequest(byte[] initData, String mime) {
- Log.d(TAG, "generateKeyRequest()");
+ private void createSession(int sessionId, byte[] initData, String mime) {
+ Log.d(TAG, "createSession()");
if (mMediaDrm == null) {
- Log.e(TAG, "generateKeyRequest() called when MediaDrm is null.");
+ Log.e(TAG, "createSession() called when MediaDrm is null.");
return;
}
if (mProvisioningPending) {
- assert(mMediaCrypto == null);
- savePendingGkrData(initData, mime);
+ assert (mMediaCrypto == null);
+ savePendingCreateSessionData(sessionId, initData, mime);
return;
}
boolean newSessionOpened = false;
- String sessionId = null;
+ ByteBuffer session = null;
try {
// Create MediaCrypto if necessary.
if (mMediaCrypto == null && !createMediaCrypto()) {
- onKeyError(null);
+ onSessionError(sessionId);
return;
}
- assert(mMediaCrypto != null);
- assert(mSessionIds.containsKey(mMediaCryptoSessionId));
+ assert (mMediaCrypto != null);
+ assert (mSessionIds.containsKey(mMediaCryptoSession));
if (mSingleSessionMode) {
- sessionId = mMediaCryptoSessionId;
- if (mSessionIds.get(sessionId) == null) {
- // Set |mime| when we call generateKeyRequest() for the first time.
- mSessionIds.put(sessionId, mime);
- } else if (!mSessionIds.get(sessionId).equals(mime)) {
+ session = mMediaCryptoSession;
+ if (mSessionMimeTypes.get(session) != null &&
+ !mSessionMimeTypes.get(session).equals(mime)) {
Log.e(TAG, "Only one mime type is supported in single session mode.");
- onKeyError(sessionId);
+ onSessionError(sessionId);
return;
}
} else {
- sessionId = openSession();
- if (sessionId == null) {
- Log.e(TAG, "Cannot open session in generateKeyRequest().");
- onKeyError(null);
+ session = openSession();
+ if (session == null) {
+ Log.e(TAG, "Cannot open session in createSession().");
+ onSessionError(sessionId);
return;
}
newSessionOpened = true;
- assert(!mSessionIds.containsKey(sessionId));
+ assert (!mSessionIds.containsKey(session));
}
- // KeyMessage or KeyError is fired in getKeyRequest().
- if (!getKeyRequest(sessionId, initData, mime)) {
- Log.e(TAG, "Cannot get key request in generateKeyRequest().");
+ MediaDrm.KeyRequest request = null;
+ request = getKeyRequest(session, initData, mime);
+ if (request == null) {
+ if (newSessionOpened) {
+ closeSession(session);
+ }
+ onSessionError(sessionId);
return;
}
+ onSessionCreated(sessionId, getWebSessionId(session));
+ onSessionMessage(sessionId, request);
if (newSessionOpened) {
- Log.e(TAG, "generateKeyRequest(): Session " + sessionId + " created.");
- mSessionIds.put(sessionId, mime);
- return;
+ Log.d(TAG, "createSession(): Session " + getWebSessionId(session) +
+ " (" + sessionId + ") created.");
}
+
+ mSessionIds.put(session, sessionId);
+ mSessionMimeTypes.put(session, mime);
} catch (android.media.NotProvisionedException e) {
Log.e(TAG, "Device not provisioned", e);
if (newSessionOpened) {
- closeSession(sessionId);
+ closeSession(session);
}
- savePendingGkrData(initData, mime);
+ savePendingCreateSessionData(sessionId, initData, mime);
startProvisioning();
}
}
@@ -494,87 +511,84 @@ class MediaDrmBridge {
*
* @param sessionId Crypto session Id.
*/
- private boolean sessionExists(String sessionId) {
- if (mMediaCryptoSessionId == null) {
- assert(mSessionIds.isEmpty());
+ private boolean sessionExists(ByteBuffer session) {
+ if (mMediaCryptoSession == null) {
+ assert (mSessionIds.isEmpty());
Log.e(TAG, "Session doesn't exist because media crypto session is not created.");
return false;
}
- assert(mSessionIds.containsKey(mMediaCryptoSessionId));
+ assert (mSessionIds.containsKey(mMediaCryptoSession));
if (mSingleSessionMode) {
- return mMediaCryptoSessionId.equals(sessionId);
+ return mMediaCryptoSession.equals(session);
}
- return !mMediaCryptoSessionId.equals(sessionId) && mSessionIds.containsKey(sessionId);
+ return !session.equals(mMediaCryptoSession) && mSessionIds.containsKey(session);
}
/**
* Cancel a key request for a session Id.
*
- * @param sessionId Crypto session Id.
+ * @param sessionId Reference ID of session to be released.
*/
@CalledByNative
- private void cancelKeyRequest(String sessionId) {
- Log.d(TAG, "cancelKeyRequest(): " + sessionId);
+ private void releaseSession(int sessionId) {
+ Log.d(TAG, "releaseSession(): " + sessionId);
if (mMediaDrm == null) {
- Log.e(TAG, "cancelKeyRequest() called when MediaDrm is null.");
+ Log.e(TAG, "releaseSession() called when MediaDrm is null.");
return;
}
- if (!sessionExists(sessionId)) {
- Log.e(TAG, "Invalid session in cancelKeyRequest.");
- onKeyError(sessionId);
+ ByteBuffer session = getSession(sessionId);
+ if (session == null) {
+ Log.e(TAG, "Invalid sessionId in releaseSession.");
+ onSessionError(sessionId);
return;
}
- try {
- final byte[] session = sessionId.getBytes("UTF-8");
- mMediaDrm.removeKeys(session);
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "Cannot cancel key request", e);
- }
+ mMediaDrm.removeKeys(session.array());
// We don't close the media crypto session in single session mode.
if (!mSingleSessionMode) {
- closeSession(sessionId);
- mSessionIds.remove(sessionId);
Log.d(TAG, "Session " + sessionId + "closed.");
+ closeSession(session);
+ mSessionIds.remove(session);
+ onSessionClosed(sessionId);
}
}
/**
* Add a key for a session Id.
*
- * @param sessionId Crypto session Id.
+ * @param sessionId Reference ID of session to be updated.
* @param key Response data from the server.
*/
@CalledByNative
- private void addKey(String sessionId, byte[] key) {
- Log.d(TAG, "addKey(): " + sessionId);
+ private void updateSession(int sessionId, byte[] key) {
+ Log.d(TAG, "updateSession(): " + sessionId);
if (mMediaDrm == null) {
- Log.e(TAG, "addKey() called when MediaDrm is null.");
+ Log.e(TAG, "updateSession() called when MediaDrm is null.");
return;
}
// TODO(xhwang): We should be able to DCHECK this when WD EME is implemented.
- if (!sessionExists(sessionId)) {
- Log.e(TAG, "Invalid session in addKey.");
- onKeyError(sessionId);
+ ByteBuffer session = getSession(sessionId);
+ if (!sessionExists(session)) {
+ Log.e(TAG, "Invalid session in updateSession.");
+ onSessionError(sessionId);
return;
}
try {
- final byte[] session = sessionId.getBytes("UTF-8");
try {
- mMediaDrm.provideKeyResponse(session, key);
+ mMediaDrm.provideKeyResponse(session.array(), key);
} catch (java.lang.IllegalStateException e) {
// This is not really an exception. Some error code are incorrectly
// reported as an exception.
// TODO(qinmin): remove this exception catch when b/10495563 is fixed.
Log.e(TAG, "Exception intentionally caught when calling provideKeyResponse()", e);
}
- onKeyAdded(sessionId);
+ onSessionReady(sessionId);
Log.d(TAG, "Key successfully added for session " + sessionId);
return;
} catch (android.media.NotProvisionedException e) {
@@ -582,10 +596,8 @@ class MediaDrmBridge {
Log.e(TAG, "failed to provide key response", e);
} catch (android.media.DeniedByServerException e) {
Log.e(TAG, "failed to provide key response", e);
- } catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "failed to provide key response", e);
}
- onKeyError(sessionId);
+ onSessionError(sessionId);
release();
}
@@ -603,8 +615,8 @@ class MediaDrmBridge {
private void startProvisioning() {
Log.d(TAG, "startProvisioning");
- assert(mMediaDrm != null);
- assert(!mProvisioningPending);
+ assert (mMediaDrm != null);
+ assert (!mProvisioningPending);
mProvisioningPending = true;
MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest();
PostRequestTask postTask = new PostRequestTask(request.getData());
@@ -618,7 +630,7 @@ class MediaDrmBridge {
*/
private void onProvisionResponse(byte[] response) {
Log.d(TAG, "onProvisionResponse()");
- assert(mProvisioningPending);
+ assert (mProvisioningPending);
mProvisioningPending = false;
// If |mMediaDrm| is released, there is no need to callback native.
@@ -659,77 +671,109 @@ class MediaDrmBridge {
return false;
}
- private void onKeyMessage(
- final String sessionId, final byte[] message, final String destinationUrl) {
+ private void onSessionCreated(final int sessionId, final String webSessionId) {
+ mHandler.post(new Runnable(){
+ public void run() {
+ nativeOnSessionCreated(mNativeMediaDrmBridge, sessionId, webSessionId);
+ }
+ });
+ }
+
+ private void onSessionMessage(final int sessionId, final MediaDrm.KeyRequest request) {
mHandler.post(new Runnable(){
public void run() {
- nativeOnKeyMessage(mNativeMediaDrmBridge, sessionId, message, destinationUrl);
+ nativeOnSessionMessage(mNativeMediaDrmBridge, sessionId,
+ request.getData(), request.getDefaultUrl());
+ }
+ });
+ }
+
+ private void onSessionReady(final int sessionId) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ nativeOnSessionReady(mNativeMediaDrmBridge, sessionId);
}
});
}
- private void onKeyAdded(final String sessionId) {
+ private void onSessionClosed(final int sessionId) {
mHandler.post(new Runnable() {
public void run() {
- nativeOnKeyAdded(mNativeMediaDrmBridge, sessionId);
+ nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId);
}
});
}
- private void onKeyError(final String sessionId) {
+ private void onSessionError(final int sessionId) {
// TODO(qinmin): pass the error code to native.
mHandler.post(new Runnable() {
public void run() {
- nativeOnKeyError(mNativeMediaDrmBridge, sessionId);
+ nativeOnSessionError(mNativeMediaDrmBridge, sessionId);
}
});
}
- private String GetSessionId(byte[] session) {
- String sessionId = null;
+ private String getWebSessionId(ByteBuffer session) {
+ String webSessionId = null;
try {
- sessionId = new String(session, "UTF-8");
+ webSessionId = new String(session.array(), "UTF-8");
} catch (java.io.UnsupportedEncodingException e) {
- Log.e(TAG, "GetSessionId failed", e);
+ Log.e(TAG, "getWebSessionId failed", e);
} catch (java.lang.NullPointerException e) {
- Log.e(TAG, "GetSessionId failed", e);
+ Log.e(TAG, "getWebSessionId failed", e);
}
- return sessionId;
+ return webSessionId;
}
private class MediaDrmListener implements MediaDrm.OnEventListener {
@Override
- public void onEvent(MediaDrm mediaDrm, byte[] session, int event, int extra, byte[] data) {
- String sessionId = null;
+ public void onEvent(
+ MediaDrm mediaDrm, byte[] session_array, int event, int extra, byte[] data) {
+ if (session_array == null) {
+ Log.e(TAG, "MediaDrmListener: Null session.");
+ return;
+ }
+ ByteBuffer session = ByteBuffer.wrap(session_array);
+ if (!sessionExists(session)) {
+ Log.e(TAG, "MediaDrmListener: Invalid session.");
+ return;
+ }
+ Integer sessionId = mSessionIds.get(session);
+ if (sessionId == null || sessionId == INVALID_SESSION_ID) {
+ Log.e(TAG, "MediaDrmListener: Invalid session ID.");
+ return;
+ }
switch(event) {
case MediaDrm.EVENT_PROVISION_REQUIRED:
- // This is handled by the handler of NotProvisionedException.
Log.d(TAG, "MediaDrm.EVENT_PROVISION_REQUIRED");
break;
case MediaDrm.EVENT_KEY_REQUIRED:
Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED");
- sessionId = GetSessionId(session);
- if (sessionId != null && !mProvisioningPending) {
- assert(sessionExists(sessionId));
- String mime = mSessionIds.get(sessionId);
- try {
- getKeyRequest(sessionId, data, mime);
- } catch (android.media.NotProvisionedException e) {
- Log.e(TAG, "Device not provisioned", e);
- startProvisioning();
- }
+ if (mProvisioningPending) {
+ return;
+ }
+ String mime = mSessionMimeTypes.get(session);
+ MediaDrm.KeyRequest request = null;
+ try {
+ request = getKeyRequest(session, data, mime);
+ } catch (android.media.NotProvisionedException e) {
+ Log.e(TAG, "Device not provisioned", e);
+ startProvisioning();
+ return;
+ }
+ if (request != null) {
+ onSessionMessage(sessionId, request);
+ } else {
+ onSessionError(sessionId);
}
break;
case MediaDrm.EVENT_KEY_EXPIRED:
Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED");
- sessionId = GetSessionId(session);
- if (sessionId != null) {
- onKeyError(sessionId);
- }
+ onSessionError(sessionId);
break;
case MediaDrm.EVENT_VENDOR_DEFINED:
Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED");
- assert(false); // Should never happen.
+ assert (false); // Should never happen.
break;
default:
Log.e(TAG, "Invalid DRM event " + (int)event);
@@ -796,12 +840,17 @@ class MediaDrmBridge {
private native void nativeOnMediaCryptoReady(long nativeMediaDrmBridge);
- private native void nativeOnKeyMessage(long nativeMediaDrmBridge, String sessionId,
- byte[] message, String destinationUrl);
+ private native void nativeOnSessionCreated(long nativeMediaDrmBridge, int sessionId,
+ String webSessionId);
+
+ private native void nativeOnSessionMessage(long nativeMediaDrmBridge, int sessionId,
+ byte[] message, String destinationUrl);
+
+ private native void nativeOnSessionReady(long nativeMediaDrmBridge, int sessionId);
- private native void nativeOnKeyAdded(long nativeMediaDrmBridge, String sessionId);
+ private native void nativeOnSessionClosed(long nativeMediaDrmBridge, int sessionId);
- private native void nativeOnKeyError(long nativeMediaDrmBridge, String sessionId);
+ private native void nativeOnSessionError(long nativeMediaDrmBridge, int sessionId);
private native void nativeOnResetDeviceCredentialsCompleted(
long nativeMediaDrmBridge, boolean success);
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 37eaa33..95085fe 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -248,9 +248,8 @@ bool MediaDrmBridge::CreateSession(uint32 session_id,
ScopedJavaLocalRef<jbyteArray> j_pssh_data =
base::android::ToJavaByteArray(env, &pssh_data[0], pssh_data.size());
ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, type);
- pending_key_request_session_ids_.push(session_id);
- Java_MediaDrmBridge_generateKeyRequest(
- env, j_media_drm_.obj(), j_pssh_data.obj(), j_mime.obj());
+ Java_MediaDrmBridge_createSession(
+ env, j_media_drm_.obj(), session_id, j_pssh_data.obj(), j_mime.obj());
return true;
}
@@ -261,19 +260,14 @@ void MediaDrmBridge::UpdateSession(uint32 session_id,
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> j_response =
base::android::ToJavaByteArray(env, response, response_length);
- ScopedJavaLocalRef<jstring> j_session_id =
- ConvertUTF8ToJavaString(env, LookupWebSessionId(session_id));
- // TODO(jrummell): Update Android names to match new functionality.
- Java_MediaDrmBridge_addKey(
- env, j_media_drm_.obj(), j_session_id.obj(), j_response.obj());
+ Java_MediaDrmBridge_updateSession(
+ env, j_media_drm_.obj(), session_id, j_response.obj());
}
void MediaDrmBridge::ReleaseSession(uint32 session_id) {
+ DVLOG(1) << __FUNCTION__;
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> j_session_id =
- ConvertUTF8ToJavaString(env, LookupWebSessionId(session_id));
- Java_MediaDrmBridge_cancelKeyRequest(
- env, j_media_drm_.obj(), j_session_id.obj());
+ Java_MediaDrmBridge_releaseSession(env, j_media_drm_.obj(), session_id);
}
void MediaDrmBridge::SetMediaCryptoReadyCB(const base::Closure& closure) {
@@ -298,32 +292,46 @@ void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject) {
base::ResetAndReturn(&media_crypto_ready_cb_).Run();
}
-void MediaDrmBridge::OnKeyMessage(JNIEnv* env,
- jobject j_media_drm,
- jstring j_session_id,
- jbyteArray j_message,
- jstring j_destination_url) {
- std::string web_session_id = ConvertJavaStringToUTF8(env, j_session_id);
- uint32_t session_id = LookupSessionId(web_session_id);
+void MediaDrmBridge::OnSessionCreated(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id,
+ jstring j_web_session_id) {
+ uint32 session_id = j_session_id;
+ std::string web_session_id = ConvertJavaStringToUTF8(env, j_web_session_id);
+ manager_->OnSessionCreated(media_keys_id_, session_id, web_session_id);
+}
+
+void MediaDrmBridge::OnSessionMessage(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id,
+ jbyteArray j_message,
+ jstring j_destination_url) {
+ uint32 session_id = j_session_id;
std::vector<uint8> message;
JavaByteArrayToByteVector(env, j_message, &message);
std::string destination_url = ConvertJavaStringToUTF8(env, j_destination_url);
-
- manager_->OnSessionCreated(media_keys_id_, session_id, web_session_id);
manager_->OnSessionMessage(
media_keys_id_, session_id, message, destination_url);
}
-void MediaDrmBridge::OnKeyAdded(JNIEnv* env, jobject, jstring j_session_id) {
- std::string web_session_id = ConvertJavaStringToUTF8(env, j_session_id);
- uint32_t session_id = LookupSessionId(web_session_id);
+void MediaDrmBridge::OnSessionReady(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id) {
+ uint32 session_id = j_session_id;
manager_->OnSessionReady(media_keys_id_, session_id);
}
-void MediaDrmBridge::OnKeyError(JNIEnv* env, jobject, jstring j_session_id) {
- // |j_session_id| can be NULL, in which case we'll return an empty string.
- std::string web_session_id = ConvertJavaStringToUTF8(env, j_session_id);
- uint32 session_id = LookupSessionId(web_session_id);
+void MediaDrmBridge::OnSessionClosed(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id) {
+ uint32 session_id = j_session_id;
+ manager_->OnSessionClosed(media_keys_id_, session_id);
+}
+
+void MediaDrmBridge::OnSessionError(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id) {
+ uint32 session_id = j_session_id;
manager_->OnSessionError(
media_keys_id_, session_id, MediaKeys::kUnknownError, 0);
}
@@ -364,35 +372,4 @@ void MediaDrmBridge::OnResetDeviceCredentialsCompleted(
base::ResetAndReturn(&reset_credentials_cb_).Run(success);
}
-uint32_t MediaDrmBridge::LookupSessionId(const std::string& session_id) {
- for (SessionMap::iterator it = session_map_.begin();
- it != session_map_.end();
- ++it) {
- if (it->second == session_id)
- return it->first;
- }
-
- // There is no entry in the map; assume it came from the oldest
- // GenerateKeyRequest() call.
- DCHECK(!pending_key_request_session_ids_.empty());
- uint32 session_reference_id = pending_key_request_session_ids_.front();
- pending_key_request_session_ids_.pop();
-
- // If this is a valid |session_id|, add it to the list. Otherwise, avoid
- // adding empty string as a mapping to prevent future calls with an empty
- // string from using the wrong session_reference_id.
- if (!session_id.empty()) {
- DCHECK(session_map_.find(session_reference_id) == session_map_.end());
- session_map_[session_reference_id] = session_id;
- }
-
- return session_reference_id;
-}
-
-const std::string& MediaDrmBridge::LookupWebSessionId(uint32 session_id) {
- // Session may not exist if error happens during GenerateKeyRequest().
- SessionMap::iterator it = session_map_.find(session_id);
- return (it != session_map_.end()) ? it->second : base::EmptyString();
-}
-
} // namespace media
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index 9a5f693..76149a6 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -79,17 +79,21 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
void SetMediaCryptoReadyCB(const base::Closure& closure);
// Called after a MediaCrypto object is created.
- void OnMediaCryptoReady(JNIEnv* env, jobject);
-
- // Called after we got the response for GenerateKeyRequest().
- void OnKeyMessage(JNIEnv* env, jobject, jstring j_session_id,
- jbyteArray message, jstring destination_url);
-
- // Called when key is added.
- void OnKeyAdded(JNIEnv* env, jobject, jstring j_session_id);
-
- // Called when error happens.
- void OnKeyError(JNIEnv* env, jobject, jstring j_session_id);
+ void OnMediaCryptoReady(JNIEnv* env, jobject j_media_drm);
+
+ // Callbacks for firing session events.
+ void OnSessionCreated(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id,
+ jstring j_web_session_id);
+ void OnSessionMessage(JNIEnv* env,
+ jobject j_media_drm,
+ jint j_session_id,
+ jbyteArray j_message,
+ jstring j_destination_url);
+ void OnSessionReady(JNIEnv* env, jobject j_media_drm, jint j_session_id);
+ void OnSessionClosed(JNIEnv* env, jobject j_media_drm, jint j_session_id);
+ void OnSessionError(JNIEnv* env, jobject j_media_drm, jint j_session_id);
// Reset the device credentials.
void ResetDeviceCredentials(const ResetCredentialsCB& callback);
@@ -106,9 +110,6 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
GURL frame_url() const { return frame_url_; }
private:
- // Map between session_id and web_session_id.
- typedef std::map<uint32_t, std::string> SessionMap;
-
static bool IsSecureDecoderRequired(SecurityLevel security_level);
MediaDrmBridge(int media_keys_id,
@@ -120,13 +121,6 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
// Get the security level of the media.
SecurityLevel GetSecurityLevel();
- // Determine the corresponding session_id for |web_session_id|.
- uint32_t LookupSessionId(const std::string& web_session_id);
-
- // Determine the corresponding web_session_id for |session_id|. The returned
- // value is only valid on the main thread, and should be stored by copy.
- const std::string& LookupWebSessionId(uint32_t session_id);
-
// ID of the MediaKeys object.
int media_keys_id_;
@@ -146,14 +140,6 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
ResetCredentialsCB reset_credentials_cb_;
- SessionMap session_map_;
-
- // As the response from GenerateKeyRequest() will be asynchronous, add this
- // request to a queue and assume that the subsequent responses come back in
- // the order issued.
- // TODO(jrummell): Remove once the Java interface supports session_id.
- std::queue<uint32_t> pending_key_request_session_ids_;
-
DISALLOW_COPY_AND_ASSIGN(MediaDrmBridge);
};