1 // Copyright 2013 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/webcontentdecryptionmodule_impl.h" 6 7 #include <map> 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/bind.h" 12 #include "base/callback_helpers.h" 13 #include "base/logging.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/strings/string_util.h" 16 #include "content/renderer/media/crypto/content_decryption_module_factory.h" 17 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" 18 #include "media/base/media_keys.h" 19 #include "url/gurl.h" 20 21 namespace content { 22 23 // Forwards the session ID-based callbacks of the MediaKeys interface to the 24 // appropriate session object. 25 class SessionIdAdapter { 26 public: 27 SessionIdAdapter(); 28 ~SessionIdAdapter(); 29 30 // On success, creates a MediaKeys, returns it in |media_keys|, returns true. 31 bool Initialize(const std::string& key_system, 32 scoped_ptr<media::MediaKeys>* media_keys); 33 34 // Generates a unique internal session id. 35 uint32 GenerateSessionId(); 36 37 // Adds a session to the internal map. Does not take ownership of the session. 38 void AddSession(uint32 session_id, 39 WebContentDecryptionModuleSessionImpl* session); 40 41 // Removes a session from the internal map. 42 void RemoveSession(uint32 session_id); 43 44 private: 45 typedef std::map<uint32, WebContentDecryptionModuleSessionImpl*> SessionMap; 46 47 // Callbacks for firing session events. 48 void OnSessionCreated(uint32 session_id, const std::string& web_session_id); 49 void OnSessionMessage(uint32 session_id, 50 const std::vector<uint8>& message, 51 const std::string& destination_url); 52 void OnSessionReady(uint32 session_id); 53 void OnSessionClosed(uint32 session_id); 54 void OnSessionError(uint32 session_id, 55 media::MediaKeys::KeyError error_code, 56 int system_code); 57 58 // Helper function of the callbacks. 59 WebContentDecryptionModuleSessionImpl* GetSession(uint32 session_id); 60 61 base::WeakPtrFactory<SessionIdAdapter> weak_ptr_factory_; 62 63 SessionMap sessions_; 64 65 // Session ID should be unique per renderer process for debugging purposes. 66 static uint32 next_session_id_; 67 68 DISALLOW_COPY_AND_ASSIGN(SessionIdAdapter); 69 }; 70 71 const uint32 kStartingSessionId = 1; 72 uint32 SessionIdAdapter::next_session_id_ = kStartingSessionId; 73 COMPILE_ASSERT(kStartingSessionId > media::MediaKeys::kInvalidSessionId, 74 invalid_starting_value); 75 76 SessionIdAdapter::SessionIdAdapter() 77 : weak_ptr_factory_(this) { 78 } 79 80 SessionIdAdapter::~SessionIdAdapter() { 81 } 82 83 bool SessionIdAdapter::Initialize(const std::string& key_system, 84 scoped_ptr<media::MediaKeys>* media_keys) { 85 DCHECK(media_keys); 86 DCHECK(!*media_keys); 87 88 base::WeakPtr<SessionIdAdapter> weak_this = weak_ptr_factory_.GetWeakPtr(); 89 scoped_ptr<media::MediaKeys> created_media_keys = 90 ContentDecryptionModuleFactory::Create( 91 // TODO(ddorwin): Address lower in the stack: http://crbug.com/252065 92 "webkit-" + key_system, 93 #if defined(ENABLE_PEPPER_CDMS) 94 // TODO(ddorwin): Support Pepper-based CDMs: http://crbug.com/250049 95 NULL, 96 NULL, 97 base::Closure(), 98 #elif defined(OS_ANDROID) 99 // TODO(xhwang): Support Android. 100 NULL, 101 0, 102 // TODO(ddorwin): Get the URL for the frame containing the MediaKeys. 103 GURL(), 104 #endif // defined(ENABLE_PEPPER_CDMS) 105 base::Bind(&SessionIdAdapter::OnSessionCreated, weak_this), 106 base::Bind(&SessionIdAdapter::OnSessionMessage, weak_this), 107 base::Bind(&SessionIdAdapter::OnSessionReady, weak_this), 108 base::Bind(&SessionIdAdapter::OnSessionClosed, weak_this), 109 base::Bind(&SessionIdAdapter::OnSessionError, weak_this)); 110 if (!created_media_keys) 111 return false; 112 113 *media_keys = created_media_keys.Pass(); 114 return true; 115 } 116 117 uint32 SessionIdAdapter::GenerateSessionId() { 118 return next_session_id_++; 119 } 120 121 void SessionIdAdapter::AddSession( 122 uint32 session_id, 123 WebContentDecryptionModuleSessionImpl* session) { 124 DCHECK(sessions_.find(session_id) == sessions_.end()); 125 sessions_[session_id] = session; 126 } 127 128 void SessionIdAdapter::RemoveSession(uint32 session_id) { 129 DCHECK(sessions_.find(session_id) != sessions_.end()); 130 sessions_.erase(session_id); 131 } 132 133 void SessionIdAdapter::OnSessionCreated(uint32 session_id, 134 const std::string& web_session_id) { 135 GetSession(session_id)->OnSessionCreated(web_session_id); 136 } 137 138 void SessionIdAdapter::OnSessionMessage(uint32 session_id, 139 const std::vector<uint8>& message, 140 const std::string& destination_url) { 141 GetSession(session_id)->OnSessionMessage(message, destination_url); 142 } 143 144 void SessionIdAdapter::OnSessionReady(uint32 session_id) { 145 GetSession(session_id)->OnSessionReady(); 146 } 147 148 void SessionIdAdapter::OnSessionClosed(uint32 session_id) { 149 GetSession(session_id)->OnSessionClosed(); 150 } 151 152 void SessionIdAdapter::OnSessionError(uint32 session_id, 153 media::MediaKeys::KeyError error_code, 154 int system_code) { 155 GetSession(session_id)->OnSessionError(error_code, system_code); 156 } 157 158 WebContentDecryptionModuleSessionImpl* SessionIdAdapter::GetSession( 159 uint32 session_id) { 160 DCHECK(sessions_.find(session_id) != sessions_.end()); 161 return sessions_[session_id]; 162 } 163 164 //------------------------------------------------------------------------------ 165 166 WebContentDecryptionModuleImpl* 167 WebContentDecryptionModuleImpl::Create(const base::string16& key_system) { 168 // TODO(ddorwin): Guard against this in supported types check and remove this. 169 // Chromium only supports ASCII key systems. 170 if (!IsStringASCII(key_system)) { 171 NOTREACHED(); 172 return NULL; 173 } 174 175 // SessionIdAdapter creates the MediaKeys so it can provide its callbacks to 176 // during creation of the MediaKeys. 177 scoped_ptr<media::MediaKeys> media_keys; 178 scoped_ptr<SessionIdAdapter> adapter(new SessionIdAdapter()); 179 if (!adapter->Initialize(UTF16ToASCII(key_system), &media_keys)) 180 return NULL; 181 182 return new WebContentDecryptionModuleImpl(media_keys.Pass(), adapter.Pass()); 183 } 184 185 WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl( 186 scoped_ptr<media::MediaKeys> media_keys, 187 scoped_ptr<SessionIdAdapter> adapter) 188 : media_keys_(media_keys.Pass()), 189 adapter_(adapter.Pass()) { 190 } 191 192 WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() { 193 } 194 195 // The caller owns the created session. 196 blink::WebContentDecryptionModuleSession* 197 WebContentDecryptionModuleImpl::createSession( 198 blink::WebContentDecryptionModuleSession::Client* client) { 199 DCHECK(media_keys_); 200 uint32 session_id = adapter_->GenerateSessionId(); 201 WebContentDecryptionModuleSessionImpl* session = 202 new WebContentDecryptionModuleSessionImpl( 203 session_id, 204 media_keys_.get(), 205 client, 206 base::Bind(&WebContentDecryptionModuleImpl::OnSessionClosed, 207 base::Unretained(this))); 208 209 adapter_->AddSession(session_id, session); 210 return session; 211 } 212 213 void WebContentDecryptionModuleImpl::OnSessionClosed(uint32 session_id) { 214 adapter_->RemoveSession(session_id); 215 } 216 217 } // namespace content 218