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

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

Issue 850183002: media: Support unprefixed EME API on Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase and address comments. Created 5 years, 11 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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_media_keys.h" 5 #include "content/renderer/media/crypto/proxy_media_keys.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "content/renderer/media/crypto/renderer_cdm_manager.h" 12 #include "content/renderer/media/crypto/renderer_cdm_manager.h"
13 #include "media/base/cdm_key_information.h"
13 #include "media/base/cdm_promise.h" 14 #include "media/base/cdm_promise.h"
14 #include "media/base/key_systems.h" 15 #include "media/base/key_systems.h"
15 16
16 namespace content { 17 namespace content {
17 18
18 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create( 19 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create(
19 const std::string& key_system, 20 const std::string& key_system,
20 const GURL& security_origin, 21 const GURL& security_origin,
21 RendererCdmManager* manager, 22 RendererCdmManager* manager,
22 const media::SessionMessageCB& session_message_cb, 23 const media::SessionMessageCB& session_message_cb,
23 const media::SessionClosedCB& session_closed_cb, 24 const media::SessionClosedCB& session_closed_cb,
24 const media::SessionErrorCB& session_error_cb, 25 const media::SessionErrorCB& session_error_cb,
25 const media::SessionKeysChangeCB& session_keys_change_cb, 26 const media::SessionKeysChangeCB& session_keys_change_cb,
26 const media::SessionExpirationUpdateCB& session_expiration_update_cb) { 27 const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
27 DCHECK(manager); 28 DCHECK(manager);
28 29 scoped_ptr<ProxyMediaKeys> proxy_media_keys(new ProxyMediaKeys(
29 // TODO(jrummell): Add support for SessionKeysChangeCB and 30 manager, session_message_cb, session_closed_cb, session_error_cb,
30 // SessionExpirationUpdateCB. 31 session_keys_change_cb, session_expiration_update_cb));
31 scoped_ptr<ProxyMediaKeys> proxy_media_keys(
32 new ProxyMediaKeys(manager,
33 session_message_cb,
34 session_closed_cb,
35 session_error_cb));
36 proxy_media_keys->InitializeCdm(key_system, security_origin); 32 proxy_media_keys->InitializeCdm(key_system, security_origin);
37 return proxy_media_keys.Pass(); 33 return proxy_media_keys.Pass();
38 } 34 }
39 35
40 ProxyMediaKeys::~ProxyMediaKeys() { 36 ProxyMediaKeys::~ProxyMediaKeys() {
41 manager_->DestroyCdm(cdm_id_); 37 manager_->DestroyCdm(cdm_id_);
42 manager_->UnregisterMediaKeys(cdm_id_); 38 manager_->UnregisterMediaKeys(cdm_id_);
43 39 cdm_promise_adapter_.Clear();
44 // Reject any outstanding promises.
45 for (PromiseMap::iterator it = session_id_to_promise_map_.begin();
46 it != session_id_to_promise_map_.end();
47 ++it) {
48 it->second->reject(
49 media::MediaKeys::NOT_SUPPORTED_ERROR, 0, "The operation was aborted.");
50 }
51 session_id_to_promise_map_.clear();
52 } 40 }
53 41
54 void ProxyMediaKeys::SetServerCertificate( 42 void ProxyMediaKeys::SetServerCertificate(
55 const uint8* certificate_data, 43 const uint8* certificate_data,
56 int certificate_data_length, 44 int certificate_data_length,
57 scoped_ptr<media::SimpleCdmPromise> promise) { 45 scoped_ptr<media::SimpleCdmPromise> promise) {
58 promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented."); 46 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
47 manager_->SetServerCertificate(
48 cdm_id_, promise_id,
49 std::vector<uint8>(certificate_data,
50 certificate_data + certificate_data_length));
59 } 51 }
60 52
61 void ProxyMediaKeys::CreateSessionAndGenerateRequest( 53 void ProxyMediaKeys::CreateSessionAndGenerateRequest(
62 SessionType session_type, 54 SessionType session_type,
63 const std::string& init_data_type, 55 const std::string& init_data_type,
64 const uint8* init_data, 56 const uint8* init_data,
65 int init_data_length, 57 int init_data_length,
66 scoped_ptr<media::NewSessionCdmPromise> promise) { 58 scoped_ptr<media::NewSessionCdmPromise> promise) {
59 if (session_type != media::MediaKeys::TEMPORARY_SESSION) {
60 promise->reject(NOT_SUPPORTED_ERROR, 0,
61 "Only temporary session is supported.");
ddorwin 2015/01/15 17:36:52 nit: ditto
xhwang 2015/01/15 19:03:44 Done.
62 return;
63 }
64
67 // TODO(xhwang): Move these checks up to blink and DCHECK here. 65 // TODO(xhwang): Move these checks up to blink and DCHECK here.
68 // See http://crbug.com/342510 66 // See http://crbug.com/342510
69 CdmHostMsg_CreateSession_ContentType create_session_content_type; 67 CdmHostMsg_CreateSession_InitDataType create_session_init_data_type;
70 if (init_data_type == "cenc") { 68 if (init_data_type == "cenc") {
71 create_session_content_type = CREATE_SESSION_TYPE_MP4; 69 create_session_init_data_type = CREATE_SESSION_TYPE_MP4;
72 } else if (init_data_type == "webm") { 70 } else if (init_data_type == "webm") {
73 create_session_content_type = CREATE_SESSION_TYPE_WEBM; 71 create_session_init_data_type = CREATE_SESSION_TYPE_WEBM;
74 } else { 72 } else {
75 DLOG(ERROR) << "Unsupported EME CreateSession content type of " 73 DLOG(ERROR) << "Unsupported EME CreateSession content type of "
76 << init_data_type; 74 << init_data_type;
77 promise->reject( 75 promise->reject(
78 NOT_SUPPORTED_ERROR, 76 NOT_SUPPORTED_ERROR,
79 0, 77 0,
80 "Unsupported EME CreateSession init data type of " + init_data_type); 78 "Unsupported EME CreateSession init data type of " + init_data_type);
81 return; 79 return;
82 } 80 }
83 81
84 uint32 session_id = CreateSessionId(); 82 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
85 SavePromise(session_id, promise.Pass()); 83 manager_->CreateSessionAndGenerateRequest(
86 manager_->CreateSession( 84 cdm_id_, promise_id, create_session_init_data_type,
87 cdm_id_,
88 session_id,
89 create_session_content_type,
90 std::vector<uint8>(init_data, init_data + init_data_length)); 85 std::vector<uint8>(init_data, init_data + init_data_length));
91 } 86 }
92 87
93 void ProxyMediaKeys::LoadSession( 88 void ProxyMediaKeys::LoadSession(
94 SessionType session_type, 89 SessionType session_type,
95 const std::string& web_session_id, 90 const std::string& session_id,
96 scoped_ptr<media::NewSessionCdmPromise> promise) { 91 scoped_ptr<media::NewSessionCdmPromise> promise) {
97 // TODO(xhwang): Check key system and platform support for LoadSession in 92 // TODO(xhwang): Check key system and platform support for LoadSession in
98 // blink and add NOTREACHED() here. 93 // blink and add NOTREACHED() here. See http://crbug.com/384152
99 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; 94 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading.";
100 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); 95 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported.");
101 } 96 }
102 97
103 void ProxyMediaKeys::UpdateSession( 98 void ProxyMediaKeys::UpdateSession(
104 const std::string& web_session_id, 99 const std::string& session_id,
105 const uint8* response, 100 const uint8* response,
106 int response_length, 101 int response_length,
107 scoped_ptr<media::SimpleCdmPromise> promise) { 102 scoped_ptr<media::SimpleCdmPromise> promise) {
108 uint32 session_id = LookupSessionId(web_session_id); 103 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
109 if (!session_id) {
110 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
111 return;
112 }
113
114 SavePromise(session_id, promise.Pass());
115 manager_->UpdateSession( 104 manager_->UpdateSession(
116 cdm_id_, 105 cdm_id_, promise_id, session_id,
117 session_id,
118 std::vector<uint8>(response, response + response_length)); 106 std::vector<uint8>(response, response + response_length));
119 } 107 }
120 108
121 void ProxyMediaKeys::CloseSession(const std::string& web_session_id, 109 void ProxyMediaKeys::CloseSession(const std::string& session_id,
122 scoped_ptr<media::SimpleCdmPromise> promise) { 110 scoped_ptr<media::SimpleCdmPromise> promise) {
123 uint32 session_id = LookupSessionId(web_session_id); 111 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
124 if (!session_id) { 112 manager_->CloseSession(cdm_id_, promise_id, session_id);
125 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
126 return;
127 }
128
129 SavePromise(session_id, promise.Pass());
130 manager_->ReleaseSession(cdm_id_, session_id);
131 } 113 }
132 114
133 void ProxyMediaKeys::RemoveSession( 115 void ProxyMediaKeys::RemoveSession(
134 const std::string& web_session_id, 116 const std::string& session_id,
135 scoped_ptr<media::SimpleCdmPromise> promise) { 117 scoped_ptr<media::SimpleCdmPromise> promise) {
136 promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented."); 118 // TODO(xhwang): Check key system and platform support for LoadSession in
119 // blink and add NOTREACHED() here. See http://crbug.com/384152
120 promise->reject(NOT_SUPPORTED_ERROR, 0, "RemoveSession() not supported.");
137 } 121 }
138 122
139 media::CdmContext* ProxyMediaKeys::GetCdmContext() { 123 media::CdmContext* ProxyMediaKeys::GetCdmContext() {
140 return this; 124 return this;
141 } 125 }
142 126
143 media::Decryptor* ProxyMediaKeys::GetDecryptor() { 127 media::Decryptor* ProxyMediaKeys::GetDecryptor() {
144 return NULL; 128 return NULL;
145 } 129 }
146 130
147 int ProxyMediaKeys::GetCdmId() const { 131 int ProxyMediaKeys::GetCdmId() const {
148 return cdm_id_; 132 return cdm_id_;
149 } 133 }
150 134
151 void ProxyMediaKeys::OnSessionCreated(uint32 session_id, 135 void ProxyMediaKeys::OnSessionMessage(
152 const std::string& web_session_id) { 136 const std::string& session_id,
153 AssignWebSessionId(session_id, web_session_id); 137 media::MediaKeys::MessageType message_type,
154 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); 138 const std::vector<uint8>& message,
155 if (promise) { 139 const GURL& legacy_destination_url) {
156 media::NewSessionCdmPromise* session_promise( 140 session_message_cb_.Run(session_id, message_type, message,
157 static_cast<media::NewSessionCdmPromise*>(promise.get()));
158 session_promise->resolve(web_session_id);
159 }
160 }
161
162 void ProxyMediaKeys::OnSessionMessage(uint32 session_id,
163 const std::vector<uint8>& message,
164 const GURL& legacy_destination_url) {
165 // TODO(jrummell): Once |message_type| is passed, use it rather than
166 // guessing from the URL.
167 media::MediaKeys::MessageType message_type =
168 legacy_destination_url.is_empty() ? media::MediaKeys::LICENSE_REQUEST
169 : media::MediaKeys::LICENSE_RENEWAL;
170 session_message_cb_.Run(LookupWebSessionId(session_id), message_type, message,
171 legacy_destination_url); 141 legacy_destination_url);
172 } 142 }
173 143
174 void ProxyMediaKeys::OnSessionReady(uint32 session_id) { 144 void ProxyMediaKeys::OnSessionClosed(const std::string& session_id) {
175 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); 145 session_closed_cb_.Run(session_id);
176 if (promise) {
177 media::SimpleCdmPromise* simple_promise(
178 static_cast<media::SimpleCdmPromise*>(promise.get()));
179 simple_promise->resolve();
180 }
181 } 146 }
182 147
183 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { 148 void ProxyMediaKeys::OnLegacySessionError(const std::string& session_id,
184 const std::string web_session_id = LookupWebSessionId(session_id); 149 media::MediaKeys::Exception exception,
185 DropWebSessionId(web_session_id); 150 uint32 system_code,
186 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); 151 const std::string& error_message) {
187 if (promise) { 152 session_error_cb_.Run(session_id, exception, system_code, error_message);
188 media::SimpleCdmPromise* simple_promise(
189 static_cast<media::SimpleCdmPromise*>(promise.get()));
190 simple_promise->resolve();
191 } else {
192 // It is possible for the CDM to close a session independent of a
193 // Release() request.
194 session_closed_cb_.Run(web_session_id);
195 }
196 } 153 }
197 154
198 void ProxyMediaKeys::OnSessionError(uint32 session_id, 155 void ProxyMediaKeys::OnSessionKeysChange(const std::string& session_id,
199 media::MediaKeys::KeyError error_code, 156 bool has_additional_usable_key,
200 uint32 system_code) { 157 media::CdmKeysInfo keys_info) {
201 const std::string web_session_id = LookupWebSessionId(session_id); 158 session_keys_change_cb_.Run(session_id, has_additional_usable_key,
202 media::MediaKeys::Exception exception_code; 159 keys_info.Pass());
203 switch (error_code) { 160 }
204 case media::MediaKeys::kClientError:
205 exception_code = media::MediaKeys::CLIENT_ERROR;
206 break;
207 case media::MediaKeys::kOutputError:
208 exception_code = media::MediaKeys::OUTPUT_ERROR;
209 break;
210 case media::MediaKeys::kUnknownError:
211 default:
212 exception_code = media::MediaKeys::UNKNOWN_ERROR;
213 break;
214 }
215 161
216 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); 162 void ProxyMediaKeys::OnSessionExpirationUpdate(
217 if (promise) { 163 const std::string& session_id,
218 promise->reject(exception_code, system_code, std::string()); 164 const base::Time& new_expiry_time) {
219 return; 165 session_expiration_update_cb_.Run(session_id, new_expiry_time);
220 } 166 }
221 167
222 // Errors generally happen in response to a request, but it is possible 168 void ProxyMediaKeys::OnPromiseResolved(uint32_t promise_id) {
223 // for something bad to happen in the CDM and it needs to tell the client. 169 cdm_promise_adapter_.ResolvePromise(promise_id);
224 session_error_cb_.Run( 170 }
225 web_session_id, exception_code, system_code, std::string()); 171
172 void ProxyMediaKeys::OnPromiseResolvedWithSession(
173 uint32_t promise_id,
174 const std::string& session_id) {
175 cdm_promise_adapter_.ResolvePromise(promise_id, session_id);
176 }
177
178 void ProxyMediaKeys::OnPromiseRejected(uint32_t promise_id,
179 media::MediaKeys::Exception exception,
180 uint32_t system_code,
181 const std::string& error_message) {
182 cdm_promise_adapter_.RejectPromise(promise_id, exception, system_code,
183 error_message);
226 } 184 }
227 185
228 ProxyMediaKeys::ProxyMediaKeys( 186 ProxyMediaKeys::ProxyMediaKeys(
229 RendererCdmManager* manager, 187 RendererCdmManager* manager,
230 const media::SessionMessageCB& session_message_cb, 188 const media::SessionMessageCB& session_message_cb,
231 const media::SessionClosedCB& session_closed_cb, 189 const media::SessionClosedCB& session_closed_cb,
232 const media::SessionErrorCB& session_error_cb) 190 const media::SessionErrorCB& session_error_cb,
191 const media::SessionKeysChangeCB& session_keys_change_cb,
192 const media::SessionExpirationUpdateCB& session_expiration_update_cb)
233 : manager_(manager), 193 : manager_(manager),
234 session_message_cb_(session_message_cb), 194 session_message_cb_(session_message_cb),
235 session_closed_cb_(session_closed_cb), 195 session_closed_cb_(session_closed_cb),
236 session_error_cb_(session_error_cb), 196 session_error_cb_(session_error_cb),
237 next_session_id_(1) { 197 session_keys_change_cb_(session_keys_change_cb),
198 session_expiration_update_cb_(session_expiration_update_cb) {
238 cdm_id_ = manager->RegisterMediaKeys(this); 199 cdm_id_ = manager->RegisterMediaKeys(this);
239 } 200 }
240 201
241 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, 202 void ProxyMediaKeys::InitializeCdm(const std::string& key_system,
242 const GURL& security_origin) { 203 const GURL& security_origin) {
243 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); 204 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin);
244 } 205 }
245 206
246 uint32_t ProxyMediaKeys::CreateSessionId() {
247 return next_session_id_++;
248 }
249
250 void ProxyMediaKeys::AssignWebSessionId(uint32_t session_id,
251 const std::string& web_session_id) {
252 DCHECK(!ContainsKey(web_session_to_session_id_map_, web_session_id));
253 DCHECK(session_id);
254 web_session_to_session_id_map_.insert(
255 std::make_pair(web_session_id, session_id));
256 }
257
258 uint32_t ProxyMediaKeys::LookupSessionId(
259 const std::string& web_session_id) const {
260 SessionIdMap::const_iterator it =
261 web_session_to_session_id_map_.find(web_session_id);
262 return (it != web_session_to_session_id_map_.end()) ? it->second : 0;
263 }
264
265 std::string ProxyMediaKeys::LookupWebSessionId(uint32_t session_id) const {
266 for (SessionIdMap::const_iterator it = web_session_to_session_id_map_.begin();
267 it != web_session_to_session_id_map_.end();
268 ++it) {
269 if (it->second == session_id)
270 return it->first;
271 }
272 // Possible to get an error creating a session, so no |web_session_id|
273 // available.
274 return std::string();
275 }
276
277 void ProxyMediaKeys::DropWebSessionId(const std::string& web_session_id) {
278 web_session_to_session_id_map_.erase(web_session_id);
279 }
280
281 void ProxyMediaKeys::SavePromise(uint32_t session_id,
282 scoped_ptr<media::CdmPromise> promise) {
283 // Should only be one promise outstanding for any |session_id|.
284 DCHECK(!ContainsKey(session_id_to_promise_map_, session_id));
285 session_id_to_promise_map_.add(session_id, promise.Pass());
286 }
287
288 scoped_ptr<media::CdmPromise> ProxyMediaKeys::TakePromise(uint32_t session_id) {
289 PromiseMap::iterator it = session_id_to_promise_map_.find(session_id);
290 // May not be a promise associated with this session for asynchronous events.
291 if (it == session_id_to_promise_map_.end())
292 return scoped_ptr<media::CdmPromise>();
293 return session_id_to_promise_map_.take_and_erase(it);
294 }
295
296 } // namespace content 207 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698