Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: content/renderer/media/crypto/proxy_decryptor.cc

Issue 265993002: Add Promises for EME (Chromium side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: One more trybot issue Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/crypto/proxy_decryptor.h" 5 #include "content/renderer/media/crypto/proxy_decryptor.h"
6 6
7 #include <cstring> 7 #include <cstring>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "content/renderer/media/crypto/content_decryption_module_factory.h" 13 #include "content/renderer/media/crypto/content_decryption_module_factory.h"
14 #include "media/base/cdm_promise.h"
14 #include "media/cdm/json_web_key.h" 15 #include "media/cdm/json_web_key.h"
15 #include "media/cdm/key_system_names.h" 16 #include "media/cdm/key_system_names.h"
16 17
17 #if defined(ENABLE_PEPPER_CDMS) 18 #if defined(ENABLE_PEPPER_CDMS)
18 #include "content/renderer/media/crypto/pepper_cdm_wrapper.h" 19 #include "content/renderer/media/crypto/pepper_cdm_wrapper.h"
19 #endif // defined(ENABLE_PEPPER_CDMS) 20 #endif // defined(ENABLE_PEPPER_CDMS)
20 21
21 #if defined(OS_ANDROID) 22 #if defined(OS_ANDROID)
22 #include "content/renderer/media/crypto/renderer_cdm_manager.h" 23 #include "content/renderer/media/crypto/renderer_cdm_manager.h"
23 #endif // defined(OS_ANDROID) 24 #endif // defined(OS_ANDROID)
24 25
25 namespace content { 26 namespace content {
26 27
27 // Since these reference IDs may conflict with the ones generated in
28 // WebContentDecryptionModuleSessionImpl for the short time both paths are
29 // active, start with 100000 and generate the IDs from there.
30 // TODO(jrummell): Only allow one path http://crbug.com/306680.
31 uint32 ProxyDecryptor::next_session_id_ = 100000;
32
33 const uint32 kInvalidSessionId = 0;
34
35 // Special system code to signal a closed persistent session in a SessionError() 28 // Special system code to signal a closed persistent session in a SessionError()
36 // call. This is needed because there is no SessionClosed() call in the prefixed 29 // call. This is needed because there is no SessionClosed() call in the prefixed
37 // EME API. 30 // EME API.
38 const int kSessionClosedSystemCode = 29127; 31 const int kSessionClosedSystemCode = 29127;
39 32
40 ProxyDecryptor::ProxyDecryptor( 33 ProxyDecryptor::ProxyDecryptor(
41 #if defined(ENABLE_PEPPER_CDMS) 34 #if defined(ENABLE_PEPPER_CDMS)
42 const CreatePepperCdmCB& create_pepper_cdm_cb, 35 const CreatePepperCdmCB& create_pepper_cdm_cb,
43 #elif defined(OS_ANDROID) 36 #elif defined(OS_ANDROID)
44 RendererCdmManager* manager, 37 RendererCdmManager* manager,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 // Returns true if |data| is prefixed with |header| and has data after the 91 // Returns true if |data| is prefixed with |header| and has data after the
99 // |header|. 92 // |header|.
100 bool HasHeader(const uint8* data, int data_length, const std::string& header) { 93 bool HasHeader(const uint8* data, int data_length, const std::string& header) {
101 return static_cast<size_t>(data_length) > header.size() && 94 return static_cast<size_t>(data_length) > header.size() &&
102 std::equal(data, data + header.size(), header.begin()); 95 std::equal(data, data + header.size(), header.begin());
103 } 96 }
104 97
105 bool ProxyDecryptor::GenerateKeyRequest(const std::string& content_type, 98 bool ProxyDecryptor::GenerateKeyRequest(const std::string& content_type,
106 const uint8* init_data, 99 const uint8* init_data,
107 int init_data_length) { 100 int init_data_length) {
108 // Use a unique reference id for this request. 101 DVLOG(1) << "GenerateKeyRequest()";
109 uint32 session_id = next_session_id_++;
110
111 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; 102 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
112 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; 103 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
113 104
114 if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { 105 bool loadSession =
115 persistent_sessions_.insert(session_id); 106 HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader);
107 bool persistent = HasHeader(
108 init_data, init_data_length, kPrefixedApiPersistentSessionHeader);
109
110 scoped_ptr<media::NewSessionCdmPromise> promise(
111 new media::NewSessionCdmPromise(
112 base::Bind(&ProxyDecryptor::SetSessionId,
113 weak_ptr_factory_.GetWeakPtr(),
114 persistent || loadSession),
115 base::Bind(&ProxyDecryptor::OnSessionError,
116 weak_ptr_factory_.GetWeakPtr(),
117 std::string()))); // No session id until created.
118
119 if (loadSession) {
116 media_keys_->LoadSession( 120 media_keys_->LoadSession(
117 session_id,
118 std::string(reinterpret_cast<const char*>( 121 std::string(reinterpret_cast<const char*>(
119 init_data + strlen(kPrefixedApiLoadSessionHeader)), 122 init_data + strlen(kPrefixedApiLoadSessionHeader)),
120 init_data_length - strlen(kPrefixedApiLoadSessionHeader))); 123 init_data_length - strlen(kPrefixedApiLoadSessionHeader)),
124 promise.Pass());
121 return true; 125 return true;
122 } 126 }
123 127
124 if (HasHeader( 128 media::MediaKeys::SessionType session_type =
125 init_data, init_data_length, kPrefixedApiPersistentSessionHeader)) 129 persistent ? media::MediaKeys::PERSISTENT_SESSION
126 persistent_sessions_.insert(session_id); 130 : media::MediaKeys::TEMPORARY_SESSION;
127 131 media_keys_->CreateSession(
128 return media_keys_->CreateSession( 132 content_type, init_data, init_data_length, session_type, promise.Pass());
129 session_id, content_type, init_data, init_data_length); 133 return true;
130 } 134 }
131 135
132 void ProxyDecryptor::AddKey(const uint8* key, 136 void ProxyDecryptor::AddKey(const uint8* key,
133 int key_length, 137 int key_length,
134 const uint8* init_data, 138 const uint8* init_data,
135 int init_data_length, 139 int init_data_length,
136 const std::string& web_session_id) { 140 const std::string& web_session_id) {
137 DVLOG(1) << "AddKey()"; 141 DVLOG(1) << "AddKey()";
138 142
139 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. 143 // In the prefixed API, the session parameter provided to addKey() is
140 uint32 session_id = LookupSessionId(web_session_id); 144 // optional, so use the single existing session if it exists.
141 if (session_id == kInvalidSessionId) { 145 // TODO(jrummell): remove when the prefixed API is removed.
142 // Session hasn't been referenced before, so it is an error. 146 std::string session_id(web_session_id);
143 // Note that the specification says "If sessionId is not null and is 147 if (session_id.empty()) {
144 // unrecognized, throw an INVALID_ACCESS_ERR." However, for backwards 148 if (active_sessions_.size() == 1) {
145 // compatibility the error is not thrown, but rather reported as a 149 base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
146 // KeyError. 150 session_id = it->first;
147 key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0); 151 } else {
148 return; 152 OnSessionError(std::string(),
153 media::MediaKeys::NOT_SUPPORTED_ERROR,
154 0,
155 "SessionId not specified.");
156 return;
157 }
149 } 158 }
150 159
160 scoped_ptr<media::SimpleCdmPromise> promise(
161 new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionReady,
162 weak_ptr_factory_.GetWeakPtr(),
163 web_session_id),
164 base::Bind(&ProxyDecryptor::OnSessionError,
165 weak_ptr_factory_.GetWeakPtr(),
166 web_session_id)));
167
151 // EME WD spec only supports a single array passed to the CDM. For 168 // EME WD spec only supports a single array passed to the CDM. For
152 // Clear Key using v0.1b, both arrays are used (|init_data| is key_id). 169 // Clear Key using v0.1b, both arrays are used (|init_data| is key_id).
153 // Since the EME WD spec supports the key as a JSON Web Key, 170 // Since the EME WD spec supports the key as a JSON Web Key,
154 // convert the 2 arrays to a JWK and pass it as the single array. 171 // convert the 2 arrays to a JWK and pass it as the single array.
155 if (is_clear_key_) { 172 if (is_clear_key_) {
156 // Decryptor doesn't support empty key ID (see http://crbug.com/123265). 173 // Decryptor doesn't support empty key ID (see http://crbug.com/123265).
157 // So ensure a non-empty value is passed. 174 // So ensure a non-empty value is passed.
158 if (!init_data) { 175 if (!init_data) {
159 static const uint8 kDummyInitData[1] = {0}; 176 static const uint8 kDummyInitData[1] = {0};
160 init_data = kDummyInitData; 177 init_data = kDummyInitData;
161 init_data_length = arraysize(kDummyInitData); 178 init_data_length = arraysize(kDummyInitData);
162 } 179 }
163 180
164 std::string jwk = 181 std::string jwk =
165 media::GenerateJWKSet(key, key_length, init_data, init_data_length); 182 media::GenerateJWKSet(key, key_length, init_data, init_data_length);
166 DCHECK(!jwk.empty()); 183 DCHECK(!jwk.empty());
167 media_keys_->UpdateSession( 184 media_keys_->UpdateSession(session_id,
168 session_id, reinterpret_cast<const uint8*>(jwk.data()), jwk.size()); 185 reinterpret_cast<const uint8*>(jwk.data()),
186 jwk.size(),
187 promise.Pass());
169 return; 188 return;
170 } 189 }
171 190
172 media_keys_->UpdateSession(session_id, key, key_length); 191 media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
173 } 192 }
174 193
175 void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) { 194 void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
176 DVLOG(1) << "CancelKeyRequest()"; 195 DVLOG(1) << "CancelKeyRequest()";
177 196
178 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. 197 scoped_ptr<media::SimpleCdmPromise> promise(
179 uint32 session_reference_id = LookupSessionId(session_id); 198 new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionClosed,
180 if (session_reference_id == kInvalidSessionId) { 199 weak_ptr_factory_.GetWeakPtr(),
181 // Session hasn't been created, so it is an error. 200 web_session_id),
182 key_error_cb_.Run( 201 base::Bind(&ProxyDecryptor::OnSessionError,
183 std::string(), media::MediaKeys::kUnknownError, 0); 202 weak_ptr_factory_.GetWeakPtr(),
184 } 203 web_session_id)));
185 else { 204 media_keys_->ReleaseSession(web_session_id, promise.Pass());
186 media_keys_->ReleaseSession(session_reference_id);
187 }
188 } 205 }
189 206
190 scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( 207 scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
191 const std::string& key_system, 208 const std::string& key_system,
192 const GURL& security_origin) { 209 const GURL& security_origin) {
193 return ContentDecryptionModuleFactory::Create( 210 return ContentDecryptionModuleFactory::Create(
194 key_system, 211 key_system,
195 security_origin, 212 security_origin,
196 #if defined(ENABLE_PEPPER_CDMS) 213 #if defined(ENABLE_PEPPER_CDMS)
197 create_pepper_cdm_cb_, 214 create_pepper_cdm_cb_,
198 #elif defined(OS_ANDROID) 215 #elif defined(OS_ANDROID)
199 manager_, 216 manager_,
200 &cdm_id_, 217 &cdm_id_,
201 #endif // defined(ENABLE_PEPPER_CDMS) 218 #endif // defined(ENABLE_PEPPER_CDMS)
202 base::Bind(&ProxyDecryptor::OnSessionCreated,
203 weak_ptr_factory_.GetWeakPtr()),
204 base::Bind(&ProxyDecryptor::OnSessionMessage, 219 base::Bind(&ProxyDecryptor::OnSessionMessage,
205 weak_ptr_factory_.GetWeakPtr()), 220 weak_ptr_factory_.GetWeakPtr()),
206 base::Bind(&ProxyDecryptor::OnSessionReady, 221 base::Bind(&ProxyDecryptor::OnSessionReady,
207 weak_ptr_factory_.GetWeakPtr()), 222 weak_ptr_factory_.GetWeakPtr()),
208 base::Bind(&ProxyDecryptor::OnSessionClosed, 223 base::Bind(&ProxyDecryptor::OnSessionClosed,
209 weak_ptr_factory_.GetWeakPtr()), 224 weak_ptr_factory_.GetWeakPtr()),
210 base::Bind(&ProxyDecryptor::OnSessionError, 225 base::Bind(&ProxyDecryptor::OnSessionError,
211 weak_ptr_factory_.GetWeakPtr())); 226 weak_ptr_factory_.GetWeakPtr()));
212 } 227 }
213 228
214 void ProxyDecryptor::OnSessionCreated(uint32 session_id, 229 void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
215 const std::string& web_session_id) {
216 // Due to heartbeat messages, OnSessionCreated() can get called multiple
217 // times.
218 SessionIdMap::iterator it = sessions_.find(session_id);
219 DCHECK(it == sessions_.end() || it->second == web_session_id);
220 if (it == sessions_.end())
221 sessions_[session_id] = web_session_id;
222 }
223
224 void ProxyDecryptor::OnSessionMessage(uint32 session_id,
225 const std::vector<uint8>& message, 230 const std::vector<uint8>& message,
226 const GURL& destination_url) { 231 const GURL& destination_url) {
227 // Assumes that OnSessionCreated() has been called before this. 232 // Assumes that OnSessionCreated() has been called before this.
228 key_message_cb_.Run( 233 key_message_cb_.Run(web_session_id, message, destination_url);
229 LookupWebSessionId(session_id), message, destination_url);
230 } 234 }
231 235
232 void ProxyDecryptor::OnSessionReady(uint32 session_id) { 236 void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
233 // Assumes that OnSessionCreated() has been called before this. 237 key_added_cb_.Run(web_session_id);
234 key_added_cb_.Run(LookupWebSessionId(session_id));
235 } 238 }
236 239
237 void ProxyDecryptor::OnSessionClosed(uint32 session_id) { 240 void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
238 std::set<uint32>::iterator it = persistent_sessions_.find(session_id); 241 base::hash_map<std::string, bool>::iterator it =
239 if (it != persistent_sessions_.end()) { 242 active_sessions_.find(web_session_id);
240 persistent_sessions_.erase(it); 243 if (it->second) {
241 OnSessionError( 244 OnSessionError(web_session_id,
242 session_id, media::MediaKeys::kUnknownError, kSessionClosedSystemCode); 245 media::MediaKeys::NOT_SUPPORTED_ERROR,
246 kSessionClosedSystemCode,
247 "Do not close persistent sessions.");
243 } 248 }
244 249 active_sessions_.erase(it);
245 sessions_.erase(session_id);
246 } 250 }
247 251
248 void ProxyDecryptor::OnSessionError(uint32 session_id, 252 void ProxyDecryptor::OnSessionError(const std::string& web_session_id,
249 media::MediaKeys::KeyError error_code, 253 media::MediaKeys::Exception exception_code,
250 uint32 system_code) { 254 uint32 system_code,
251 // Assumes that OnSessionCreated() has been called before this. 255 const std::string& error_message) {
252 key_error_cb_.Run(LookupWebSessionId(session_id), error_code, system_code); 256 // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed
257 // EME has different error message, so all the specific error events will
258 // get lost.
259 media::MediaKeys::KeyError error_code;
260 switch (exception_code) {
261 case media::MediaKeys::CLIENT_ERROR:
262 error_code = media::MediaKeys::kClientError;
263 break;
264 case media::MediaKeys::OUTPUT_ERROR:
265 error_code = media::MediaKeys::kOutputError;
266 break;
267 default:
268 // This will include all other CDM4 errors and any error generated
269 // by CDM5 or later.
270 error_code = media::MediaKeys::kUnknownError;
271 break;
272 }
273 key_error_cb_.Run(web_session_id, error_code, system_code);
253 } 274 }
254 275
255 uint32 ProxyDecryptor::LookupSessionId(const std::string& session_id) const { 276 void ProxyDecryptor::SetSessionId(bool persistent,
256 for (SessionIdMap::const_iterator it = sessions_.begin(); 277 const std::string& web_session_id) {
257 it != sessions_.end(); 278 active_sessions_.insert(std::make_pair(web_session_id, persistent));
258 ++it) {
259 if (it->second == session_id)
260 return it->first;
261 }
262
263 // If |session_id| is null, then use the single reference id.
264 if (session_id.empty() && sessions_.size() == 1)
265 return sessions_.begin()->first;
266
267 return kInvalidSessionId;
268 }
269
270 const std::string& ProxyDecryptor::LookupWebSessionId(uint32 session_id) const {
271 DCHECK_NE(session_id, kInvalidSessionId);
272
273 // Session may not exist if error happens during GenerateKeyRequest().
274 SessionIdMap::const_iterator it = sessions_.find(session_id);
275 return (it != sessions_.end()) ? it->second : base::EmptyString();
276 } 279 }
277 280
278 } // namespace content 281 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/crypto/proxy_decryptor.h ('k') | content/renderer/media/crypto/proxy_media_keys.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698