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 CreateSessionAndGenerateRequestIfPermitted( |
369 render_frame_id, cdm_id, eme_init_data_type, | 373 render_frame_id, cdm_id, eme_init_data_type, init_data, promise.Pass(), |
370 init_data, promise.Pass(), PERMISSION_STATUS_GRANTED); | 374 true /* allowed */); |
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 CheckPermissionStatus( |
383 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); | 387 render_frame_id, cdm_id, |
384 if (iter == cdm_security_origin_map_.end()) { | 388 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted, |
385 NOTREACHED(); | 389 this, render_frame_id, cdm_id, eme_init_data_type, init_data, |
386 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 390 base::Passed(&promise))); |
387 return; | |
388 } | |
389 GURL security_origin = iter->second; | |
390 | |
391 RequestSessionPermission(render_frame_id, security_origin, cdm_id, | |
392 eme_init_data_type, init_data, promise.Pass()); | |
393 } | 391 } |
394 | 392 |
395 void BrowserCdmManager::OnUpdateSession(int render_frame_id, | 393 void BrowserCdmManager::OnUpdateSession(int render_frame_id, |
396 int cdm_id, | 394 int cdm_id, |
397 uint32_t promise_id, | 395 uint32_t promise_id, |
398 const std::string& session_id, | 396 const std::string& session_id, |
399 const std::vector<uint8>& response) { | 397 const std::vector<uint8>& response) { |
| 398 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 399 |
400 scoped_ptr<SimplePromise> promise( | 400 scoped_ptr<SimplePromise> promise( |
401 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); | 401 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); |
402 | 402 |
403 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 403 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
404 if (!cdm) { | 404 if (!cdm) { |
405 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 405 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
406 return; | 406 return; |
407 } | 407 } |
408 | 408 |
409 if (response.size() > kMaxSessionResponseLength) { | 409 if (response.size() > kMaxSessionResponseLength) { |
410 LOG(WARNING) << "Response for ID " << cdm_id | 410 LOG(WARNING) << "Response for ID " << cdm_id |
411 << " is too long: " << response.size(); | 411 << " is too long: " << response.size(); |
412 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); | 412 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); |
413 return; | 413 return; |
414 } | 414 } |
415 | 415 |
416 if (response.empty()) { | 416 if (response.empty()) { |
417 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); | 417 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); |
418 return; | 418 return; |
419 } | 419 } |
420 | 420 |
421 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass()); | 421 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass()); |
422 } | 422 } |
423 | 423 |
424 void BrowserCdmManager::OnCloseSession(int render_frame_id, | 424 void BrowserCdmManager::OnCloseSession(int render_frame_id, |
425 int cdm_id, | 425 int cdm_id, |
426 uint32_t promise_id, | 426 uint32_t promise_id, |
427 const std::string& session_id) { | 427 const std::string& session_id) { |
| 428 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 429 |
428 scoped_ptr<SimplePromise> promise( | 430 scoped_ptr<SimplePromise> promise( |
429 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); | 431 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); |
430 | 432 |
431 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); | 433 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); |
432 if (!cdm) { | 434 if (!cdm) { |
433 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | 435 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); |
434 return; | 436 return; |
435 } | 437 } |
436 | 438 |
437 cdm->CloseSession(session_id, promise.Pass()); | 439 cdm->CloseSession(session_id, promise.Pass()); |
438 } | 440 } |
439 | 441 |
440 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { | 442 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { |
| 443 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
441 RemoveCdm(GetId(render_frame_id, cdm_id)); | 444 RemoveCdm(GetId(render_frame_id, cdm_id)); |
442 } | 445 } |
443 | 446 |
444 // Use a weak pointer here instead of |this| to avoid circular references. | 447 // Use a weak pointer here instead of |this| to avoid circular references. |
445 #define BROWSER_CDM_MANAGER_CB(func) \ | 448 #define BROWSER_CDM_MANAGER_CB(func) \ |
446 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ | 449 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ |
447 render_frame_id, cdm_id) | 450 render_frame_id, cdm_id) |
448 | 451 |
449 void BrowserCdmManager::AddCdm(int render_frame_id, | 452 void BrowserCdmManager::AddCdm(int render_frame_id, |
450 int cdm_id, | 453 int cdm_id, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 | 486 |
484 for (size_t i = 0; i < ids_to_remove.size(); ++i) | 487 for (size_t i = 0; i < ids_to_remove.size(); ++i) |
485 RemoveCdm(ids_to_remove[i]); | 488 RemoveCdm(ids_to_remove[i]); |
486 } | 489 } |
487 | 490 |
488 void BrowserCdmManager::RemoveCdm(uint64 id) { | 491 void BrowserCdmManager::RemoveCdm(uint64 id) { |
489 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 492 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
490 | 493 |
491 cdm_map_.erase(id); | 494 cdm_map_.erase(id); |
492 cdm_security_origin_map_.erase(id); | 495 cdm_security_origin_map_.erase(id); |
493 if (cdm_cancel_permission_map_.count(id)) { | 496 } |
494 cdm_cancel_permission_map_[id].Run(); | 497 |
495 cdm_cancel_permission_map_.erase(id); | 498 void BrowserCdmManager::CheckPermissionStatus( |
| 499 int render_frame_id, |
| 500 int cdm_id, |
| 501 const PermissionStatusCB& permission_status_cb) { |
| 502 // Always called on |task_runner_|, which may not be on the UI thread. |
| 503 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 504 |
| 505 GURL security_origin; |
| 506 std::map<uint64, GURL>::const_iterator iter = |
| 507 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); |
| 508 DCHECK(iter != cdm_security_origin_map_.end()); |
| 509 if (iter != cdm_security_origin_map_.end()) |
| 510 security_origin = iter->second; |
| 511 |
| 512 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 513 BrowserThread::PostTask( |
| 514 BrowserThread::UI, FROM_HERE, |
| 515 base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread, this, |
| 516 render_frame_id, security_origin, permission_status_cb)); |
| 517 } else { |
| 518 CheckPermissionStatusOnUIThread(render_frame_id, security_origin, |
| 519 permission_status_cb); |
496 } | 520 } |
497 } | 521 } |
498 | 522 |
499 void BrowserCdmManager::RequestSessionPermission( | 523 // Note: This function runs on the UI thread, which may be different from |
| 524 // |task_runner_|. Be careful about thread safety! |
| 525 void BrowserCdmManager::CheckPermissionStatusOnUIThread( |
500 int render_frame_id, | 526 int render_frame_id, |
501 const GURL& security_origin, | 527 const GURL& security_origin, |
502 int cdm_id, | 528 const base::Callback<void(bool)>& permission_status_cb) { |
503 media::EmeInitDataType init_data_type, | 529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
504 const std::vector<uint8>& init_data, | |
505 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
506 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
507 BrowserThread::PostTask( | |
508 BrowserThread::UI, FROM_HERE, | |
509 base::Bind(&BrowserCdmManager::RequestSessionPermission, this, | |
510 render_frame_id, security_origin, cdm_id, init_data_type, | |
511 init_data, base::Passed(&promise))); | |
512 return; | |
513 } | |
514 | 530 |
515 RenderFrameHost* rfh = | 531 RenderFrameHost* rfh = |
516 RenderFrameHost::FromID(render_process_id_, render_frame_id); | 532 RenderFrameHost::FromID(render_process_id_, render_frame_id); |
517 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); | 533 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); |
518 DCHECK(web_contents); | 534 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
519 GetContentClient()->browser()->RequestPermission( | 535 |
520 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER, web_contents, | 536 PermissionStatus permission_status = |
521 0, // bridge id | 537 GetContentClient()->browser()->GetPermissionStatus( |
522 security_origin, | 538 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER, |
523 // Only implemented for Android infobars which do not support | 539 web_contents->GetBrowserContext(), security_origin, embedding_origin); |
524 // user gestures. | 540 |
525 true, base::Bind(&BrowserCdmManager::GenerateRequestIfPermitted, this, | 541 bool allowed = (permission_status == PERMISSION_STATUS_GRANTED); |
526 render_frame_id, cdm_id, init_data_type, init_data, | 542 if (!task_runner_->RunsTasksOnCurrentThread()) { |
527 base::Passed(&promise))); | 543 task_runner_->PostTask(FROM_HERE, |
| 544 base::Bind(permission_status_cb, allowed)); |
| 545 } else { |
| 546 permission_status_cb.Run(allowed); |
| 547 } |
528 } | 548 } |
529 | 549 |
530 void BrowserCdmManager::GenerateRequestIfPermitted( | 550 void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted( |
531 int render_frame_id, | 551 int render_frame_id, |
532 int cdm_id, | 552 int cdm_id, |
533 media::EmeInitDataType init_data_type, | 553 media::EmeInitDataType init_data_type, |
534 const std::vector<uint8>& init_data, | 554 const std::vector<uint8>& init_data, |
535 scoped_ptr<media::NewSessionCdmPromise> promise, | 555 scoped_ptr<media::NewSessionCdmPromise> promise, |
536 PermissionStatus permission) { | 556 bool permission_was_allowed) { |
537 cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id)); | 557 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
538 if (permission != PERMISSION_STATUS_GRANTED) { | 558 |
| 559 if (!permission_was_allowed) { |
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 |