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
SessionIdAdapter()76 SessionIdAdapter::SessionIdAdapter()
77 : weak_ptr_factory_(this) {
78 }
79
~SessionIdAdapter()80 SessionIdAdapter::~SessionIdAdapter() {
81 }
82
Initialize(const std::string & key_system,scoped_ptr<media::MediaKeys> * media_keys)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
GenerateSessionId()117 uint32 SessionIdAdapter::GenerateSessionId() {
118 return next_session_id_++;
119 }
120
AddSession(uint32 session_id,WebContentDecryptionModuleSessionImpl * session)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
RemoveSession(uint32 session_id)128 void SessionIdAdapter::RemoveSession(uint32 session_id) {
129 DCHECK(sessions_.find(session_id) != sessions_.end());
130 sessions_.erase(session_id);
131 }
132
OnSessionCreated(uint32 session_id,const std::string & web_session_id)133 void SessionIdAdapter::OnSessionCreated(uint32 session_id,
134 const std::string& web_session_id) {
135 GetSession(session_id)->OnSessionCreated(web_session_id);
136 }
137
OnSessionMessage(uint32 session_id,const std::vector<uint8> & message,const std::string & destination_url)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
OnSessionReady(uint32 session_id)144 void SessionIdAdapter::OnSessionReady(uint32 session_id) {
145 GetSession(session_id)->OnSessionReady();
146 }
147
OnSessionClosed(uint32 session_id)148 void SessionIdAdapter::OnSessionClosed(uint32 session_id) {
149 GetSession(session_id)->OnSessionClosed();
150 }
151
OnSessionError(uint32 session_id,media::MediaKeys::KeyError error_code,int system_code)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
GetSession(uint32 session_id)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*
Create(const base::string16 & key_system)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
WebContentDecryptionModuleImpl(scoped_ptr<media::MediaKeys> media_keys,scoped_ptr<SessionIdAdapter> adapter)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
~WebContentDecryptionModuleImpl()192 WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() {
193 }
194
195 // The caller owns the created session.
196 blink::WebContentDecryptionModuleSession*
createSession(blink::WebContentDecryptionModuleSession::Client * client)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
OnSessionClosed(uint32 session_id)213 void WebContentDecryptionModuleImpl::OnSessionClosed(uint32 session_id) {
214 adapter_->RemoveSession(session_id);
215 }
216
217 } // namespace content
218