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

Side by Side Diff: content/browser/media/cdm/browser_cdm_manager.cc

Issue 2380743004: media: Remove Browser CDM implementation (Closed)
Patch Set: media: Remove Browser CDM implementation Created 4 years, 2 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/media/cdm/browser_cdm_manager.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <string>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/lazy_instance.h"
16 #include "base/task_runner.h"
17 #include "build/build_config.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/browser/permission_manager.h"
22 #include "content/public/browser/permission_type.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_process_host_observer.h"
26 #include "content/public/browser/storage_partition.h"
27 #include "content/public/browser/web_contents.h"
28 #include "media/base/cdm_config.h"
29 #include "media/base/cdm_factory.h"
30 #include "media/base/cdm_promise.h"
31 #include "media/base/limits.h"
32
33 #if defined(OS_ANDROID)
34 #include "content/public/browser/android/provision_fetcher_factory.h"
35 #include "content/public/common/renderer_preferences.h"
36 #include "media/base/android/android_cdm_factory.h"
37 #endif
38
39 namespace content {
40
41 using media::MediaKeys;
42
43 namespace {
44
45 #if defined(OS_ANDROID)
46 // Android only supports 128-bit key IDs.
47 const size_t kAndroidKeyIdBytes = 128 / 8;
48 #endif
49
50 // The ID used in this class is a concatenation of |render_frame_id| and
51 // |cdm_id|, i.e. (render_frame_id << 32) + cdm_id.
52
53 uint64_t GetId(int render_frame_id, int cdm_id) {
54 return (static_cast<uint64_t>(render_frame_id) << 32) +
55 static_cast<uint64_t>(cdm_id);
56 }
57
58 bool IdBelongsToFrame(uint64_t id, int render_frame_id) {
59 return (id >> 32) == static_cast<uint64_t>(render_frame_id);
60 }
61
62 // media::CdmPromiseTemplate implementation backed by a BrowserCdmManager.
63 template <typename... T>
64 class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> {
65 public:
66 CdmPromiseInternal(const base::WeakPtr<BrowserCdmManager>& manager,
67 int render_frame_id,
68 int cdm_id,
69 uint32_t promise_id)
70 : manager_(manager),
71 render_frame_id_(render_frame_id),
72 cdm_id_(cdm_id),
73 promise_id_(promise_id) {
74 DCHECK(manager_);
75 }
76
77 ~CdmPromiseInternal() final {
78 if (!IsPromiseSettled())
79 RejectPromiseOnDestruction();
80 }
81
82 // CdmPromiseTemplate<> implementation.
83 void resolve(const T&... result) final;
84
85 void reject(MediaKeys::Exception exception,
86 uint32_t system_code,
87 const std::string& error_message) final {
88 MarkPromiseSettled();
89 if (manager_) {
90 manager_->RejectPromise(render_frame_id_, cdm_id_, promise_id_, exception,
91 system_code, error_message);
92 }
93 }
94
95 private:
96 using media::CdmPromiseTemplate<T...>::IsPromiseSettled;
97 using media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
98 using media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction;
99
100 base::WeakPtr<BrowserCdmManager> const manager_;
101 const int render_frame_id_;
102 const int cdm_id_;
103 const uint32_t promise_id_;
104 };
105
106 template <>
107 void CdmPromiseInternal<>::resolve() {
108 MarkPromiseSettled();
109 if (manager_)
110 manager_->ResolvePromise(render_frame_id_, cdm_id_, promise_id_);
111 }
112
113 template <>
114 void CdmPromiseInternal<std::string>::resolve(const std::string& session_id) {
115 MarkPromiseSettled();
116 if (manager_) {
117 manager_->ResolvePromiseWithSession(render_frame_id_, cdm_id_, promise_id_,
118 session_id);
119 }
120 }
121
122 typedef CdmPromiseInternal<> SimplePromise;
123 typedef CdmPromiseInternal<std::string> NewSessionPromise;
124
125 // Render process ID to BrowserCdmManager map.
126 typedef std::map<int, BrowserCdmManager*> BrowserCdmManagerMap;
127 base::LazyInstance<BrowserCdmManagerMap>::Leaky g_browser_cdm_manager_map =
128 LAZY_INSTANCE_INITIALIZER;
129
130 // Keeps the BrowserCdmManager alive, and in the global map, for as long as the
131 // RenderProcessHost is connected to the child process. This class is a
132 // self-owned observer.
133 class BrowserCdmManagerProcessWatcher : public RenderProcessHostObserver {
134 public:
135 BrowserCdmManagerProcessWatcher(
136 int render_process_id,
137 const scoped_refptr<BrowserCdmManager>& manager)
138 : browser_cdm_manager_(manager) {
139 RenderProcessHost::FromID(render_process_id)->AddObserver(this);
140 CHECK(g_browser_cdm_manager_map.Get()
141 .insert(std::make_pair(render_process_id, manager.get()))
142 .second);
143 }
144
145 // RenderProcessHostObserver:
146 void RenderProcessExited(RenderProcessHost* host,
147 base::TerminationStatus /* status */,
148 int /* exit_code */) override {
149 RemoveHostObserverAndDestroy(host);
150 }
151
152 void RenderProcessHostDestroyed(RenderProcessHost* host) override {
153 RemoveHostObserverAndDestroy(host);
154 }
155
156 private:
157 void RemoveHostObserverAndDestroy(RenderProcessHost* host) {
158 CHECK(g_browser_cdm_manager_map.Get().erase(host->GetID()));
159 host->RemoveObserver(this);
160 delete this;
161 }
162
163 const scoped_refptr<BrowserCdmManager> browser_cdm_manager_;
164 };
165
166 } // namespace
167
168 // static
169 BrowserCdmManager* BrowserCdmManager::FromProcess(int render_process_id) {
170 DCHECK_CURRENTLY_ON(BrowserThread::UI);
171 auto& map = g_browser_cdm_manager_map.Get();
172 auto iterator = map.find(render_process_id);
173 return (iterator == map.end()) ? nullptr : iterator->second;
174 }
175
176 BrowserCdmManager::BrowserCdmManager(
177 int render_process_id,
178 const scoped_refptr<base::TaskRunner>& task_runner)
179 : BrowserMessageFilter(CdmMsgStart),
180 render_process_id_(render_process_id),
181 task_runner_(task_runner),
182 weak_ptr_factory_(this) {
183 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
184 DCHECK_CURRENTLY_ON(BrowserThread::UI);
185
186 new BrowserCdmManagerProcessWatcher(render_process_id, this);
187
188 if (!task_runner_.get()) {
189 task_runner_ = BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
190 }
191 }
192
193 BrowserCdmManager::~BrowserCdmManager() {
194 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
195 DCHECK_CURRENTLY_ON(BrowserThread::UI);
196 }
197
198 // Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
199 void BrowserCdmManager::OnDestruct() const {
200 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
201 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
202 delete this;
203 } else {
204 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
205 }
206 }
207
208 base::TaskRunner* BrowserCdmManager::OverrideTaskRunnerForMessage(
209 const IPC::Message& message) {
210 // Only handles CDM messages.
211 if (IPC_MESSAGE_CLASS(message) != CdmMsgStart)
212 return NULL;
213
214 return task_runner_.get();
215 }
216
217 bool BrowserCdmManager::OnMessageReceived(const IPC::Message& msg) {
218 DCHECK(task_runner_->RunsTasksOnCurrentThread());
219 bool handled = true;
220 IPC_BEGIN_MESSAGE_MAP(BrowserCdmManager, msg)
221 IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
222 IPC_MESSAGE_HANDLER(CdmHostMsg_SetServerCertificate, OnSetServerCertificate)
223 IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSessionAndGenerateRequest,
224 OnCreateSessionAndGenerateRequest)
225 IPC_MESSAGE_HANDLER(CdmHostMsg_LoadSession, OnLoadSession)
226 IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
227 IPC_MESSAGE_HANDLER(CdmHostMsg_CloseSession, OnCloseSession)
228 IPC_MESSAGE_HANDLER(CdmHostMsg_RemoveSession, OnRemoveSession)
229 IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
230 IPC_MESSAGE_UNHANDLED(handled = false)
231 IPC_END_MESSAGE_MAP()
232 return handled;
233 }
234
235 scoped_refptr<MediaKeys> BrowserCdmManager::GetCdm(int render_frame_id,
236 int cdm_id) const {
237 DCHECK(task_runner_->RunsTasksOnCurrentThread());
238 const auto& iter = cdm_map_.find(GetId(render_frame_id, cdm_id));
239 return iter == cdm_map_.end() ? nullptr : iter->second;
240 }
241
242 void BrowserCdmManager::RenderFrameDeleted(int render_frame_id) {
243 if (!task_runner_->RunsTasksOnCurrentThread()) {
244 task_runner_->PostTask(
245 FROM_HERE,
246 base::Bind(&BrowserCdmManager::RemoveAllCdmForFrame,
247 this, render_frame_id));
248 return;
249 }
250 RemoveAllCdmForFrame(render_frame_id);
251 }
252
253 void BrowserCdmManager::ResolvePromise(int render_frame_id,
254 int cdm_id,
255 uint32_t promise_id) {
256 Send(new CdmMsg_ResolvePromise(render_frame_id, cdm_id, promise_id));
257 }
258
259 void BrowserCdmManager::ResolvePromiseWithSession(
260 int render_frame_id,
261 int cdm_id,
262 uint32_t promise_id,
263 const std::string& session_id) {
264 if (session_id.length() > media::limits::kMaxSessionIdLength) {
265 RejectPromise(render_frame_id, cdm_id, promise_id,
266 MediaKeys::INVALID_ACCESS_ERROR, 0,
267 "Session ID is too long.");
268 return;
269 }
270
271 Send(new CdmMsg_ResolvePromiseWithSession(render_frame_id, cdm_id, promise_id,
272 session_id));
273 }
274
275 void BrowserCdmManager::RejectPromise(int render_frame_id,
276 int cdm_id,
277 uint32_t promise_id,
278 MediaKeys::Exception exception,
279 uint32_t system_code,
280 const std::string& error_message) {
281 Send(new CdmMsg_RejectPromise(render_frame_id, cdm_id, promise_id, exception,
282 system_code, error_message));
283 }
284
285 media::CdmFactory* BrowserCdmManager::GetCdmFactory() {
286 if (!cdm_factory_) {
287 // Create a new CdmFactory.
288 cdm_factory_ = GetContentClient()->browser()->CreateCdmFactory();
289
290 #if defined(OS_ANDROID)
291 if (!cdm_factory_) {
292 // Obtain http request context for the current render process.
293 net::URLRequestContextGetter* context_getter =
294 BrowserContext::GetDefaultStoragePartition(
295 RenderProcessHost::FromID(render_process_id_)->
296 GetBrowserContext())->GetURLRequestContext();
297 DCHECK(context_getter);
298
299 cdm_factory_.reset(new media::AndroidCdmFactory(
300 base::Bind(&CreateProvisionFetcher, context_getter)));
301 }
302 #endif
303 }
304
305 return cdm_factory_.get();
306 }
307
308 void BrowserCdmManager::OnSessionMessage(int render_frame_id,
309 int cdm_id,
310 const std::string& session_id,
311 MediaKeys::MessageType message_type,
312 const std::vector<uint8_t>& message) {
313 Send(new CdmMsg_SessionMessage(render_frame_id, cdm_id, session_id,
314 message_type, message));
315 }
316
317 void BrowserCdmManager::OnSessionClosed(int render_frame_id,
318 int cdm_id,
319 const std::string& session_id) {
320 Send(new CdmMsg_SessionClosed(render_frame_id, cdm_id, session_id));
321 }
322
323 void BrowserCdmManager::OnSessionKeysChange(int render_frame_id,
324 int cdm_id,
325 const std::string& session_id,
326 bool has_additional_usable_key,
327 media::CdmKeysInfo keys_info) {
328 std::vector<media::CdmKeyInformation> key_info_vector;
329 for (auto* key_info : keys_info)
330 key_info_vector.push_back(*key_info);
331 Send(new CdmMsg_SessionKeysChange(render_frame_id, cdm_id, session_id,
332 has_additional_usable_key,
333 key_info_vector));
334 }
335
336 void BrowserCdmManager::OnSessionExpirationUpdate(
337 int render_frame_id,
338 int cdm_id,
339 const std::string& session_id,
340 const base::Time& new_expiry_time) {
341 Send(new CdmMsg_SessionExpirationUpdate(render_frame_id, cdm_id, session_id,
342 new_expiry_time));
343 }
344
345 // Use a weak pointer here instead of |this| to avoid circular references.
346 #define BROWSER_CDM_MANAGER_CB(func, ...) \
347 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \
348 render_frame_id, cdm_id, ##__VA_ARGS__)
349
350 void BrowserCdmManager::OnInitializeCdm(
351 int render_frame_id,
352 int cdm_id,
353 uint32_t promise_id,
354 const CdmHostMsg_InitializeCdm_Params& params) {
355 DCHECK(task_runner_->RunsTasksOnCurrentThread());
356 DCHECK(!GetCdm(render_frame_id, cdm_id));
357
358 std::unique_ptr<SimplePromise> promise(new SimplePromise(
359 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
360
361 if (params.key_system.size() > media::limits::kMaxKeySystemLength) {
362 NOTREACHED() << "Invalid key system: " << params.key_system;
363 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Invalid key system.");
364 return;
365 }
366
367 if (!GetCdmFactory()) {
368 NOTREACHED() << "CDM not supported.";
369 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "CDM not supported.");
370 return;
371 }
372
373 // The render process makes sure |allow_distinctive_identifier| and
374 // |allow_persistent_state| are true. See RenderCdmFactory::Create().
375 // TODO(xhwang): Pass |allow_distinctive_identifier| and
376 // |allow_persistent_state| from the render process.
377 media::CdmConfig cdm_config;
378 cdm_config.allow_distinctive_identifier = true;
379 cdm_config.allow_persistent_state = true;
380 cdm_config.use_hw_secure_codecs = params.use_hw_secure_codecs;
381
382 GetCdmFactory()->Create(
383 params.key_system, params.security_origin, cdm_config,
384 BROWSER_CDM_MANAGER_CB(OnSessionMessage),
385 BROWSER_CDM_MANAGER_CB(OnSessionClosed),
386 BROWSER_CDM_MANAGER_CB(OnSessionKeysChange),
387 BROWSER_CDM_MANAGER_CB(OnSessionExpirationUpdate),
388 BROWSER_CDM_MANAGER_CB(OnCdmCreated, params.security_origin,
389 base::Passed(&promise)));
390 }
391
392 void BrowserCdmManager::OnSetServerCertificate(
393 int render_frame_id,
394 int cdm_id,
395 uint32_t promise_id,
396 const std::vector<uint8_t>& certificate) {
397 DCHECK(task_runner_->RunsTasksOnCurrentThread());
398
399 std::unique_ptr<SimplePromise> promise(new SimplePromise(
400 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
401
402 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
403 if (!cdm) {
404 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
405 return;
406 }
407
408 if (certificate.empty()) {
409 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate.");
410 return;
411 }
412
413 cdm->SetServerCertificate(certificate, std::move(promise));
414 }
415
416 void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
417 const CdmHostMsg_CreateSessionAndGenerateRequest_Params& params) {
418 DCHECK(task_runner_->RunsTasksOnCurrentThread());
419
420 int render_frame_id = params.render_frame_id;
421 int cdm_id = params.cdm_id;
422 const std::vector<uint8_t>& init_data = params.init_data;
423 std::unique_ptr<NewSessionPromise> promise(
424 new NewSessionPromise(weak_ptr_factory_.GetWeakPtr(), render_frame_id,
425 cdm_id, params.promise_id));
426
427 if (init_data.size() > media::limits::kMaxInitDataLength) {
428 LOG(WARNING) << "InitData for ID: " << cdm_id
429 << " too long: " << init_data.size();
430 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long.");
431 return;
432 }
433 #if defined(OS_ANDROID)
434 // 'webm' initData is a single key ID. On Android the length is restricted.
435 if (params.init_data_type == INIT_DATA_TYPE_WEBM &&
436 init_data.size() != kAndroidKeyIdBytes) {
437 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
438 "'webm' initData is not the correct length.");
439 return;
440 }
441 #endif
442
443 media::EmeInitDataType eme_init_data_type;
444 switch (params.init_data_type) {
445 case INIT_DATA_TYPE_WEBM:
446 eme_init_data_type = media::EmeInitDataType::WEBM;
447 break;
448 #if defined(USE_PROPRIETARY_CODECS)
449 case INIT_DATA_TYPE_CENC:
450 eme_init_data_type = media::EmeInitDataType::CENC;
451 break;
452 #endif
453 default:
454 NOTREACHED();
455 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
456 "Invalid init data type.");
457 return;
458 }
459
460 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
461 if (!cdm) {
462 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
463 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
464 return;
465 }
466
467 CheckPermissionStatus(
468 render_frame_id, cdm_id,
469 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted,
470 this, render_frame_id, cdm_id, params.session_type,
471 eme_init_data_type, init_data, base::Passed(&promise)));
472 }
473
474 void BrowserCdmManager::OnLoadSession(
475 int render_frame_id,
476 int cdm_id,
477 uint32_t promise_id,
478 media::MediaKeys::SessionType session_type,
479 const std::string& session_id) {
480 DCHECK(task_runner_->RunsTasksOnCurrentThread());
481
482 std::unique_ptr<NewSessionPromise> promise(new NewSessionPromise(
483 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
484
485 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
486 if (!cdm) {
487 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
488 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
489 return;
490 }
491
492 CheckPermissionStatus(
493 render_frame_id, cdm_id,
494 base::Bind(&BrowserCdmManager::LoadSessionIfPermitted,
495 this, render_frame_id, cdm_id, session_type,
496 session_id, base::Passed(&promise)));
497 }
498
499 void BrowserCdmManager::OnUpdateSession(int render_frame_id,
500 int cdm_id,
501 uint32_t promise_id,
502 const std::string& session_id,
503 const std::vector<uint8_t>& response) {
504 DCHECK(task_runner_->RunsTasksOnCurrentThread());
505
506 std::unique_ptr<SimplePromise> promise(new SimplePromise(
507 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
508
509 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
510 if (!cdm) {
511 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
512 return;
513 }
514
515 if (response.size() > media::limits::kMaxSessionResponseLength) {
516 LOG(WARNING) << "Response for ID " << cdm_id
517 << " is too long: " << response.size();
518 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long.");
519 return;
520 }
521
522 if (response.empty()) {
523 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty.");
524 return;
525 }
526
527 cdm->UpdateSession(session_id, response, std::move(promise));
528 }
529
530 void BrowserCdmManager::OnCloseSession(int render_frame_id,
531 int cdm_id,
532 uint32_t promise_id,
533 const std::string& session_id) {
534 DCHECK(task_runner_->RunsTasksOnCurrentThread());
535
536 std::unique_ptr<SimplePromise> promise(new SimplePromise(
537 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
538
539 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
540 if (!cdm) {
541 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
542 return;
543 }
544
545 cdm->CloseSession(session_id, std::move(promise));
546 }
547
548 void BrowserCdmManager::OnRemoveSession(int render_frame_id,
549 int cdm_id,
550 uint32_t promise_id,
551 const std::string& session_id) {
552 DCHECK(task_runner_->RunsTasksOnCurrentThread());
553
554 std::unique_ptr<SimplePromise> promise(new SimplePromise(
555 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
556
557 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
558 if (!cdm) {
559 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
560 return;
561 }
562
563 cdm->RemoveSession(session_id, std::move(promise));
564 }
565
566 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) {
567 DCHECK(task_runner_->RunsTasksOnCurrentThread());
568 RemoveCdm(GetId(render_frame_id, cdm_id));
569 }
570
571 void BrowserCdmManager::OnCdmCreated(
572 int render_frame_id,
573 int cdm_id,
574 const GURL& security_origin,
575 std::unique_ptr<media::SimpleCdmPromise> promise,
576 const scoped_refptr<media::MediaKeys>& cdm,
577 const std::string& error_message) {
578 if (!cdm) {
579 DVLOG(1) << "Failed to create CDM: " << error_message;
580 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, error_message);
581 return;
582 }
583
584 uint64_t id = GetId(render_frame_id, cdm_id);
585 cdm_map_[id] = cdm;
586 cdm_security_origin_map_[id] = security_origin;
587 promise->resolve();
588 }
589
590 void BrowserCdmManager::RemoveAllCdmForFrame(int render_frame_id) {
591 DCHECK(task_runner_->RunsTasksOnCurrentThread());
592
593 std::vector<uint64_t> ids_to_remove;
594 for (const auto& entry : cdm_map_) {
595 if (IdBelongsToFrame(entry.first, render_frame_id))
596 ids_to_remove.push_back(entry.first);
597 }
598
599 for (const auto& id_to_remove : ids_to_remove)
600 RemoveCdm(id_to_remove);
601 }
602
603 void BrowserCdmManager::RemoveCdm(uint64_t id) {
604 DCHECK(task_runner_->RunsTasksOnCurrentThread());
605
606 cdm_map_.erase(id);
607 cdm_security_origin_map_.erase(id);
608 }
609
610 void BrowserCdmManager::CheckPermissionStatus(
611 int render_frame_id,
612 int cdm_id,
613 const PermissionStatusCB& permission_status_cb) {
614 // Always called on |task_runner_|, which may not be on the UI thread.
615 DCHECK(task_runner_->RunsTasksOnCurrentThread());
616
617 GURL security_origin;
618 std::map<uint64_t, GURL>::const_iterator iter =
619 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id));
620 DCHECK(iter != cdm_security_origin_map_.end());
621 if (iter != cdm_security_origin_map_.end())
622 security_origin = iter->second;
623
624 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
625 BrowserThread::PostTask(
626 BrowserThread::UI, FROM_HERE,
627 base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread, this,
628 render_frame_id, security_origin, permission_status_cb));
629 } else {
630 CheckPermissionStatusOnUIThread(render_frame_id, security_origin,
631 permission_status_cb);
632 }
633 }
634
635 // Note: This function runs on the UI thread, which may be different from
636 // |task_runner_|. Be careful about thread safety!
637 void BrowserCdmManager::CheckPermissionStatusOnUIThread(
638 int render_frame_id,
639 const GURL& security_origin,
640 const base::Callback<void(bool)>& permission_status_cb) {
641 DCHECK_CURRENTLY_ON(BrowserThread::UI);
642
643 RenderFrameHost* rfh =
644 RenderFrameHost::FromID(render_process_id_, render_frame_id);
645 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
646 PermissionManager* permission_manager =
647 web_contents->GetBrowserContext()->GetPermissionManager();
648 if (!permission_manager) {
649 permission_status_cb.Run(false);
650 return;
651 }
652
653 blink::mojom::PermissionStatus permission_status =
654 permission_manager->GetPermissionStatus(
655 PermissionType::PROTECTED_MEDIA_IDENTIFIER, security_origin,
656 web_contents->GetLastCommittedURL().GetOrigin());
657
658 bool allowed = (permission_status == blink::mojom::PermissionStatus::GRANTED);
659 if (!task_runner_->RunsTasksOnCurrentThread()) {
660 task_runner_->PostTask(FROM_HERE,
661 base::Bind(permission_status_cb, allowed));
662 } else {
663 permission_status_cb.Run(allowed);
664 }
665 }
666
667 void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted(
668 int render_frame_id,
669 int cdm_id,
670 media::MediaKeys::SessionType session_type,
671 media::EmeInitDataType init_data_type,
672 const std::vector<uint8_t>& init_data,
673 std::unique_ptr<media::NewSessionCdmPromise> promise,
674 bool permission_was_allowed) {
675 DCHECK(task_runner_->RunsTasksOnCurrentThread());
676
677 if (!permission_was_allowed) {
678 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
679 return;
680 }
681
682 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
683 if (!cdm) {
684 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
685 return;
686 }
687
688 cdm->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
689 std::move(promise));
690 }
691
692 void BrowserCdmManager::LoadSessionIfPermitted(
693 int render_frame_id,
694 int cdm_id,
695 media::MediaKeys::SessionType session_type,
696 const std::string& session_id,
697 std::unique_ptr<media::NewSessionCdmPromise> promise,
698 bool permission_was_allowed) {
699 DCHECK_NE(media::MediaKeys::SessionType::TEMPORARY_SESSION, session_type);
700 DCHECK(task_runner_->RunsTasksOnCurrentThread());
701
702 if (!permission_was_allowed) {
703 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
704 return;
705 }
706
707 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
708 if (!cdm) {
709 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
710 return;
711 }
712
713 cdm->LoadSession(session_type, session_id, std::move(promise));
714 }
715
716 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698