| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/media/webrtc/media_stream_devices_controller.h" | 5 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 | 341 |
| 342 MediaStreamDevicesController::~MediaStreamDevicesController() { | 342 MediaStreamDevicesController::~MediaStreamDevicesController() { |
| 343 if (!callback_.is_null()) { | 343 if (!callback_.is_null()) { |
| 344 callback_.Run(content::MediaStreamDevices(), | 344 callback_.Run(content::MediaStreamDevices(), |
| 345 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, | 345 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, |
| 346 std::unique_ptr<content::MediaStreamUI>()); | 346 std::unique_ptr<content::MediaStreamUI>()); |
| 347 } | 347 } |
| 348 } | 348 } |
| 349 | 349 |
| 350 bool MediaStreamDevicesController::IsAskingForAudio() const { | 350 bool MediaStreamDevicesController::IsAskingForAudio() const { |
| 351 return old_audio_setting_ == CONTENT_SETTING_ASK; | 351 return audio_setting_ == CONTENT_SETTING_ASK; |
| 352 } | 352 } |
| 353 | 353 |
| 354 bool MediaStreamDevicesController::IsAskingForVideo() const { | 354 bool MediaStreamDevicesController::IsAskingForVideo() const { |
| 355 return old_video_setting_ == CONTENT_SETTING_ASK; | 355 return video_setting_ == CONTENT_SETTING_ASK; |
| 356 } | 356 } |
| 357 | 357 |
| 358 void MediaStreamDevicesController::PromptAnswered(ContentSetting setting, | 358 void MediaStreamDevicesController::PromptAnswered(ContentSetting setting, |
| 359 bool persist) { | 359 bool persist) { |
| 360 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 360 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 361 | 361 |
| 362 HostContentSettingsMap* host_content_settings_map = | 362 HostContentSettingsMap* host_content_settings_map = |
| 363 HostContentSettingsMapFactory::GetForProfile(profile_); | 363 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 364 ContentSetting audio_setting = old_audio_setting_; | 364 if (audio_setting_ == CONTENT_SETTING_ASK) { |
| 365 if (old_audio_setting_ == CONTENT_SETTING_ASK) { | |
| 366 if (persist && setting != CONTENT_SETTING_ASK) { | 365 if (persist && setting != CONTENT_SETTING_ASK) { |
| 367 host_content_settings_map->SetContentSettingDefaultScope( | 366 host_content_settings_map->SetContentSettingDefaultScope( |
| 368 request_.security_origin, GURL(), | 367 request_.security_origin, GURL(), |
| 369 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting); | 368 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting); |
| 370 } | 369 } |
| 371 audio_setting = setting; | 370 audio_setting_ = setting; |
| 372 } | 371 } |
| 373 | 372 |
| 374 ContentSetting video_setting = old_video_setting_; | 373 if (video_setting_ == CONTENT_SETTING_ASK) { |
| 375 if (old_video_setting_ == CONTENT_SETTING_ASK) { | |
| 376 if (persist && setting != CONTENT_SETTING_ASK) { | 374 if (persist && setting != CONTENT_SETTING_ASK) { |
| 377 host_content_settings_map->SetContentSettingDefaultScope( | 375 host_content_settings_map->SetContentSettingDefaultScope( |
| 378 request_.security_origin, GURL(), | 376 request_.security_origin, GURL(), |
| 379 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting); | 377 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting); |
| 380 } | 378 } |
| 381 video_setting = setting; | 379 video_setting_ = setting; |
| 382 } | 380 } |
| 383 | 381 |
| 384 content::MediaStreamRequestResult denial_reason = content::MEDIA_DEVICE_OK; | 382 if (setting == CONTENT_SETTING_BLOCK) |
| 385 if (setting == CONTENT_SETTING_ASK) | 383 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED; |
| 386 denial_reason = content::MEDIA_DEVICE_PERMISSION_DISMISSED; | 384 else if (setting == CONTENT_SETTING_ASK) |
| 387 else if (setting == CONTENT_SETTING_BLOCK) | 385 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DISMISSED; |
| 388 denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED; | |
| 389 | 386 |
| 390 RunCallback(audio_setting, video_setting, denial_reason); | 387 RunCallback(); |
| 391 } | 388 } |
| 392 | 389 |
| 393 #if defined(OS_ANDROID) | 390 #if defined(OS_ANDROID) |
| 394 void MediaStreamDevicesController::AndroidOSPromptAnswered(bool allowed) { | 391 void MediaStreamDevicesController::AndroidOSPromptAnswered(bool allowed) { |
| 395 DCHECK(old_audio_setting_ != CONTENT_SETTING_ASK && | 392 DCHECK(audio_setting_ != CONTENT_SETTING_ASK && |
| 396 old_video_setting_ != CONTENT_SETTING_ASK); | 393 video_setting_ != CONTENT_SETTING_ASK); |
| 397 | |
| 398 ContentSetting audio_setting = old_audio_setting_; | |
| 399 ContentSetting video_setting = old_video_setting_; | |
| 400 | 394 |
| 401 if (!allowed) { | 395 if (!allowed) { |
| 396 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED; |
| 402 // Only permissions that were previously ALLOW for a site will have had | 397 // Only permissions that were previously ALLOW for a site will have had |
| 403 // their android permissions requested. It's only in that case that we need | 398 // their android permissions requested. It's only in that case that we need |
| 404 // to change the setting to BLOCK to reflect that it wasn't allowed. | 399 // to change the setting to BLOCK to reflect that it wasn't allowed. |
| 405 if (audio_setting == CONTENT_SETTING_ALLOW) | 400 if (audio_setting_ == CONTENT_SETTING_ALLOW) |
| 406 audio_setting = CONTENT_SETTING_BLOCK; | 401 audio_setting_ = CONTENT_SETTING_BLOCK; |
| 407 if (video_setting == CONTENT_SETTING_ALLOW) | 402 if (video_setting_ == CONTENT_SETTING_ALLOW) |
| 408 video_setting = CONTENT_SETTING_BLOCK; | 403 video_setting_ = CONTENT_SETTING_BLOCK; |
| 409 } | 404 } |
| 410 | 405 |
| 411 RunCallback(audio_setting, video_setting, | 406 RunCallback(); |
| 412 content::MEDIA_DEVICE_PERMISSION_DENIED); | |
| 413 } | 407 } |
| 414 #endif // defined(OS_ANDROID) | 408 #endif // defined(OS_ANDROID) |
| 415 | 409 |
| 410 void MediaStreamDevicesController::RequestFinishedNoPrompt() { |
| 411 RunCallback(); |
| 412 } |
| 413 |
| 416 // static | 414 // static |
| 417 void MediaStreamDevicesController::RequestPermissionsWithDelegate( | 415 void MediaStreamDevicesController::RequestPermissionsWithDelegate( |
| 418 const content::MediaStreamRequest& request, | 416 const content::MediaStreamRequest& request, |
| 419 const content::MediaResponseCallback& callback, | 417 const content::MediaResponseCallback& callback, |
| 420 PermissionPromptDelegate* delegate) { | 418 PermissionPromptDelegate* delegate) { |
| 421 content::WebContents* web_contents = | 419 content::WebContents* web_contents = |
| 422 content::WebContents::FromRenderFrameHost( | 420 content::WebContents::FromRenderFrameHost( |
| 423 content::RenderFrameHost::FromID(request.render_process_id, | 421 content::RenderFrameHost::FromID(request.render_process_id, |
| 424 request.render_frame_id)); | 422 request.render_frame_id)); |
| 425 if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) { | 423 if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) { |
| 426 MediaPermissionRequestLogger::LogRequest( | 424 MediaPermissionRequestLogger::LogRequest( |
| 427 web_contents, request.render_process_id, request.render_frame_id, | 425 web_contents, request.render_process_id, request.render_frame_id, |
| 428 content::IsOriginSecure(request.security_origin)); | 426 content::IsOriginSecure(request.security_origin)); |
| 429 } | 427 } |
| 430 | 428 |
| 431 std::unique_ptr<MediaStreamDevicesController> controller( | 429 std::unique_ptr<MediaStreamDevicesController> controller( |
| 432 new MediaStreamDevicesController(web_contents, request, callback)); | 430 new MediaStreamDevicesController(web_contents, request, callback)); |
| 433 if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) { | |
| 434 #if defined(OS_ANDROID) | |
| 435 // If either audio or video was previously allowed and Chrome no longer has | |
| 436 // the necessary permissions, show a infobar to attempt to address this | |
| 437 // mismatch. | |
| 438 std::vector<ContentSettingsType> content_settings_types; | |
| 439 if (controller->IsAllowedForAudio()) | |
| 440 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); | |
| 441 | 431 |
| 442 if (controller->IsAllowedForVideo()) { | 432 // Show a prompt if needed. |
| 443 content_settings_types.push_back( | 433 if (controller->IsAskingForAudio() || controller->IsAskingForVideo()) { |
| 444 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); | 434 Profile* profile = |
| 445 } | 435 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 446 if (!content_settings_types.empty() && | 436 delegate->ShowPrompt( |
| 447 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar( | 437 request.user_gesture, web_contents, |
| 448 web_contents, content_settings_types)) { | 438 base::MakeUnique<Request>( |
| 449 PermissionUpdateInfoBarDelegate::Create( | 439 profile, controller->IsAskingForAudio(), |
| 450 web_contents, content_settings_types, | 440 controller->IsAskingForVideo(), request.security_origin, |
| 451 base::Bind(&MediaStreamDevicesController::AndroidOSPromptAnswered, | 441 base::Bind(&MediaStreamDevicesController::PromptAnswered, |
| 452 base::Passed(&controller))); | 442 base::Passed(&controller)))); |
| 453 } | |
| 454 #endif | |
| 455 return; | 443 return; |
| 456 } | 444 } |
| 457 | 445 |
| 458 Profile* profile = | 446 #if defined(OS_ANDROID) |
| 459 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 447 // If either audio or video was previously allowed and Chrome no longer has |
| 460 delegate->ShowPrompt( | 448 // the necessary permissions, show a infobar to attempt to address this |
| 461 request.user_gesture, web_contents, | 449 // mismatch. |
| 462 base::MakeUnique<MediaStreamDevicesController::Request>( | 450 std::vector<ContentSettingsType> content_settings_types; |
| 463 profile, controller->IsAskingForAudio(), | 451 if (controller->IsAllowedForAudio()) |
| 464 controller->IsAskingForVideo(), request.security_origin, | 452 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); |
| 465 base::Bind(&MediaStreamDevicesController::PromptAnswered, | 453 |
| 466 base::Passed(&controller)))); | 454 if (controller->IsAllowedForVideo()) { |
| 455 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); |
| 456 } |
| 457 if (!content_settings_types.empty() && |
| 458 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar( |
| 459 web_contents, content_settings_types)) { |
| 460 PermissionUpdateInfoBarDelegate::Create( |
| 461 web_contents, content_settings_types, |
| 462 base::Bind(&MediaStreamDevicesController::AndroidOSPromptAnswered, |
| 463 base::Passed(&controller))); |
| 464 return; |
| 465 } |
| 466 #endif |
| 467 |
| 468 // If we reach here, no prompt needed to be shown. |
| 469 controller->RequestFinishedNoPrompt(); |
| 467 } | 470 } |
| 468 | 471 |
| 469 MediaStreamDevicesController::MediaStreamDevicesController( | 472 MediaStreamDevicesController::MediaStreamDevicesController( |
| 470 content::WebContents* web_contents, | 473 content::WebContents* web_contents, |
| 471 const content::MediaStreamRequest& request, | 474 const content::MediaStreamRequest& request, |
| 472 const content::MediaResponseCallback& callback) | 475 const content::MediaResponseCallback& callback) |
| 473 : web_contents_(web_contents), request_(request), callback_(callback) { | 476 : web_contents_(web_contents), request_(request), callback_(callback) { |
| 474 DCHECK(content::IsOriginSecure(request_.security_origin) || | 477 DCHECK(content::IsOriginSecure(request_.security_origin) || |
| 475 request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); | 478 request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); |
| 476 | 479 |
| 477 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 480 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 478 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); | 481 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); |
| 479 | 482 |
| 480 content::MediaStreamRequestResult denial_reason = content::MEDIA_DEVICE_OK; | 483 denial_reason_ = content::MEDIA_DEVICE_OK; |
| 481 old_audio_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, | 484 audio_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, |
| 482 request, &denial_reason); | 485 request, &denial_reason_); |
| 483 old_video_setting_ = GetContentSetting( | 486 video_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, |
| 484 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request, &denial_reason); | 487 request, &denial_reason_); |
| 485 | |
| 486 // If either setting is ask, we show the infobar. | |
| 487 if (old_audio_setting_ == CONTENT_SETTING_ASK || | |
| 488 old_video_setting_ == CONTENT_SETTING_ASK) { | |
| 489 return; | |
| 490 } | |
| 491 | |
| 492 #if defined(OS_ANDROID) | |
| 493 std::vector<ContentSettingsType> content_settings_types; | |
| 494 if (IsAllowedForAudio()) | |
| 495 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); | |
| 496 | |
| 497 if (IsAllowedForVideo()) { | |
| 498 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); | |
| 499 } | |
| 500 | |
| 501 // If the site had been previously granted the access to audio or video but | |
| 502 // Chrome is now missing the necessary permission, we need to show an infobar | |
| 503 // to resolve the difference. | |
| 504 if (!content_settings_types.empty() && | |
| 505 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar( | |
| 506 web_contents, content_settings_types)) { | |
| 507 return; | |
| 508 } | |
| 509 #endif | |
| 510 | |
| 511 // Otherwise we can run the callback immediately. | |
| 512 RunCallback(old_audio_setting_, old_video_setting_, denial_reason); | |
| 513 } | 488 } |
| 514 | 489 |
| 515 bool MediaStreamDevicesController::IsAllowedForAudio() const { | 490 bool MediaStreamDevicesController::IsAllowedForAudio() const { |
| 516 return old_audio_setting_ == CONTENT_SETTING_ALLOW; | 491 return audio_setting_ == CONTENT_SETTING_ALLOW; |
| 517 } | 492 } |
| 518 | 493 |
| 519 bool MediaStreamDevicesController::IsAllowedForVideo() const { | 494 bool MediaStreamDevicesController::IsAllowedForVideo() const { |
| 520 return old_video_setting_ == CONTENT_SETTING_ALLOW; | 495 return video_setting_ == CONTENT_SETTING_ALLOW; |
| 521 } | 496 } |
| 522 | 497 |
| 523 content::MediaStreamDevices MediaStreamDevicesController::GetDevices( | 498 content::MediaStreamDevices MediaStreamDevicesController::GetDevices( |
| 524 ContentSetting audio_setting, | 499 ContentSetting audio_setting, |
| 525 ContentSetting video_setting) { | 500 ContentSetting video_setting) { |
| 526 bool audio_allowed = audio_setting == CONTENT_SETTING_ALLOW; | 501 bool audio_allowed = audio_setting == CONTENT_SETTING_ALLOW; |
| 527 bool video_allowed = video_setting == CONTENT_SETTING_ALLOW; | 502 bool video_allowed = video_setting == CONTENT_SETTING_ALLOW; |
| 528 | 503 |
| 529 if (!audio_allowed && !video_allowed) | 504 if (!audio_allowed && !video_allowed) |
| 530 return content::MediaStreamDevices(); | 505 return content::MediaStreamDevices(); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 // Get the default devices for the request. | 577 // Get the default devices for the request. |
| 603 MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile( | 578 MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile( |
| 604 profile_, audio_allowed, video_allowed, &devices); | 579 profile_, audio_allowed, video_allowed, &devices); |
| 605 break; | 580 break; |
| 606 } | 581 } |
| 607 } // switch | 582 } // switch |
| 608 | 583 |
| 609 return devices; | 584 return devices; |
| 610 } | 585 } |
| 611 | 586 |
| 612 void MediaStreamDevicesController::RunCallback( | 587 void MediaStreamDevicesController::RunCallback() { |
| 613 ContentSetting audio_setting, | |
| 614 ContentSetting video_setting, | |
| 615 content::MediaStreamRequestResult denial_reason) { | |
| 616 CHECK(!callback_.is_null()); | 588 CHECK(!callback_.is_null()); |
| 617 | 589 |
| 618 // If the kill switch is on we don't update the tab context. | 590 // If the kill switch is on we don't update the tab context. |
| 619 if (denial_reason != content::MEDIA_DEVICE_KILL_SWITCH_ON) | 591 if (denial_reason_ != content::MEDIA_DEVICE_KILL_SWITCH_ON) |
| 620 UpdateTabSpecificContentSettings(audio_setting, video_setting); | 592 UpdateTabSpecificContentSettings(audio_setting_, video_setting_); |
| 621 | 593 |
| 622 content::MediaStreamDevices devices = | 594 content::MediaStreamDevices devices = |
| 623 GetDevices(audio_setting, video_setting); | 595 GetDevices(audio_setting_, video_setting_); |
| 624 | 596 |
| 625 // If either audio or video are allowed then the callback should report | 597 // If either audio or video are allowed then the callback should report |
| 626 // success, otherwise we report |denial_reason|. | 598 // success, otherwise we report |denial_reason_|. |
| 627 content::MediaStreamRequestResult request_result = content::MEDIA_DEVICE_OK; | 599 content::MediaStreamRequestResult request_result = content::MEDIA_DEVICE_OK; |
| 628 if (audio_setting != CONTENT_SETTING_ALLOW && | 600 if (audio_setting_ != CONTENT_SETTING_ALLOW && |
| 629 video_setting != CONTENT_SETTING_ALLOW) { | 601 video_setting_ != CONTENT_SETTING_ALLOW) { |
| 630 DCHECK_NE(content::MEDIA_DEVICE_OK, denial_reason); | 602 DCHECK_NE(content::MEDIA_DEVICE_OK, denial_reason_); |
| 631 request_result = denial_reason; | 603 request_result = denial_reason_; |
| 632 } else if (devices.empty()) { | 604 } else if (devices.empty()) { |
| 633 // Even if one of the content settings was allowed, if there are no devices | 605 // Even if one of the content settings was allowed, if there are no devices |
| 634 // at this point we still report a failure. | 606 // at this point we still report a failure. |
| 635 request_result = content::MEDIA_DEVICE_NO_HARDWARE; | 607 request_result = content::MEDIA_DEVICE_NO_HARDWARE; |
| 636 } | 608 } |
| 637 | 609 |
| 638 std::unique_ptr<content::MediaStreamUI> ui; | 610 std::unique_ptr<content::MediaStreamUI> ui; |
| 639 if (!devices.empty()) { | 611 if (!devices.empty()) { |
| 640 ui = MediaCaptureDevicesDispatcher::GetInstance() | 612 ui = MediaCaptureDevicesDispatcher::GetInstance() |
| 641 ->GetMediaStreamCaptureIndicator() | 613 ->GetMediaStreamCaptureIndicator() |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 } | 726 } |
| 755 } | 727 } |
| 756 | 728 |
| 757 // Don't approve device requests if the tab was hidden. | 729 // Don't approve device requests if the tab was hidden. |
| 758 // TODO(qinmin): Add a test for this. http://crbug.com/396869. | 730 // TODO(qinmin): Add a test for this. http://crbug.com/396869. |
| 759 // TODO(raymes): Shouldn't this apply to all permissions not just audio/video? | 731 // TODO(raymes): Shouldn't this apply to all permissions not just audio/video? |
| 760 return web_contents_->GetRenderWidgetHostView()->IsShowing(); | 732 return web_contents_->GetRenderWidgetHostView()->IsShowing(); |
| 761 #endif | 733 #endif |
| 762 return true; | 734 return true; |
| 763 } | 735 } |
| OLD | NEW |