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

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: latest CDM_5 Created 6 years, 7 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/android/renderer_media_player_manager.h" 23 #include "content/renderer/media/android/renderer_media_player_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 RendererMediaPlayerManager* manager, 37 RendererMediaPlayerManager* 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.
109 uint32 session_id = next_session_id_++;
110
111 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; 101 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
112 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; 102 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
103 DVLOG(1) << "GenerateKeyRequest()";
113 104
114 if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { 105 if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
115 persistent_sessions_.insert(session_id); 106 scoped_ptr<media::CdmNewSessionPromise> promise(
107 new media::CdmNewSessionPromise(
108 base::Bind(&ProxyDecryptor::SetSessionId,
109 weak_ptr_factory_.GetWeakPtr(),
110 true), // Persistent session.
111 base::Bind(&ProxyDecryptor::OnSessionError,
112 weak_ptr_factory_.GetWeakPtr(),
113 std::string()))); // No session id until created.
116 media_keys_->LoadSession( 114 media_keys_->LoadSession(
117 session_id,
118 std::string(reinterpret_cast<const char*>( 115 std::string(reinterpret_cast<const char*>(
119 init_data + strlen(kPrefixedApiLoadSessionHeader)), 116 init_data + strlen(kPrefixedApiLoadSessionHeader)),
120 init_data_length - strlen(kPrefixedApiLoadSessionHeader))); 117 init_data_length - strlen(kPrefixedApiLoadSessionHeader)),
118 promise.Pass());
121 return true; 119 return true;
122 } 120 }
123 121
124 if (HasHeader( 122 bool persistent = HasHeader(
125 init_data, init_data_length, kPrefixedApiPersistentSessionHeader)) 123 init_data, init_data_length, kPrefixedApiPersistentSessionHeader);
126 persistent_sessions_.insert(session_id); 124 media::MediaKeys::SessionType session_type =
125 persistent ? media::MediaKeys::SESSION_TYPE_PERSISTENT
126 : media::MediaKeys::SESSION_TYPE_TEMPORARY;
127 127
128 return media_keys_->CreateSession( 128 scoped_ptr<media::CdmNewSessionPromise> promise(
129 session_id, content_type, init_data, init_data_length); 129 new media::CdmNewSessionPromise(
130 base::Bind(&ProxyDecryptor::SetSessionId,
131 weak_ptr_factory_.GetWeakPtr(),
132 persistent),
133 base::Bind(&ProxyDecryptor::OnSessionError,
134 weak_ptr_factory_.GetWeakPtr(),
135 std::string())));
136 media_keys_->CreateSession(
137 content_type, init_data, init_data_length, session_type, promise.Pass());
138 return true;
130 } 139 }
131 140
132 void ProxyDecryptor::AddKey(const uint8* key, 141 void ProxyDecryptor::AddKey(const uint8* key,
133 int key_length, 142 int key_length,
134 const uint8* init_data, 143 const uint8* init_data,
135 int init_data_length, 144 int init_data_length,
136 const std::string& web_session_id) { 145 const std::string& web_session_id) {
137 DVLOG(1) << "AddKey()"; 146 DVLOG(1) << "AddKey()";
138 147
139 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. 148 // If |web_session_id| is null, then use the single reference id.
140 uint32 session_id = LookupSessionId(web_session_id); 149 std::string session_id(web_session_id);
141 if (session_id == kInvalidSessionId) { 150 if (session_id.empty()) {
142 // Session hasn't been referenced before, so it is an error. 151 if (active_sessions_.size() == 1) {
143 // Note that the specification says "If sessionId is not null and is 152 std::set<std::string>::iterator it = active_sessions_.begin();
144 // unrecognized, throw an INVALID_ACCESS_ERR." However, for backwards 153 session_id = *it;
145 // compatibility the error is not thrown, but rather reported as a 154 } else {
146 // KeyError. 155 OnSessionError(std::string(),
147 key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0); 156 media::MediaKeys::MEDIA_KEYS_EXCEPTION_NOT_SUPPORTED_ERROR,
148 return; 157 0,
158 "SessionId not specified.");
159 return;
160 }
149 } 161 }
150 162
163 scoped_ptr<media::CdmChangeSessionPromise> promise(
164 new media::CdmChangeSessionPromise(
165 base::Bind(&ProxyDecryptor::OnSessionReady,
166 weak_ptr_factory_.GetWeakPtr(),
167 web_session_id),
168 base::Bind(&ProxyDecryptor::OnSessionError,
169 weak_ptr_factory_.GetWeakPtr(),
170 web_session_id)));
171
151 // EME WD spec only supports a single array passed to the CDM. For 172 // 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). 173 // 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, 174 // 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. 175 // convert the 2 arrays to a JWK and pass it as the single array.
155 if (is_clear_key_) { 176 if (is_clear_key_) {
156 // Decryptor doesn't support empty key ID (see http://crbug.com/123265). 177 // Decryptor doesn't support empty key ID (see http://crbug.com/123265).
157 // So ensure a non-empty value is passed. 178 // So ensure a non-empty value is passed.
158 if (!init_data) { 179 if (!init_data) {
159 static const uint8 kDummyInitData[1] = {0}; 180 static const uint8 kDummyInitData[1] = {0};
160 init_data = kDummyInitData; 181 init_data = kDummyInitData;
161 init_data_length = arraysize(kDummyInitData); 182 init_data_length = arraysize(kDummyInitData);
162 } 183 }
163 184
164 std::string jwk = 185 std::string jwk =
165 media::GenerateJWKSet(key, key_length, init_data, init_data_length); 186 media::GenerateJWKSet(key, key_length, init_data, init_data_length);
166 DCHECK(!jwk.empty()); 187 DCHECK(!jwk.empty());
167 media_keys_->UpdateSession( 188 media_keys_->UpdateSession(session_id,
168 session_id, reinterpret_cast<const uint8*>(jwk.data()), jwk.size()); 189 reinterpret_cast<const uint8*>(jwk.data()),
190 jwk.size(),
191 promise.Pass());
169 return; 192 return;
170 } 193 }
171 194
172 media_keys_->UpdateSession(session_id, key, key_length); 195 media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
173 } 196 }
174 197
175 void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) { 198 void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
176 DVLOG(1) << "CancelKeyRequest()"; 199 DVLOG(1) << "CancelKeyRequest()";
177 200
178 // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called. 201 scoped_ptr<media::CdmChangeSessionPromise> promise(
179 uint32 session_reference_id = LookupSessionId(session_id); 202 new media::CdmChangeSessionPromise(
180 if (session_reference_id == kInvalidSessionId) { 203 base::Bind(&ProxyDecryptor::OnSessionClosed,
181 // Session hasn't been created, so it is an error. 204 weak_ptr_factory_.GetWeakPtr(),
182 key_error_cb_.Run( 205 web_session_id),
183 std::string(), media::MediaKeys::kUnknownError, 0); 206 base::Bind(&ProxyDecryptor::OnSessionError,
184 } 207 weak_ptr_factory_.GetWeakPtr(),
185 else { 208 web_session_id)));
186 media_keys_->ReleaseSession(session_reference_id); 209 media_keys_->ReleaseSession(web_session_id, promise.Pass());
187 }
188 } 210 }
189 211
190 scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( 212 scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
191 const std::string& key_system, 213 const std::string& key_system,
192 const GURL& security_origin) { 214 const GURL& security_origin) {
193 return ContentDecryptionModuleFactory::Create( 215 return ContentDecryptionModuleFactory::Create(
194 key_system, 216 key_system,
195 security_origin, 217 security_origin,
196 #if defined(ENABLE_PEPPER_CDMS) 218 #if defined(ENABLE_PEPPER_CDMS)
197 create_pepper_cdm_cb_, 219 create_pepper_cdm_cb_,
198 #elif defined(OS_ANDROID) 220 #elif defined(OS_ANDROID)
199 manager_, 221 manager_,
200 &cdm_id_, 222 &cdm_id_,
201 #endif // defined(ENABLE_PEPPER_CDMS) 223 #endif // defined(ENABLE_PEPPER_CDMS)
202 base::Bind(&ProxyDecryptor::OnSessionCreated,
203 weak_ptr_factory_.GetWeakPtr()),
204 base::Bind(&ProxyDecryptor::OnSessionMessage, 224 base::Bind(&ProxyDecryptor::OnSessionMessage,
205 weak_ptr_factory_.GetWeakPtr()), 225 weak_ptr_factory_.GetWeakPtr()),
206 base::Bind(&ProxyDecryptor::OnSessionReady, 226 base::Bind(&ProxyDecryptor::OnSessionReady,
207 weak_ptr_factory_.GetWeakPtr()), 227 weak_ptr_factory_.GetWeakPtr()),
208 base::Bind(&ProxyDecryptor::OnSessionClosed, 228 base::Bind(&ProxyDecryptor::OnSessionClosed,
209 weak_ptr_factory_.GetWeakPtr()), 229 weak_ptr_factory_.GetWeakPtr()),
210 base::Bind(&ProxyDecryptor::OnSessionError, 230 base::Bind(&ProxyDecryptor::OnSessionError,
211 weak_ptr_factory_.GetWeakPtr())); 231 weak_ptr_factory_.GetWeakPtr()));
212 } 232 }
213 233
214 void ProxyDecryptor::OnSessionCreated(uint32 session_id, 234 void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
215 const std::string& web_session_id) { 235 const std::vector<uint8>& message,
216 // Due to heartbeat messages, OnSessionCreated() can get called multiple 236 const std::string& destination_url) {
217 // times. 237 key_message_cb_.Run(web_session_id, message, destination_url);
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 } 238 }
223 239
224 void ProxyDecryptor::OnSessionMessage(uint32 session_id, 240 void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
225 const std::vector<uint8>& message, 241 key_added_cb_.Run(web_session_id);
226 const std::string& destination_url) {
227 // Assumes that OnSessionCreated() has been called before this.
228 key_message_cb_.Run(LookupWebSessionId(session_id), message, destination_url);
229 } 242 }
230 243
231 void ProxyDecryptor::OnSessionReady(uint32 session_id) { 244 void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
232 // Assumes that OnSessionCreated() has been called before this. 245 std::set<std::string>::iterator it =
233 key_added_cb_.Run(LookupWebSessionId(session_id)); 246 persistent_sessions_.find(web_session_id);
247 active_sessions_.erase(web_session_id);
248 if (it != persistent_sessions_.end()) {
249 persistent_sessions_.erase(it);
250 OnSessionError(web_session_id,
251 media::MediaKeys::MEDIA_KEYS_EXCEPTION_NOT_SUPPORTED_ERROR,
ddorwin 2014/05/13 22:44:02 I see a mix of enum naming styles. (This is the Ch
jrummell 2014/05/15 22:38:09 Looks like ENUM_NAME is the preferred style. Remov
252 kSessionClosedSystemCode,
253 "Do not close persistent sessions.");
254 }
234 } 255 }
235 256
236 void ProxyDecryptor::OnSessionClosed(uint32 session_id) { 257 void ProxyDecryptor::OnSessionError(
237 std::set<uint32>::iterator it = persistent_sessions_.find(session_id); 258 const std::string& web_session_id,
238 if (it != persistent_sessions_.end()) { 259 media::MediaKeys::MediaKeysException exception_code,
239 persistent_sessions_.erase(it); 260 uint32 system_code,
240 OnSessionError( 261 const std::string& error_message) {
241 session_id, media::MediaKeys::kUnknownError, kSessionClosedSystemCode); 262 // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed
263 // EME has different error message, so all the specific error events will
264 // get lost.
265 switch (exception_code) {
ddorwin 2014/05/13 22:44:02 The switch should convert the exception then there
jrummell 2014/05/15 22:38:09 Done.
266 case media::MediaKeys::MEDIA_KEYS_EXCEPTION_CLIENT_ERROR:
267 key_error_cb_.Run(
268 web_session_id, media::MediaKeys::kClientError, system_code);
269 break;
270 case media::MediaKeys::MEDIA_KEYS_EXCEPTION_OUTPUT_ERROR:
271 key_error_cb_.Run(
272 web_session_id, media::MediaKeys::kOutputError, system_code);
273 break;
274 default:
275 // This will include all other CDM4 errors and any error generated
276 // by CDM5 or later.
277 key_error_cb_.Run(
278 web_session_id, media::MediaKeys::kUnknownError, system_code);
279 break;
242 } 280 }
243
244 sessions_.erase(session_id);
245 } 281 }
246 282
247 void ProxyDecryptor::OnSessionError(uint32 session_id, 283 void ProxyDecryptor::SetSessionId(bool persistent,
248 media::MediaKeys::KeyError error_code, 284 const std::string& web_session_id) {
249 uint32 system_code) { 285 active_sessions_.insert(web_session_id);
250 // Assumes that OnSessionCreated() has been called before this. 286 if (persistent) {
251 key_error_cb_.Run(LookupWebSessionId(session_id), error_code, system_code); 287 persistent_sessions_.insert(web_session_id);
252 }
253
254 uint32 ProxyDecryptor::LookupSessionId(const std::string& session_id) const {
255 for (SessionIdMap::const_iterator it = sessions_.begin();
256 it != sessions_.end();
257 ++it) {
258 if (it->second == session_id)
259 return it->first;
260 } 288 }
261
262 // If |session_id| is null, then use the single reference id.
263 if (session_id.empty() && sessions_.size() == 1)
264 return sessions_.begin()->first;
265
266 return kInvalidSessionId;
267 }
268
269 const std::string& ProxyDecryptor::LookupWebSessionId(uint32 session_id) const {
270 DCHECK_NE(session_id, kInvalidSessionId);
271
272 // Session may not exist if error happens during GenerateKeyRequest().
273 SessionIdMap::const_iterator it = sessions_.find(session_id);
274 return (it != sessions_.end()) ? it->second : base::EmptyString();
275 } 289 }
276 290
277 } // namespace content 291 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698