1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/cdm_session_adapter.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/stl_util.h" 11 #include "content/renderer/media/crypto/content_decryption_module_factory.h" 12 #include "content/renderer/media/crypto/key_systems.h" 13 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" 14 #include "media/base/cdm_promise.h" 15 #include "media/base/media_keys.h" 16 #include "url/gurl.h" 17 18 namespace content { 19 20 const char kMediaEME[] = "Media.EME."; 21 const char kDot[] = "."; 22 23 CdmSessionAdapter::CdmSessionAdapter() : 24 #if defined(ENABLE_BROWSER_CDMS) 25 cdm_id_(0), 26 #endif 27 weak_ptr_factory_(this) {} 28 29 CdmSessionAdapter::~CdmSessionAdapter() {} 30 31 bool CdmSessionAdapter::Initialize( 32 #if defined(ENABLE_PEPPER_CDMS) 33 const CreatePepperCdmCB& create_pepper_cdm_cb, 34 #elif defined(ENABLE_BROWSER_CDMS) 35 RendererCdmManager* manager, 36 #endif // defined(ENABLE_PEPPER_CDMS) 37 const std::string& key_system, 38 const GURL& security_origin) { 39 key_system_uma_prefix_ = kMediaEME + KeySystemNameForUMA(key_system) + kDot; 40 base::WeakPtr<CdmSessionAdapter> weak_this = weak_ptr_factory_.GetWeakPtr(); 41 media_keys_ = ContentDecryptionModuleFactory::Create( 42 key_system, 43 security_origin, 44 #if defined(ENABLE_PEPPER_CDMS) 45 create_pepper_cdm_cb, 46 #elif defined(ENABLE_BROWSER_CDMS) 47 manager, 48 &cdm_id_, 49 #endif // defined(ENABLE_PEPPER_CDMS) 50 base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this), 51 base::Bind(&CdmSessionAdapter::OnSessionReady, weak_this), 52 base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this), 53 base::Bind(&CdmSessionAdapter::OnSessionError, weak_this), 54 base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this), 55 base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this)); 56 57 // Success if |media_keys_| created. 58 return media_keys_; 59 } 60 61 void CdmSessionAdapter::SetServerCertificate( 62 const uint8* server_certificate, 63 int server_certificate_length, 64 scoped_ptr<media::SimpleCdmPromise> promise) { 65 media_keys_->SetServerCertificate( 66 server_certificate, server_certificate_length, promise.Pass()); 67 } 68 69 WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() { 70 return new WebContentDecryptionModuleSessionImpl(this); 71 } 72 73 bool CdmSessionAdapter::RegisterSession( 74 const std::string& web_session_id, 75 base::WeakPtr<WebContentDecryptionModuleSessionImpl> session) { 76 // If this session ID is already registered, don't register it again. 77 if (ContainsKey(sessions_, web_session_id)) 78 return false; 79 80 sessions_[web_session_id] = session; 81 return true; 82 } 83 84 void CdmSessionAdapter::UnregisterSession(const std::string& web_session_id) { 85 DCHECK(ContainsKey(sessions_, web_session_id)); 86 sessions_.erase(web_session_id); 87 } 88 89 void CdmSessionAdapter::InitializeNewSession( 90 const std::string& init_data_type, 91 const uint8* init_data, 92 int init_data_length, 93 media::MediaKeys::SessionType session_type, 94 scoped_ptr<media::NewSessionCdmPromise> promise) { 95 media_keys_->CreateSession(init_data_type, 96 init_data, 97 init_data_length, 98 session_type, 99 promise.Pass()); 100 } 101 102 void CdmSessionAdapter::UpdateSession( 103 const std::string& web_session_id, 104 const uint8* response, 105 int response_length, 106 scoped_ptr<media::SimpleCdmPromise> promise) { 107 media_keys_->UpdateSession( 108 web_session_id, response, response_length, promise.Pass()); 109 } 110 111 void CdmSessionAdapter::CloseSession( 112 const std::string& web_session_id, 113 scoped_ptr<media::SimpleCdmPromise> promise) { 114 media_keys_->CloseSession(web_session_id, promise.Pass()); 115 } 116 117 void CdmSessionAdapter::RemoveSession( 118 const std::string& web_session_id, 119 scoped_ptr<media::SimpleCdmPromise> promise) { 120 media_keys_->RemoveSession(web_session_id, promise.Pass()); 121 } 122 123 void CdmSessionAdapter::GetUsableKeyIds( 124 const std::string& web_session_id, 125 scoped_ptr<media::KeyIdsPromise> promise) { 126 media_keys_->GetUsableKeyIds(web_session_id, promise.Pass()); 127 } 128 129 media::Decryptor* CdmSessionAdapter::GetDecryptor() { 130 return media_keys_->GetDecryptor(); 131 } 132 133 const std::string& CdmSessionAdapter::GetKeySystemUMAPrefix() const { 134 return key_system_uma_prefix_; 135 } 136 137 #if defined(ENABLE_BROWSER_CDMS) 138 int CdmSessionAdapter::GetCdmId() const { 139 return cdm_id_; 140 } 141 #endif // defined(ENABLE_BROWSER_CDMS) 142 143 void CdmSessionAdapter::OnSessionMessage(const std::string& web_session_id, 144 const std::vector<uint8>& message, 145 const GURL& destination_url) { 146 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 147 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 148 << web_session_id; 149 if (session) 150 session->OnSessionMessage(message, destination_url); 151 } 152 153 void CdmSessionAdapter::OnSessionKeysChange(const std::string& web_session_id, 154 bool has_additional_usable_key) { 155 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 156 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 157 << web_session_id; 158 if (session) 159 session->OnSessionKeysChange(has_additional_usable_key); 160 } 161 162 void CdmSessionAdapter::OnSessionExpirationUpdate( 163 const std::string& web_session_id, 164 const base::Time& new_expiry_time) { 165 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 166 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 167 << web_session_id; 168 if (session) 169 session->OnSessionExpirationUpdate(new_expiry_time); 170 } 171 172 void CdmSessionAdapter::OnSessionReady(const std::string& web_session_id) { 173 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 174 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 175 << web_session_id; 176 if (session) 177 session->OnSessionReady(); 178 } 179 180 void CdmSessionAdapter::OnSessionClosed(const std::string& web_session_id) { 181 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 182 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 183 << web_session_id; 184 if (session) 185 session->OnSessionClosed(); 186 } 187 188 void CdmSessionAdapter::OnSessionError( 189 const std::string& web_session_id, 190 media::MediaKeys::Exception exception_code, 191 uint32 system_code, 192 const std::string& error_message) { 193 WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id); 194 DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session " 195 << web_session_id; 196 if (session) 197 session->OnSessionError(exception_code, system_code, error_message); 198 } 199 200 WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::GetSession( 201 const std::string& web_session_id) { 202 // Since session objects may get garbage collected, it is possible that there 203 // are events coming back from the CDM and the session has been unregistered. 204 // We can not tell if the CDM is firing events at sessions that never existed. 205 SessionMap::iterator session = sessions_.find(web_session_id); 206 return (session != sessions_.end()) ? session->second.get() : NULL; 207 } 208 209 } // namespace content 210