OLD | NEW |
---|---|
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/browser/media/cdm/browser_cdm_manager.h" | 5 #include "content/browser/media/cdm/browser_cdm_manager.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 } | 304 } |
305 | 305 |
306 AddCdm(render_frame_id, cdm_id, key_system, security_origin); | 306 AddCdm(render_frame_id, cdm_id, key_system, security_origin); |
307 } | 307 } |
308 | 308 |
309 void BrowserCdmManager::OnSetServerCertificate( | 309 void BrowserCdmManager::OnSetServerCertificate( |
310 int render_frame_id, | 310 int render_frame_id, |
311 int cdm_id, | 311 int cdm_id, |
312 uint32_t promise_id, | 312 uint32_t promise_id, |
313 const std::vector<uint8_t>& certificate) { | 313 const std::vector<uint8_t>& certificate) { |
314 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
315 | |
314 scoped_ptr<SimplePromise> promise( | 316 scoped_ptr<SimplePromise> promise( |
315 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); | 317 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); |
316 | 318 |
317 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 319 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
318 if (!cdm) { | 320 if (!cdm) { |
319 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 321 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
320 return; | 322 return; |
321 } | 323 } |
322 | 324 |
323 if (certificate.empty()) { | 325 if (certificate.empty()) { |
324 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate."); | 326 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate."); |
325 return; | 327 return; |
326 } | 328 } |
327 | 329 |
328 cdm->SetServerCertificate(&certificate[0], certificate.size(), | 330 cdm->SetServerCertificate(&certificate[0], certificate.size(), |
329 promise.Pass()); | 331 promise.Pass()); |
330 } | 332 } |
331 | 333 |
332 void BrowserCdmManager::OnCreateSessionAndGenerateRequest( | 334 void BrowserCdmManager::OnCreateSessionAndGenerateRequest( |
333 int render_frame_id, | 335 int render_frame_id, |
334 int cdm_id, | 336 int cdm_id, |
335 uint32_t promise_id, | 337 uint32_t promise_id, |
336 CdmHostMsg_CreateSession_InitDataType init_data_type, | 338 CdmHostMsg_CreateSession_InitDataType init_data_type, |
337 const std::vector<uint8>& init_data) { | 339 const std::vector<uint8>& init_data) { |
340 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
341 | |
338 scoped_ptr<NewSessionPromise> promise( | 342 scoped_ptr<NewSessionPromise> promise( |
339 new NewSessionPromise(this, render_frame_id, cdm_id, promise_id)); | 343 new NewSessionPromise(this, render_frame_id, cdm_id, promise_id)); |
340 | 344 |
341 if (init_data.size() > kMaxInitDataLength) { | 345 if (init_data.size() > kMaxInitDataLength) { |
342 LOG(WARNING) << "InitData for ID: " << cdm_id | 346 LOG(WARNING) << "InitData for ID: " << cdm_id |
343 << " too long: " << init_data.size(); | 347 << " too long: " << init_data.size(); |
344 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long."); | 348 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long."); |
345 return; | 349 return; |
346 } | 350 } |
347 | 351 |
(...skipping 10 matching lines...) Expand all Loading... | |
358 default: | 362 default: |
359 NOTREACHED(); | 363 NOTREACHED(); |
360 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, | 364 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, |
361 "Invalid init data type."); | 365 "Invalid init data type."); |
362 return; | 366 return; |
363 } | 367 } |
364 | 368 |
365 #if defined(OS_ANDROID) | 369 #if defined(OS_ANDROID) |
366 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 370 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
367 switches::kDisableInfobarForProtectedMediaIdentifier)) { | 371 switches::kDisableInfobarForProtectedMediaIdentifier)) { |
368 GenerateRequestIfPermitted( | 372 CreateSessionAndGenerateRequest(render_frame_id, cdm_id, eme_init_data_type, |
369 render_frame_id, cdm_id, eme_init_data_type, | 373 init_data, promise.Pass(), |
370 init_data, promise.Pass(), PERMISSION_STATUS_GRANTED); | 374 PERMISSION_STATUS_GRANTED); |
371 return; | 375 return; |
372 } | 376 } |
373 #endif | 377 #endif |
374 | 378 |
375 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 379 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
376 if (!cdm) { | 380 if (!cdm) { |
377 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id; | 381 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id; |
378 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 382 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
379 return; | 383 return; |
380 } | 384 } |
381 | 385 |
382 std::map<uint64, GURL>::const_iterator iter = | 386 std::map<uint64, GURL>::const_iterator iter = |
383 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); | 387 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); |
384 if (iter == cdm_security_origin_map_.end()) { | 388 if (iter == cdm_security_origin_map_.end()) { |
385 NOTREACHED(); | 389 NOTREACHED(); |
386 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 390 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "Origin not found."); |
387 return; | 391 return; |
388 } | 392 } |
389 GURL security_origin = iter->second; | 393 GURL security_origin = iter->second; |
390 | 394 |
391 RequestSessionPermission(render_frame_id, security_origin, cdm_id, | 395 CheckPermissionStatus(render_frame_id, security_origin, cdm_id, |
392 eme_init_data_type, init_data, promise.Pass()); | 396 eme_init_data_type, init_data, promise.Pass()); |
393 } | 397 } |
394 | 398 |
395 void BrowserCdmManager::OnUpdateSession(int render_frame_id, | 399 void BrowserCdmManager::OnUpdateSession(int render_frame_id, |
396 int cdm_id, | 400 int cdm_id, |
397 uint32_t promise_id, | 401 uint32_t promise_id, |
398 const std::string& session_id, | 402 const std::string& session_id, |
399 const std::vector<uint8>& response) { | 403 const std::vector<uint8>& response) { |
404 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
405 | |
400 scoped_ptr<SimplePromise> promise( | 406 scoped_ptr<SimplePromise> promise( |
401 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); | 407 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); |
402 | 408 |
403 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 409 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
404 if (!cdm) { | 410 if (!cdm) { |
405 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 411 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
406 return; | 412 return; |
407 } | 413 } |
408 | 414 |
409 if (response.size() > kMaxSessionResponseLength) { | 415 if (response.size() > kMaxSessionResponseLength) { |
410 LOG(WARNING) << "Response for ID " << cdm_id | 416 LOG(WARNING) << "Response for ID " << cdm_id |
411 << " is too long: " << response.size(); | 417 << " is too long: " << response.size(); |
412 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); | 418 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); |
413 return; | 419 return; |
414 } | 420 } |
415 | 421 |
416 if (response.empty()) { | 422 if (response.empty()) { |
417 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); | 423 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); |
418 return; | 424 return; |
419 } | 425 } |
420 | 426 |
421 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass()); | 427 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass()); |
422 } | 428 } |
423 | 429 |
424 void BrowserCdmManager::OnCloseSession(int render_frame_id, | 430 void BrowserCdmManager::OnCloseSession(int render_frame_id, |
425 int cdm_id, | 431 int cdm_id, |
426 uint32_t promise_id, | 432 uint32_t promise_id, |
427 const std::string& session_id) { | 433 const std::string& session_id) { |
434 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
435 | |
428 scoped_ptr<SimplePromise> promise( | 436 scoped_ptr<SimplePromise> promise( |
429 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); | 437 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); |
430 | 438 |
431 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 439 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
432 if (!cdm) { | 440 if (!cdm) { |
433 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 441 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
434 return; | 442 return; |
435 } | 443 } |
436 | 444 |
437 cdm->CloseSession(session_id, promise.Pass()); | 445 cdm->CloseSession(session_id, promise.Pass()); |
438 } | 446 } |
439 | 447 |
440 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { | 448 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { |
449 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
441 RemoveCdm(GetId(render_frame_id, cdm_id)); | 450 RemoveCdm(GetId(render_frame_id, cdm_id)); |
442 } | 451 } |
443 | 452 |
444 // Use a weak pointer here instead of |this| to avoid circular references. | 453 // Use a weak pointer here instead of |this| to avoid circular references. |
445 #define BROWSER_CDM_MANAGER_CB(func) \ | 454 #define BROWSER_CDM_MANAGER_CB(func) \ |
446 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ | 455 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ |
447 render_frame_id, cdm_id) | 456 render_frame_id, cdm_id) |
448 | 457 |
449 void BrowserCdmManager::AddCdm(int render_frame_id, | 458 void BrowserCdmManager::AddCdm(int render_frame_id, |
450 int cdm_id, | 459 int cdm_id, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 | 492 |
484 for (size_t i = 0; i < ids_to_remove.size(); ++i) | 493 for (size_t i = 0; i < ids_to_remove.size(); ++i) |
485 RemoveCdm(ids_to_remove[i]); | 494 RemoveCdm(ids_to_remove[i]); |
486 } | 495 } |
487 | 496 |
488 void BrowserCdmManager::RemoveCdm(uint64 id) { | 497 void BrowserCdmManager::RemoveCdm(uint64 id) { |
489 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 498 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
490 | 499 |
491 cdm_map_.erase(id); | 500 cdm_map_.erase(id); |
492 cdm_security_origin_map_.erase(id); | 501 cdm_security_origin_map_.erase(id); |
493 if (cdm_cancel_permission_map_.count(id)) { | |
494 cdm_cancel_permission_map_[id].Run(); | |
495 cdm_cancel_permission_map_.erase(id); | |
496 } | |
497 } | 502 } |
498 | 503 |
499 void BrowserCdmManager::RequestSessionPermission( | 504 void BrowserCdmManager::CheckPermissionStatus( |
500 int render_frame_id, | 505 int render_frame_id, |
501 const GURL& security_origin, | 506 const GURL& security_origin, |
502 int cdm_id, | 507 int cdm_id, |
503 media::EmeInitDataType init_data_type, | 508 media::EmeInitDataType init_data_type, |
504 const std::vector<uint8>& init_data, | 509 const std::vector<uint8>& init_data, |
505 scoped_ptr<media::NewSessionCdmPromise> promise) { | 510 scoped_ptr<media::NewSessionCdmPromise> promise) { |
511 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
ddorwin
2015/03/16 23:58:28
This seems inconsistent with the need for line 514
xhwang
2015/03/17 01:25:22
|task_runner_| is not always on the UI thread. Add
| |
512 | |
513 // RenderFrameHost::FromID() can only be called from the UI thread. | |
506 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 514 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
507 BrowserThread::PostTask( | 515 BrowserThread::PostTask( |
508 BrowserThread::UI, FROM_HERE, | 516 BrowserThread::UI, FROM_HERE, |
509 base::Bind(&BrowserCdmManager::RequestSessionPermission, this, | 517 base::Bind(&BrowserCdmManager::CheckPermissionStatus, this, |
510 render_frame_id, security_origin, cdm_id, init_data_type, | 518 render_frame_id, security_origin, cdm_id, init_data_type, |
511 init_data, base::Passed(&promise))); | 519 init_data, base::Passed(&promise))); |
512 return; | 520 return; |
513 } | 521 } |
514 | 522 |
523 // Note: This part of code may not run on the |task_runner_|. Be careful | |
524 // about thread safty! | |
525 | |
515 RenderFrameHost* rfh = | 526 RenderFrameHost* rfh = |
516 RenderFrameHost::FromID(render_process_id_, render_frame_id); | 527 RenderFrameHost::FromID(render_process_id_, render_frame_id); |
517 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); | 528 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); |
518 DCHECK(web_contents); | 529 |
519 GetContentClient()->browser()->RequestPermission( | 530 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
520 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER, web_contents, | 531 |
521 0, // bridge id | 532 PermissionStatus permission_status = |
522 security_origin, | 533 GetContentClient()->browser()->GetPermissionStatus( |
523 // Only implemented for Android infobars which do not support | 534 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER, |
524 // user gestures. | 535 web_contents->GetBrowserContext(), security_origin, embedding_origin); |
525 true, base::Bind(&BrowserCdmManager::GenerateRequestIfPermitted, this, | 536 |
526 render_frame_id, cdm_id, init_data_type, init_data, | 537 CreateSessionAndGenerateRequest(render_frame_id, cdm_id, init_data_type, |
ddorwin
2015/03/16 23:58:28
It seems odd to do this inside CheckPermissionStat
xhwang
2015/03/17 01:25:22
Good point. Updated.
| |
527 base::Passed(&promise))); | 538 init_data, promise.Pass(), permission_status); |
528 } | 539 } |
529 | 540 |
530 void BrowserCdmManager::GenerateRequestIfPermitted( | 541 void BrowserCdmManager::CreateSessionAndGenerateRequest( |
531 int render_frame_id, | 542 int render_frame_id, |
532 int cdm_id, | 543 int cdm_id, |
533 media::EmeInitDataType init_data_type, | 544 media::EmeInitDataType init_data_type, |
534 const std::vector<uint8>& init_data, | 545 const std::vector<uint8>& init_data, |
535 scoped_ptr<media::NewSessionCdmPromise> promise, | 546 scoped_ptr<media::NewSessionCdmPromise> promise, |
536 PermissionStatus permission) { | 547 PermissionStatus permission_status) { |
537 cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id)); | 548 // Make sure cdm->CreateSessionAndGenerateRequest() is called on the |
538 if (permission != PERMISSION_STATUS_GRANTED) { | 549 // |task_runner_|. |
550 if (!task_runner_->RunsTasksOnCurrentThread()) { | |
551 task_runner_->PostTask( | |
552 FROM_HERE, | |
553 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequest, this, | |
554 render_frame_id, cdm_id, init_data_type, init_data, | |
555 base::Passed(&promise), permission_status)); | |
556 return; | |
557 } | |
558 | |
559 if (permission_status != PERMISSION_STATUS_GRANTED) { | |
ddorwin
2015/03/16 23:58:28
Why do we do this here? Probably because GenerateR
xhwang
2015/03/17 01:25:22
Done.
| |
539 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); | 560 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); |
540 return; | 561 return; |
541 } | 562 } |
542 | 563 |
543 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 564 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
544 if (!cdm) { | 565 if (!cdm) { |
545 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 566 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
546 return; | 567 return; |
547 } | 568 } |
548 | 569 |
(...skipping 15 matching lines...) Expand all Loading... | |
564 } | 585 } |
565 | 586 |
566 // Only the temporary session type is supported in browser CDM path. | 587 // Only the temporary session type is supported in browser CDM path. |
567 // TODO(xhwang): Add SessionType support if needed. | 588 // TODO(xhwang): Add SessionType support if needed. |
568 cdm->CreateSessionAndGenerateRequest(media::MediaKeys::TEMPORARY_SESSION, | 589 cdm->CreateSessionAndGenerateRequest(media::MediaKeys::TEMPORARY_SESSION, |
569 init_data_type_string, &init_data[0], | 590 init_data_type_string, &init_data[0], |
570 init_data.size(), promise.Pass()); | 591 init_data.size(), promise.Pass()); |
571 } | 592 } |
572 | 593 |
573 } // namespace content | 594 } // namespace content |
OLD | NEW |