Chromium Code Reviews| 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 |