| 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 |