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

Side by Side Diff: media/cdm/proxy_decryptor.cc

Issue 1070853004: media: CdmFactory creates CDM (MediaKeys) asynchronously. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments addressed Created 5 years, 8 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
« media/cdm/proxy_decryptor.h ('K') | « media/cdm/proxy_decryptor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "media/cdm/proxy_decryptor.h" 5 #include "media/cdm/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 "media/base/cdm_callback_promise.h" 13 #include "media/base/cdm_callback_promise.h"
14 #include "media/base/cdm_factory.h" 14 #include "media/base/cdm_factory.h"
15 #include "media/base/cdm_key_information.h" 15 #include "media/base/cdm_key_information.h"
16 #include "media/base/key_systems.h" 16 #include "media/base/key_systems.h"
17 #include "media/base/media_permission.h" 17 #include "media/base/media_permission.h"
18 #include "media/cdm/json_web_key.h" 18 #include "media/cdm/json_web_key.h"
19 #include "media/cdm/key_system_names.h" 19 #include "media/cdm/key_system_names.h"
20 20
21 namespace media { 21 namespace media {
22 22
23 // Special system code to signal a closed persistent session in a SessionError() 23 // Special system code to signal a closed persistent session in a SessionError()
24 // call. This is needed because there is no SessionClosed() call in the prefixed 24 // call. This is needed because there is no SessionClosed() call in the prefixed
25 // EME API. 25 // EME API.
26 const int kSessionClosedSystemCode = 29127; 26 const int kSessionClosedSystemCode = 29127;
27 27
28 ProxyDecryptor::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData(
29 EmeInitDataType init_data_type,
30 const std::vector<uint8>& init_data)
31 : init_data_type(init_data_type), init_data(init_data) {
32 }
33
34 ProxyDecryptor::PendingGenerateKeyRequestData::
35 ~PendingGenerateKeyRequestData() {
36 }
37
28 ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission, 38 ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission,
29 const KeyAddedCB& key_added_cb, 39 const KeyAddedCB& key_added_cb,
30 const KeyErrorCB& key_error_cb, 40 const KeyErrorCB& key_error_cb,
31 const KeyMessageCB& key_message_cb) 41 const KeyMessageCB& key_message_cb)
32 : media_permission_(media_permission), 42 : is_creating_cdm_(false),
43 media_permission_(media_permission),
33 key_added_cb_(key_added_cb), 44 key_added_cb_(key_added_cb),
34 key_error_cb_(key_error_cb), 45 key_error_cb_(key_error_cb),
35 key_message_cb_(key_message_cb), 46 key_message_cb_(key_message_cb),
36 is_clear_key_(false), 47 is_clear_key_(false),
37 weak_ptr_factory_(this) { 48 weak_ptr_factory_(this) {
38 DCHECK(media_permission); 49 DCHECK(media_permission);
39 DCHECK(!key_added_cb_.is_null()); 50 DCHECK(!key_added_cb_.is_null());
40 DCHECK(!key_error_cb_.is_null()); 51 DCHECK(!key_error_cb_.is_null());
41 DCHECK(!key_message_cb_.is_null()); 52 DCHECK(!key_message_cb_.is_null());
42 } 53 }
43 54
44 ProxyDecryptor::~ProxyDecryptor() { 55 ProxyDecryptor::~ProxyDecryptor() {
45 // Destroy the decryptor explicitly before destroying the plugin. 56 // Destroy the decryptor explicitly before destroying the plugin.
46 media_keys_.reset(); 57 media_keys_.reset();
47 } 58 }
48 59
49 CdmContext* ProxyDecryptor::GetCdmContext() { 60 void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory,
50 return media_keys_ ? media_keys_->GetCdmContext() : nullptr; 61 const std::string& key_system,
62 const GURL& security_origin,
63 const CdmContextReadyCB& cdm_context_ready_cb) {
64 DVLOG(1) << __FUNCTION__ << ": key_system = " << key_system;
65 DCHECK(!is_creating_cdm_);
66 DCHECK(!media_keys_);
67
68 // TODO(sandersd): Trigger permissions check here and use it to determine
69 // distinctive identifier support, instead of always requiring the
70 // permission. http://crbug.com/455271
71 bool allow_distinctive_identifier = true;
72 bool allow_persistent_state = true;
73
74 is_creating_cdm_ = true;
75
76 base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
77 cdm_factory->Create(
78 key_system, allow_distinctive_identifier, allow_persistent_state,
79 security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
80 base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
81 base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this),
82 base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
83 base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this),
84 base::Bind(&ProxyDecryptor::OnCdmCreated, weak_this, key_system,
85 security_origin, cdm_context_ready_cb));
51 } 86 }
52 87
53 bool ProxyDecryptor::InitializeCDM(CdmFactory* cdm_factory, 88 void ProxyDecryptor::OnCdmCreated(const std::string& key_system,
54 const std::string& key_system, 89 const GURL& security_origin,
55 const GURL& security_origin) { 90 const CdmContextReadyCB& cdm_context_ready_cb,
56 DVLOG(1) << "InitializeCDM: key_system = " << key_system; 91 scoped_ptr<MediaKeys> cdm) {
92 is_creating_cdm_ = false;
57 93
58 DCHECK(!media_keys_); 94 if (!cdm) {
59 media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin); 95 cdm_context_ready_cb.Run(nullptr);
60 if (!media_keys_) 96 return;
61 return false; 97 }
62 98
63 key_system_ = key_system; 99 key_system_ = key_system;
64 security_origin_ = security_origin; 100 security_origin_ = security_origin;
101 is_clear_key_ = IsClearKey(key_system) || IsExternalClearKey(key_system);
102 media_keys_ = cdm.Pass();
65 103
66 is_clear_key_ = 104 cdm_context_ready_cb.Run(media_keys_->GetCdmContext());
67 IsClearKey(key_system) || IsExternalClearKey(key_system); 105
68 return true; 106 for (const auto& request : pending_requests_)
107 GenerateKeyRequestInternal(request.init_data_type, request.init_data);
108 pending_requests_.clear();
109 }
110
111 void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
112 const uint8* init_data,
113 int init_data_length) {
114 std::vector<uint8> init_data_vector(init_data, init_data + init_data_length);
115
116 if (is_creating_cdm_) {
117 pending_requests_.push_back(
118 PendingGenerateKeyRequestData(init_data_type, init_data_vector));
119 return;
120 }
121
ddorwin 2015/04/11 02:41:48 DCHECK(media_keys_); Line 116 assumes it. Oh, act
xhwang 2015/04/13 18:56:10 media_keys_ will be null here if previous CDM crea
122 GenerateKeyRequestInternal(init_data_type, init_data_vector);
69 } 123 }
70 124
71 // Returns true if |data| is prefixed with |header| and has data after the 125 // Returns true if |data| is prefixed with |header| and has data after the
72 // |header|. 126 // |header|.
73 bool HasHeader(const uint8* data, int data_length, const std::string& header) { 127 bool HasHeader(const std::vector<uint8>& data, const std::string& header) {
74 return static_cast<size_t>(data_length) > header.size() && 128 return data.size() > header.size() &&
75 std::equal(data, data + header.size(), header.begin()); 129 std::equal(header.begin(), header.end(), data.begin());
76 } 130 }
77 131
78 // Removes the first |length| items from |data|. 132 // Removes the first |length| items from |data|.
79 void StripHeader(std::vector<uint8>& data, size_t length) { 133 void StripHeader(std::vector<uint8>& data, size_t length) {
80 data.erase(data.begin(), data.begin() + length); 134 data.erase(data.begin(), data.begin() + length);
81 } 135 }
82 136
83 bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type, 137 void ProxyDecryptor::GenerateKeyRequestInternal(
84 const uint8* init_data, 138 EmeInitDataType init_data_type,
85 int init_data_length) { 139 const std::vector<uint8>& init_data) {
86 DVLOG(1) << "GenerateKeyRequest()"; 140 DVLOG(1) << __FUNCTION__;
141 DCHECK(!is_creating_cdm_);
142
143 if (!media_keys_) {
144 OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0,
145 "CDM creation failed.");
146 return;
147 }
148
87 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; 149 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
88 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; 150 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
89 151
90 SessionCreationType session_creation_type = TemporarySession; 152 SessionCreationType session_creation_type = TemporarySession;
91 std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); 153 std::vector<uint8> stripped_init_data = init_data;
92 if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { 154 if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) {
93 session_creation_type = LoadSession; 155 session_creation_type = LoadSession;
94 StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader)); 156 StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader));
95 } else if (HasHeader(init_data, 157 } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) {
96 init_data_length,
97 kPrefixedApiPersistentSessionHeader)) {
98 session_creation_type = PersistentSession; 158 session_creation_type = PersistentSession;
99 StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader)); 159 StripHeader(stripped_init_data,
160 strlen(kPrefixedApiPersistentSessionHeader));
100 } 161 }
101 162
102 scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>( 163 scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>(
103 base::Bind(&ProxyDecryptor::SetSessionId, weak_ptr_factory_.GetWeakPtr(), 164 base::Bind(&ProxyDecryptor::SetSessionId, weak_ptr_factory_.GetWeakPtr(),
104 session_creation_type), 165 session_creation_type),
105 base::Bind(&ProxyDecryptor::OnLegacySessionError, 166 base::Bind(&ProxyDecryptor::OnLegacySessionError,
106 weak_ptr_factory_.GetWeakPtr(), 167 weak_ptr_factory_.GetWeakPtr(),
107 std::string()))); // No session id until created. 168 std::string()))); // No session id until created.
108 169
109 if (session_creation_type == LoadSession) { 170 if (session_creation_type == LoadSession) {
110 media_keys_->LoadSession( 171 media_keys_->LoadSession(
111 MediaKeys::PERSISTENT_LICENSE_SESSION, 172 MediaKeys::PERSISTENT_LICENSE_SESSION,
112 std::string( 173 std::string(
113 reinterpret_cast<const char*>(vector_as_array(&init_data_vector)), 174 reinterpret_cast<const char*>(vector_as_array(&stripped_init_data)),
114 init_data_vector.size()), 175 stripped_init_data.size()),
115 promise.Pass()); 176 promise.Pass());
116 return true; 177 return;
117 } 178 }
118 179
119 MediaKeys::SessionType session_type = 180 MediaKeys::SessionType session_type =
120 session_creation_type == PersistentSession 181 session_creation_type == PersistentSession
121 ? MediaKeys::PERSISTENT_LICENSE_SESSION 182 ? MediaKeys::PERSISTENT_LICENSE_SESSION
122 : MediaKeys::TEMPORARY_SESSION; 183 : MediaKeys::TEMPORARY_SESSION;
123 184
124 // No permission required when AesDecryptor is used or when the key system is 185 // No permission required when AesDecryptor is used or when the key system is
125 // external clear key. 186 // external clear key.
126 DCHECK(!key_system_.empty()); 187 DCHECK(!key_system_.empty());
127 if (CanUseAesDecryptor(key_system_) || IsExternalClearKey(key_system_)) { 188 if (CanUseAesDecryptor(key_system_) || IsExternalClearKey(key_system_)) {
128 OnPermissionStatus(session_type, init_data_type, init_data_vector, 189 OnPermissionStatus(session_type, init_data_type, stripped_init_data,
129 promise.Pass(), true /* granted */); 190 promise.Pass(), true /* granted */);
130 return true; 191 return;
131 } 192 }
132 193
133 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) 194 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
134 media_permission_->RequestPermission( 195 media_permission_->RequestPermission(
135 MediaPermission::PROTECTED_MEDIA_IDENTIFIER, security_origin_, 196 MediaPermission::PROTECTED_MEDIA_IDENTIFIER, security_origin_,
136 base::Bind(&ProxyDecryptor::OnPermissionStatus, 197 base::Bind(&ProxyDecryptor::OnPermissionStatus,
137 weak_ptr_factory_.GetWeakPtr(), session_type, init_data_type, 198 weak_ptr_factory_.GetWeakPtr(), session_type, init_data_type,
138 init_data_vector, base::Passed(&promise))); 199 stripped_init_data, base::Passed(&promise)));
139 #else 200 #else
140 OnPermissionStatus(session_type, init_data_type, init_data_vector, 201 OnPermissionStatus(session_type, init_data_type, stripped_init_data,
141 promise.Pass(), true /* granted */); 202 promise.Pass(), true /* granted */);
142 #endif 203 #endif
143
144 return true;
145 } 204 }
146 205
147 void ProxyDecryptor::OnPermissionStatus( 206 void ProxyDecryptor::OnPermissionStatus(
148 MediaKeys::SessionType session_type, 207 MediaKeys::SessionType session_type,
149 EmeInitDataType init_data_type, 208 EmeInitDataType init_data_type,
150 const std::vector<uint8>& init_data, 209 const std::vector<uint8>& init_data,
151 scoped_ptr<NewSessionCdmPromise> promise, 210 scoped_ptr<NewSessionCdmPromise> promise,
152 bool granted) { 211 bool granted) {
153 // ProxyDecryptor is only used by Prefixed EME, where RequestPermission() is 212 // ProxyDecryptor is only used by Prefixed EME, where RequestPermission() is
154 // only for triggering the permission UI. Later CheckPermission() will be 213 // only for triggering the permission UI. Later CheckPermission() will be
155 // called (e.g. in PlatformVerificationFlow on ChromeOS; in BrowserCdmManager 214 // called (e.g. in PlatformVerificationFlow on ChromeOS; in BrowserCdmManager
156 // on Android) and the permission status will be evaluated then. 215 // on Android) and the permission status will be evaluated then.
157 DVLOG_IF(1, !granted) << "Permission request rejected."; 216 DVLOG_IF(1, !granted) << "Permission request rejected.";
158 217
159 media_keys_->CreateSessionAndGenerateRequest( 218 media_keys_->CreateSessionAndGenerateRequest(
160 session_type, init_data_type, vector_as_array(&init_data), 219 session_type, init_data_type, vector_as_array(&init_data),
161 init_data.size(), promise.Pass()); 220 init_data.size(), promise.Pass());
162 } 221 }
163 222
164 void ProxyDecryptor::AddKey(const uint8* key, 223 void ProxyDecryptor::AddKey(const uint8* key,
165 int key_length, 224 int key_length,
166 const uint8* init_data, 225 const uint8* init_data,
167 int init_data_length, 226 int init_data_length,
168 const std::string& session_id) { 227 const std::string& session_id) {
169 DVLOG(1) << "AddKey()"; 228 DVLOG(1) << "AddKey()";
170 229
230 if (!media_keys_) {
231 OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
232 "CDM creation failed.");
ddorwin 2015/04/11 02:41:48 Is this the correct message? Can we not DCHECK bec
xhwang 2015/04/13 18:56:10 Updated message. WMPI (actually EncryptedMediaPla
233 return;
234 }
235
171 // In the prefixed API, the session parameter provided to addKey() is 236 // In the prefixed API, the session parameter provided to addKey() is
172 // optional, so use the single existing session if it exists. 237 // optional, so use the single existing session if it exists.
173 std::string new_session_id(session_id); 238 std::string new_session_id(session_id);
174 if (new_session_id.empty()) { 239 if (new_session_id.empty()) {
175 if (active_sessions_.size() == 1) { 240 if (active_sessions_.size() == 1) {
176 base::hash_map<std::string, bool>::iterator it = active_sessions_.begin(); 241 base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
177 new_session_id = it->first; 242 new_session_id = it->first;
178 } else { 243 } else {
179 OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0, 244 OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0,
180 "SessionId not specified."); 245 "SessionId not specified.");
(...skipping 28 matching lines...) Expand all
209 jwk.size(), promise.Pass()); 274 jwk.size(), promise.Pass());
210 return; 275 return;
211 } 276 }
212 277
213 media_keys_->UpdateSession(new_session_id, key, key_length, promise.Pass()); 278 media_keys_->UpdateSession(new_session_id, key, key_length, promise.Pass());
214 } 279 }
215 280
216 void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) { 281 void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
217 DVLOG(1) << "CancelKeyRequest()"; 282 DVLOG(1) << "CancelKeyRequest()";
218 283
284 if (!media_keys_) {
285 OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
ddorwin 2015/04/11 02:41:48 ditto
xhwang 2015/04/13 18:56:10 Done.
286 "CDM creation failed.");
287 return;
288 }
289
219 scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>( 290 scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
220 base::Bind(&ProxyDecryptor::OnSessionClosed, 291 base::Bind(&ProxyDecryptor::OnSessionClosed,
221 weak_ptr_factory_.GetWeakPtr(), session_id), 292 weak_ptr_factory_.GetWeakPtr(), session_id),
222 base::Bind(&ProxyDecryptor::OnLegacySessionError, 293 base::Bind(&ProxyDecryptor::OnLegacySessionError,
223 weak_ptr_factory_.GetWeakPtr(), session_id))); 294 weak_ptr_factory_.GetWeakPtr(), session_id)));
224 media_keys_->RemoveSession(session_id, promise.Pass()); 295 media_keys_->RemoveSession(session_id, promise.Pass());
225 } 296 }
226 297
227 scoped_ptr<MediaKeys> ProxyDecryptor::CreateMediaKeys(
228 CdmFactory* cdm_factory,
229 const std::string& key_system,
230 const GURL& security_origin) {
231 // TODO(sandersd): Trigger permissions check here and use it to determine
232 // distinctive identifier support, instead of always requiring the
233 // permission. http://crbug.com/455271
234 bool allow_distinctive_identifier = true;
235 bool allow_persistent_state = true;
236 base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
237 return cdm_factory->Create(
238 key_system, allow_distinctive_identifier, allow_persistent_state,
239 security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
240 base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
241 base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this),
242 base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
243 base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this));
244 }
245
246 void ProxyDecryptor::OnSessionMessage(const std::string& session_id, 298 void ProxyDecryptor::OnSessionMessage(const std::string& session_id,
247 MediaKeys::MessageType message_type, 299 MediaKeys::MessageType message_type,
248 const std::vector<uint8>& message, 300 const std::vector<uint8>& message,
249 const GURL& legacy_destination_url) { 301 const GURL& legacy_destination_url) {
250 // Assumes that OnSessionCreated() has been called before this. 302 // Assumes that OnSessionCreated() has been called before this.
251 303
252 // For ClearKey, convert the message from JSON into just passing the key 304 // For ClearKey, convert the message from JSON into just passing the key
253 // as the message. If unable to extract the key, return the message unchanged. 305 // as the message. If unable to extract the key, return the message unchanged.
254 if (is_clear_key_) { 306 if (is_clear_key_) {
255 std::vector<uint8> key; 307 std::vector<uint8> key;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 bool is_persistent = 385 bool is_persistent =
334 session_type == PersistentSession || session_type == LoadSession; 386 session_type == PersistentSession || session_type == LoadSession;
335 active_sessions_.insert(std::make_pair(session_id, is_persistent)); 387 active_sessions_.insert(std::make_pair(session_id, is_persistent));
336 388
337 // For LoadSession(), generate the KeyAdded event. 389 // For LoadSession(), generate the KeyAdded event.
338 if (session_type == LoadSession) 390 if (session_type == LoadSession)
339 GenerateKeyAdded(session_id); 391 GenerateKeyAdded(session_id);
340 } 392 }
341 393
342 } // namespace media 394 } // namespace media
OLDNEW
« media/cdm/proxy_decryptor.h ('K') | « media/cdm/proxy_decryptor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698