| Index: media/base/android/media_drm_bridge.cc | 
| diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc | 
| index 91c08d2033fdb32e6d2a78a90a8edaacfedab030..a89522df7115e8426a6df794cf6d0323f6fd485f 100644 | 
| --- a/media/base/android/media_drm_bridge.cc | 
| +++ b/media/base/android/media_drm_bridge.cc | 
| @@ -19,6 +19,7 @@ | 
| #include "base/sys_byteorder.h" | 
| #include "base/sys_info.h" | 
| #include "jni/MediaDrmBridge_jni.h" | 
| +#include "media/base/cdm_key_information.h" | 
|  | 
| #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR. | 
|  | 
| @@ -30,20 +31,34 @@ using base::android::ScopedJavaLocalRef; | 
|  | 
| namespace media { | 
|  | 
| -static uint32 ReadUint32(const uint8_t* data) { | 
| +namespace { | 
| + | 
| +// DrmBridge supports session expiration event but doesn't provide detailed | 
| +// status for each key ID, which is required by the EME spec. Use a dummy key ID | 
| +// here to report session expiration info. | 
| +const char kDummyKeyId[] = "Dummy Key Id"; | 
| + | 
| +uint32 ReadUint32(const uint8_t* data) { | 
| uint32 value = 0; | 
| for (int i = 0; i < 4; ++i) | 
| value = (value << 8) | data[i]; | 
| return value; | 
| } | 
|  | 
| -static uint64 ReadUint64(const uint8_t* data) { | 
| +uint64 ReadUint64(const uint8_t* data) { | 
| uint64 value = 0; | 
| for (int i = 0; i < 8; ++i) | 
| value = (value << 8) | data[i]; | 
| return value; | 
| } | 
|  | 
| +// Returns string session ID from jbyteArray (byte[] in Java). | 
| +std::string GetSessionId(JNIEnv* env, jbyteArray j_session_id) { | 
| +  std::vector<uint8> session_id_vector; | 
| +  JavaByteArrayToByteVector(env, j_session_id, &session_id_vector); | 
| +  return std::string(session_id_vector.begin(), session_id_vector.end()); | 
| +} | 
| + | 
| // The structure of an ISO CENC Protection System Specific Header (PSSH) box is | 
| // as follows. (See ISO/IEC FDIS 23001-7:2011(E).) | 
| // Note: ISO boxes use big-endian values. | 
| @@ -70,58 +85,6 @@ const uint8 kWidevineUuid[16] = { | 
|  | 
| typedef std::vector<uint8> UUID; | 
|  | 
| -class KeySystemUuidManager { | 
| - public: | 
| -  KeySystemUuidManager(); | 
| -  UUID GetUUID(const std::string& key_system); | 
| -  void AddMapping(const std::string& key_system, const UUID& uuid); | 
| -  std::vector<std::string> GetPlatformKeySystemNames(); | 
| - | 
| - private: | 
| -  typedef base::hash_map<std::string, UUID> KeySystemUuidMap; | 
| - | 
| -  KeySystemUuidMap key_system_uuid_map_; | 
| - | 
| -  DISALLOW_COPY_AND_ASSIGN(KeySystemUuidManager); | 
| -}; | 
| - | 
| -KeySystemUuidManager::KeySystemUuidManager() { | 
| -  // Widevine is always supported in Android. | 
| -  key_system_uuid_map_[kWidevineKeySystem] = | 
| -      UUID(kWidevineUuid, kWidevineUuid + arraysize(kWidevineUuid)); | 
| -} | 
| - | 
| -UUID KeySystemUuidManager::GetUUID(const std::string& key_system) { | 
| -  KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system); | 
| -  if (it == key_system_uuid_map_.end()) | 
| -    return UUID(); | 
| -  return it->second; | 
| -} | 
| - | 
| -void KeySystemUuidManager::AddMapping(const std::string& key_system, | 
| -                                      const UUID& uuid) { | 
| -  KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system); | 
| -  DCHECK(it == key_system_uuid_map_.end()) | 
| -      << "Shouldn't overwrite an existing key system."; | 
| -  if (it != key_system_uuid_map_.end()) | 
| -    return; | 
| -  key_system_uuid_map_[key_system] = uuid; | 
| -} | 
| - | 
| -std::vector<std::string> KeySystemUuidManager::GetPlatformKeySystemNames() { | 
| -  std::vector<std::string> key_systems; | 
| -  for (KeySystemUuidMap::iterator it = key_system_uuid_map_.begin(); | 
| -       it != key_system_uuid_map_.end(); ++it) { | 
| -    // Rule out the key system handled by Chrome explicitly. | 
| -    if (it->first != kWidevineKeySystem) | 
| -      key_systems.push_back(it->first); | 
| -  } | 
| -  return key_systems; | 
| -} | 
| - | 
| -base::LazyInstance<KeySystemUuidManager>::Leaky g_key_system_uuid_manager = | 
| -    LAZY_INSTANCE_INITIALIZER; | 
| - | 
| // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the | 
| // "Data" of the box and put it in |pssh_data|. Returns true if such a box is | 
| // found and successfully parsed. Returns false otherwise. | 
| @@ -129,9 +92,10 @@ base::LazyInstance<KeySystemUuidManager>::Leaky g_key_system_uuid_manager = | 
| // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box | 
| // will be set in |pssh_data|. | 
| // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. | 
| -static bool GetPsshData(const uint8* data, int data_size, | 
| -                        const UUID& uuid, | 
| -                        std::vector<uint8>* pssh_data) { | 
| +bool GetPsshData(const uint8* data, | 
| +                 int data_size, | 
| +                 const UUID& uuid, | 
| +                 std::vector<uint8>* pssh_data) { | 
| const uint8* cur = data; | 
| const uint8* data_end = data + data_size; | 
| int bytes_left = data_size; | 
| @@ -206,37 +170,65 @@ static bool GetPsshData(const uint8* data, int data_size, | 
| return false; | 
| } | 
|  | 
| -static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( | 
| -    const std::string& security_level_str) { | 
| -  if (0 == security_level_str.compare("L1")) | 
| -    return MediaDrmBridge::SECURITY_LEVEL_1; | 
| -  if (0 == security_level_str.compare("L3")) | 
| -    return MediaDrmBridge::SECURITY_LEVEL_3; | 
| -  DCHECK(security_level_str.empty()); | 
| -  return MediaDrmBridge::SECURITY_LEVEL_NONE; | 
| +class KeySystemUuidManager { | 
| + public: | 
| +  KeySystemUuidManager(); | 
| +  UUID GetUUID(const std::string& key_system); | 
| +  void AddMapping(const std::string& key_system, const UUID& uuid); | 
| +  std::vector<std::string> GetPlatformKeySystemNames(); | 
| + | 
| + private: | 
| +  typedef base::hash_map<std::string, UUID> KeySystemUuidMap; | 
| + | 
| +  KeySystemUuidMap key_system_uuid_map_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(KeySystemUuidManager); | 
| +}; | 
| + | 
| +KeySystemUuidManager::KeySystemUuidManager() { | 
| +  // Widevine is always supported in Android. | 
| +  key_system_uuid_map_[kWidevineKeySystem] = | 
| +      UUID(kWidevineUuid, kWidevineUuid + arraysize(kWidevineUuid)); | 
| } | 
|  | 
| -static std::string GetSecurityLevelString( | 
| -    MediaDrmBridge::SecurityLevel security_level) { | 
| -  switch (security_level) { | 
| -    case MediaDrmBridge::SECURITY_LEVEL_NONE: | 
| -      return ""; | 
| -    case MediaDrmBridge::SECURITY_LEVEL_1: | 
| -      return "L1"; | 
| -    case MediaDrmBridge::SECURITY_LEVEL_3: | 
| -      return "L3"; | 
| +UUID KeySystemUuidManager::GetUUID(const std::string& key_system) { | 
| +  KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system); | 
| +  if (it == key_system_uuid_map_.end()) | 
| +    return UUID(); | 
| +  return it->second; | 
| +} | 
| + | 
| +void KeySystemUuidManager::AddMapping(const std::string& key_system, | 
| +                                      const UUID& uuid) { | 
| +  KeySystemUuidMap::iterator it = key_system_uuid_map_.find(key_system); | 
| +  DCHECK(it == key_system_uuid_map_.end()) | 
| +      << "Shouldn't overwrite an existing key system."; | 
| +  if (it != key_system_uuid_map_.end()) | 
| +    return; | 
| +  key_system_uuid_map_[key_system] = uuid; | 
| +} | 
| + | 
| +std::vector<std::string> KeySystemUuidManager::GetPlatformKeySystemNames() { | 
| +  std::vector<std::string> key_systems; | 
| +  for (KeySystemUuidMap::iterator it = key_system_uuid_map_.begin(); | 
| +       it != key_system_uuid_map_.end(); ++it) { | 
| +    // Rule out the key system handled by Chrome explicitly. | 
| +    if (it->first != kWidevineKeySystem) | 
| +      key_systems.push_back(it->first); | 
| } | 
| -  return ""; | 
| +  return key_systems; | 
| } | 
|  | 
| +base::LazyInstance<KeySystemUuidManager>::Leaky g_key_system_uuid_manager = | 
| +    LAZY_INSTANCE_INITIALIZER; | 
| + | 
| // Checks whether |key_system| is supported with |container_mime_type|. Only | 
| // checks |key_system| support if |container_mime_type| is empty. | 
| // TODO(xhwang): The |container_mime_type| is not the same as contentType in | 
| // the EME spec. Revisit this once the spec issue with initData type is | 
| // resolved. | 
| -static bool IsKeySystemSupportedWithTypeImpl( | 
| -    const std::string& key_system, | 
| -    const std::string& container_mime_type) { | 
| +bool IsKeySystemSupportedWithTypeImpl(const std::string& key_system, | 
| +                                      const std::string& container_mime_type) { | 
| if (!MediaDrmBridge::IsAvailable()) | 
| return false; | 
|  | 
| @@ -253,6 +245,42 @@ static bool IsKeySystemSupportedWithTypeImpl( | 
| env, j_scheme_uuid.obj(), j_container_mime_type.obj()); | 
| } | 
|  | 
| +MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( | 
| +    const std::string& security_level_str) { | 
| +  if (0 == security_level_str.compare("L1")) | 
| +    return MediaDrmBridge::SECURITY_LEVEL_1; | 
| +  if (0 == security_level_str.compare("L3")) | 
| +    return MediaDrmBridge::SECURITY_LEVEL_3; | 
| +  DCHECK(security_level_str.empty()); | 
| +  return MediaDrmBridge::SECURITY_LEVEL_NONE; | 
| +} | 
| + | 
| +std::string GetSecurityLevelString( | 
| +    MediaDrmBridge::SecurityLevel security_level) { | 
| +  switch (security_level) { | 
| +    case MediaDrmBridge::SECURITY_LEVEL_NONE: | 
| +      return ""; | 
| +    case MediaDrmBridge::SECURITY_LEVEL_1: | 
| +      return "L1"; | 
| +    case MediaDrmBridge::SECURITY_LEVEL_3: | 
| +      return "L3"; | 
| +  } | 
| +  return ""; | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +// Called by Java. | 
| +static void AddKeySystemUuidMapping(JNIEnv* env, | 
| +                                    jclass clazz, | 
| +                                    jstring j_key_system, | 
| +                                    jobject j_buffer) { | 
| +  std::string key_system = ConvertJavaStringToUTF8(env, j_key_system); | 
| +  uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer)); | 
| +  UUID uuid(buffer, buffer + 16); | 
| +  g_key_system_uuid_manager.Get().AddMapping(key_system, uuid); | 
| +} | 
| + | 
| // static | 
| bool MediaDrmBridge::IsAvailable() { | 
| if (base::android::BuildInfo::GetInstance()->sdk_int() < 19) | 
| @@ -283,22 +311,13 @@ bool MediaDrmBridge::IsSecurityLevelSupported(const std::string& key_system, | 
| return false; | 
|  | 
| scoped_ptr<MediaDrmBridge> media_drm_bridge = | 
| -      MediaDrmBridge::CreateSessionless(key_system); | 
| +      MediaDrmBridge::CreateWithoutSessionSupport(key_system); | 
| if (!media_drm_bridge) | 
| return false; | 
|  | 
| return media_drm_bridge->SetSecurityLevel(security_level); | 
| } | 
|  | 
| -static void AddKeySystemUuidMapping(JNIEnv* env, jclass clazz, | 
| -                                    jstring j_key_system, | 
| -                                    jobject j_buffer) { | 
| -  std::string key_system = ConvertJavaStringToUTF8(env, j_key_system); | 
| -  uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer)); | 
| -  UUID uuid(buffer, buffer + 16); | 
| -  g_key_system_uuid_manager.Get().AddMapping(key_system, uuid); | 
| -} | 
| - | 
| // static | 
| std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() { | 
| return g_key_system_uuid_manager.Get().GetPlatformKeySystemNames(); | 
| @@ -322,18 +341,17 @@ bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { | 
| return RegisterNativesImpl(env); | 
| } | 
|  | 
| -MediaDrmBridge::MediaDrmBridge(const std::vector<uint8>& scheme_uuid, | 
| -                               const SessionCreatedCB& session_created_cb, | 
| -                               const SessionMessageCB& session_message_cb, | 
| -                               const SessionReadyCB& session_ready_cb, | 
| -                               const SessionClosedCB& session_closed_cb, | 
| -                               const SessionErrorCB& session_error_cb) | 
| +MediaDrmBridge::MediaDrmBridge( | 
| +    const std::vector<uint8>& scheme_uuid, | 
| +    const SessionMessageCB& session_message_cb, | 
| +    const SessionClosedCB& session_closed_cb, | 
| +    const SessionErrorCB& session_error_cb, | 
| +    const SessionKeysChangeCB& session_keys_change_cb) | 
| : scheme_uuid_(scheme_uuid), | 
| -      session_created_cb_(session_created_cb), | 
| session_message_cb_(session_message_cb), | 
| -      session_ready_cb_(session_ready_cb), | 
| session_closed_cb_(session_closed_cb), | 
| -      session_error_cb_(session_error_cb) { | 
| +      session_error_cb_(session_error_cb), | 
| +      session_keys_change_cb_(session_keys_change_cb) { | 
| JNIEnv* env = AttachCurrentThread(); | 
| CHECK(env); | 
|  | 
| @@ -351,13 +369,14 @@ MediaDrmBridge::~MediaDrmBridge() { | 
| } | 
|  | 
| // static | 
| +// TODO(xhwang): Enable SessionExpirationUpdateCB when it is supported. | 
| scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create( | 
| const std::string& key_system, | 
| -    const SessionCreatedCB& session_created_cb, | 
| const SessionMessageCB& session_message_cb, | 
| -    const SessionReadyCB& session_ready_cb, | 
| const SessionClosedCB& session_closed_cb, | 
| -    const SessionErrorCB& session_error_cb) { | 
| +    const SessionErrorCB& session_error_cb, | 
| +    const SessionKeysChangeCB& session_keys_change_cb, | 
| +    const SessionExpirationUpdateCB& /* session_expiration_update_cb */) { | 
| scoped_ptr<MediaDrmBridge> media_drm_bridge; | 
| if (!IsAvailable()) | 
| return media_drm_bridge.Pass(); | 
| @@ -366,12 +385,9 @@ scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create( | 
| if (scheme_uuid.empty()) | 
| return media_drm_bridge.Pass(); | 
|  | 
| -  media_drm_bridge.reset(new MediaDrmBridge(scheme_uuid, | 
| -                                            session_created_cb, | 
| -                                            session_message_cb, | 
| -                                            session_ready_cb, | 
| -                                            session_closed_cb, | 
| -                                            session_error_cb)); | 
| +  media_drm_bridge.reset(new MediaDrmBridge(scheme_uuid, session_message_cb, | 
| +                                            session_closed_cb, session_error_cb, | 
| +                                            session_keys_change_cb)); | 
|  | 
| if (media_drm_bridge->j_media_drm_.is_null()) | 
| media_drm_bridge.reset(); | 
| @@ -380,14 +396,11 @@ scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create( | 
| } | 
|  | 
| // static | 
| -scoped_ptr<MediaDrmBridge> MediaDrmBridge::CreateSessionless( | 
| +scoped_ptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport( | 
| const std::string& key_system) { | 
| -  return MediaDrmBridge::Create(key_system, | 
| -                                SessionCreatedCB(), | 
| -                                SessionMessageCB(), | 
| -                                SessionReadyCB(), | 
| -                                SessionClosedCB(), | 
| -                                SessionErrorCB()); | 
| +  return MediaDrmBridge::Create( | 
| +      key_system, SessionMessageCB(), SessionClosedCB(), SessionErrorCB(), | 
| +      SessionKeysChangeCB(), SessionExpirationUpdateCB()); | 
| } | 
|  | 
| bool MediaDrmBridge::SetSecurityLevel(SecurityLevel security_level) { | 
| @@ -403,27 +416,42 @@ bool MediaDrmBridge::SetSecurityLevel(SecurityLevel security_level) { | 
| env, j_media_drm_.obj(), j_security_level.obj()); | 
| } | 
|  | 
| -bool MediaDrmBridge::CreateSession(uint32 session_id, | 
| -                                   const std::string& content_type, | 
| -                                   const uint8* init_data, | 
| -                                   int init_data_length) { | 
| +void MediaDrmBridge::SetServerCertificate( | 
| +    const uint8* certificate_data, | 
| +    int certificate_data_length, | 
| +    scoped_ptr<media::SimpleCdmPromise> promise) { | 
| +  promise->reject(NOT_SUPPORTED_ERROR, 0, | 
| +                  "SetServerCertificate() is not supported."); | 
| +} | 
| + | 
| +void MediaDrmBridge::CreateSessionAndGenerateRequest( | 
| +    SessionType session_type, | 
| +    const std::string& init_data_type, | 
| +    const uint8* init_data, | 
| +    int init_data_length, | 
| +    scoped_ptr<media::NewSessionCdmPromise> promise) { | 
| DVLOG(1) << __FUNCTION__; | 
|  | 
| -  DCHECK(!session_created_cb_.is_null()) | 
| -      << "CreateSession called on a sessionless MediaDrmBridge object."; | 
| +  if (session_type != media::MediaKeys::TEMPORARY_SESSION) { | 
| +    promise->reject(NOT_SUPPORTED_ERROR, 0, | 
| +                    "Only the temporary session type is supported."); | 
| +    return; | 
| +  } | 
|  | 
| JNIEnv* env = AttachCurrentThread(); | 
| ScopedJavaLocalRef<jbyteArray> j_init_data; | 
| // Caller should always use "video/*" content types. | 
| -  DCHECK_EQ(0u, content_type.find("video/")); | 
| +  DCHECK_EQ(0u, init_data_type.find("video/")); | 
|  | 
| // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as | 
| // the init data when using MP4 container. | 
| if (std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid) && | 
| -      content_type == "video/mp4") { | 
| +      init_data_type == "video/mp4") { | 
| std::vector<uint8> pssh_data; | 
| -    if (!GetPsshData(init_data, init_data_length, scheme_uuid_, &pssh_data)) | 
| -      return false; | 
| +    if (!GetPsshData(init_data, init_data_length, scheme_uuid_, &pssh_data)) { | 
| +      promise->reject(INVALID_ACCESS_ERROR, 0, "Invalid PSSH data."); | 
| +      return; | 
| +    } | 
| j_init_data = | 
| base::android::ToJavaByteArray(env, &pssh_data[0], pssh_data.size()); | 
| } else { | 
| @@ -432,41 +460,58 @@ bool MediaDrmBridge::CreateSession(uint32 session_id, | 
| } | 
|  | 
| ScopedJavaLocalRef<jstring> j_mime = | 
| -      ConvertUTF8ToJavaString(env, content_type); | 
| -  Java_MediaDrmBridge_createSession( | 
| -      env, j_media_drm_.obj(), session_id, j_init_data.obj(), j_mime.obj()); | 
| -  return true; | 
| +      ConvertUTF8ToJavaString(env, init_data_type); | 
| +  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); | 
| +  Java_MediaDrmBridge_createSession(env, j_media_drm_.obj(), j_init_data.obj(), | 
| +                                    j_mime.obj(), promise_id); | 
| } | 
|  | 
| -void MediaDrmBridge::LoadSession(uint32 session_id, | 
| -                                 const std::string& web_session_id) { | 
| -  // MediaDrmBridge doesn't support loading sessions. | 
| -  NOTREACHED(); | 
| +void MediaDrmBridge::LoadSession( | 
| +    SessionType session_type, | 
| +    const std::string& session_id, | 
| +    scoped_ptr<media::NewSessionCdmPromise> promise) { | 
| +  promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); | 
| } | 
|  | 
| -void MediaDrmBridge::UpdateSession(uint32 session_id, | 
| -                                   const uint8* response, | 
| -                                   int response_length) { | 
| +void MediaDrmBridge::UpdateSession( | 
| +    const std::string& session_id, | 
| +    const uint8* response, | 
| +    int response_length, | 
| +    scoped_ptr<media::SimpleCdmPromise> promise) { | 
| DVLOG(1) << __FUNCTION__; | 
|  | 
| -  DCHECK(!session_ready_cb_.is_null()) | 
| -      << __FUNCTION__ << " called on a sessionless MediaDrmBridge object."; | 
| - | 
| JNIEnv* env = AttachCurrentThread(); | 
| ScopedJavaLocalRef<jbyteArray> j_response = | 
| base::android::ToJavaByteArray(env, response, response_length); | 
| -  Java_MediaDrmBridge_updateSession( | 
| -      env, j_media_drm_.obj(), session_id, j_response.obj()); | 
| +  ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( | 
| +      env, reinterpret_cast<const uint8_t*>(session_id.data()), | 
| +      session_id.size()); | 
| +  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); | 
| +  Java_MediaDrmBridge_updateSession(env, j_media_drm_.obj(), j_session_id.obj(), | 
| +                                    j_response.obj(), promise_id); | 
| } | 
|  | 
| -void MediaDrmBridge::ReleaseSession(uint32 session_id) { | 
| +void MediaDrmBridge::CloseSession(const std::string& session_id, | 
| +                                  scoped_ptr<media::SimpleCdmPromise> promise) { | 
| DVLOG(1) << __FUNCTION__; | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( | 
| +      env, reinterpret_cast<const uint8_t*>(session_id.data()), | 
| +      session_id.size()); | 
| +  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); | 
| +  Java_MediaDrmBridge_closeSession(env, j_media_drm_.obj(), j_session_id.obj(), | 
| +                                   promise_id); | 
| +} | 
|  | 
| -  DCHECK(!session_closed_cb_.is_null()) | 
| -      << __FUNCTION__ << " called on a sessionless MediaDrmBridge object."; | 
| +void MediaDrmBridge::RemoveSession( | 
| +    const std::string& session_id, | 
| +    scoped_ptr<media::SimpleCdmPromise> promise) { | 
| +  promise->reject(NOT_SUPPORTED_ERROR, 0, "RemoveSession() is not supported."); | 
| +} | 
|  | 
| -  JNIEnv* env = AttachCurrentThread(); | 
| -  Java_MediaDrmBridge_releaseSession(env, j_media_drm_.obj(), session_id); | 
| +CdmContext* MediaDrmBridge::GetCdmContext() { | 
| +  NOTREACHED(); | 
| +  return nullptr; | 
| } | 
|  | 
| int MediaDrmBridge::RegisterPlayer(const base::Closure& new_key_cb, | 
| @@ -500,54 +545,80 @@ void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject) { | 
| base::ResetAndReturn(&media_crypto_ready_cb_).Run(); | 
| } | 
|  | 
| -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); | 
| -  session_created_cb_.Run(session_id, web_session_id); | 
| +void MediaDrmBridge::OnPromiseResolved(JNIEnv* env, | 
| +                                       jobject j_media_drm, | 
| +                                       jint j_promise_id) { | 
| +  cdm_promise_adapter_.ResolvePromise(j_promise_id); | 
| +} | 
| + | 
| +void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv* env, | 
| +                                                  jobject j_media_drm, | 
| +                                                  jint j_promise_id, | 
| +                                                  jbyteArray j_session_id) { | 
| +  cdm_promise_adapter_.ResolvePromise(j_promise_id, | 
| +                                      GetSessionId(env, j_session_id)); | 
| +} | 
| + | 
| +void MediaDrmBridge::OnPromiseRejected(JNIEnv* env, | 
| +                                       jobject j_media_drm, | 
| +                                       jint j_promise_id, | 
| +                                       jstring j_error_message) { | 
| +  std::string error_message = ConvertJavaStringToUTF8(env, j_error_message); | 
| +  cdm_promise_adapter_.RejectPromise(j_promise_id, MediaKeys::UNKNOWN_ERROR, 0, | 
| +                                     error_message); | 
| } | 
|  | 
| void MediaDrmBridge::OnSessionMessage(JNIEnv* env, | 
| jobject j_media_drm, | 
| -                                      jint j_session_id, | 
| +                                      jbyteArray j_session_id, | 
| jbyteArray j_message, | 
| -                                      jstring j_destination_url) { | 
| -  uint32 session_id = j_session_id; | 
| +                                      jstring j_legacy_destination_url) { | 
| std::vector<uint8> message; | 
| JavaByteArrayToByteVector(env, j_message, &message); | 
| -  GURL destination_gurl = GURL(ConvertJavaStringToUTF8(env, j_destination_url)); | 
| -  if (!destination_gurl.is_valid() && !destination_gurl.is_empty()) { | 
| -    DLOG(WARNING) << "SessionMessage destination_url is invalid : " | 
| -                  << destination_gurl.possibly_invalid_spec(); | 
| -    destination_gurl = GURL::EmptyGURL();  // Replace invalid destination_url. | 
| -  } | 
| -  session_message_cb_.Run(session_id, message, destination_gurl); | 
| -} | 
| +  GURL legacy_destination_url = | 
| +      GURL(ConvertJavaStringToUTF8(env, j_legacy_destination_url)); | 
| +  // Note: Message type is not supported in MediaDrm. Do our best guess here. | 
| +  media::MediaKeys::MessageType message_type = | 
| +      legacy_destination_url.is_empty() ? media::MediaKeys::LICENSE_REQUEST | 
| +                                        : media::MediaKeys::LICENSE_RENEWAL; | 
|  | 
| -void MediaDrmBridge::OnSessionReady(JNIEnv* env, | 
| -                                    jobject j_media_drm, | 
| -                                    jint j_session_id) { | 
| -  uint32 session_id = j_session_id; | 
| -  session_ready_cb_.Run(session_id); | 
| -  // TODO(xhwang/jrummell): Move this when usableKeyIds/keyschange are | 
| -  // implemented. | 
| -  player_tracker_.NotifyNewKey(); | 
| +  session_message_cb_.Run(GetSessionId(env, j_session_id), message_type, | 
| +                          message, legacy_destination_url); | 
| } | 
|  | 
| void MediaDrmBridge::OnSessionClosed(JNIEnv* env, | 
| jobject j_media_drm, | 
| -                                     jint j_session_id) { | 
| -  uint32 session_id = j_session_id; | 
| -  session_closed_cb_.Run(session_id); | 
| -} | 
| - | 
| -void MediaDrmBridge::OnSessionError(JNIEnv* env, | 
| -                                    jobject j_media_drm, | 
| -                                    jint j_session_id) { | 
| -  uint32 session_id = j_session_id; | 
| -  session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); | 
| +                                     jbyteArray j_session_id) { | 
| +  session_closed_cb_.Run(GetSessionId(env, j_session_id)); | 
| +} | 
| + | 
| +void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env, | 
| +                                         jobject j_media_drm, | 
| +                                         jbyteArray j_session_id, | 
| +                                         bool has_additional_usable_key, | 
| +                                         jint j_key_status) { | 
| +  if (has_additional_usable_key) | 
| +    player_tracker_.NotifyNewKey(); | 
| + | 
| +  scoped_ptr<CdmKeyInformation> cdm_key_information(new CdmKeyInformation()); | 
| +  cdm_key_information->key_id.assign(kDummyKeyId, | 
| +                                     kDummyKeyId + sizeof(kDummyKeyId)); | 
| +  cdm_key_information->status = | 
| +      static_cast<CdmKeyInformation::KeyStatus>(j_key_status); | 
| +  CdmKeysInfo cdm_keys_info; | 
| +  cdm_keys_info.push_back(cdm_key_information.release()); | 
| + | 
| +  session_keys_change_cb_.Run(GetSessionId(env, j_session_id), | 
| +                              has_additional_usable_key, cdm_keys_info.Pass()); | 
| +} | 
| + | 
| +void MediaDrmBridge::OnLegacySessionError(JNIEnv* env, | 
| +                                          jobject j_media_drm, | 
| +                                          jbyteArray j_session_id, | 
| +                                          jstring j_error_message) { | 
| +  std::string error_message = ConvertJavaStringToUTF8(env, j_error_message); | 
| +  session_error_cb_.Run(GetSessionId(env, j_session_id), | 
| +                        MediaKeys::UNKNOWN_ERROR, 0, error_message); | 
| } | 
|  | 
| ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() { | 
|  |