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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/media/media_stream_devices_controller.h" 6 7 #include "base/metrics/histogram.h" 8 #include "base/prefs/scoped_user_pref_update.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "base/values.h" 11 #include "chrome/browser/content_settings/host_content_settings_map.h" 12 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 13 #include "chrome/browser/media/media_capture_devices_dispatcher.h" 14 #include "chrome/browser/media/media_stream_capture_indicator.h" 15 #include "chrome/browser/media/media_stream_device_permissions.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/common/chrome_switches.h" 19 #include "chrome/common/pref_names.h" 20 #include "chrome/grit/generated_resources.h" 21 #include "components/content_settings/core/browser/content_settings_provider.h" 22 #include "components/content_settings/core/common/content_settings.h" 23 #include "components/content_settings/core/common/content_settings_pattern.h" 24 #include "components/pref_registry/pref_registry_syncable.h" 25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/render_widget_host_view.h" 27 #include "content/public/common/media_stream_request.h" 28 #include "extensions/common/constants.h" 29 #include "grit/theme_resources.h" 30 #include "ui/base/l10n/l10n_util.h" 31 32 using content::BrowserThread; 33 34 namespace { 35 36 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) { 37 const content::MediaStreamDevices* audio_devices = 38 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ? 39 &MediaCaptureDevicesDispatcher::GetInstance() 40 ->GetAudioCaptureDevices() : 41 NULL; 42 43 const content::MediaStreamDevices* video_devices = 44 request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ? 45 &MediaCaptureDevicesDispatcher::GetInstance() 46 ->GetVideoCaptureDevices() : 47 NULL; 48 49 // Check if we're being asked for audio and/or video and that either of those 50 // lists is empty. If they are, we do not have devices available for the 51 // request. 52 // TODO(tommi): It's kind of strange to have this here since if we fail this 53 // test, there'll be a UI shown that indicates to the user that access to 54 // non-existing audio/video devices has been denied. The user won't have 55 // any way to change that but there will be a UI shown which indicates that 56 // access is blocked. 57 if ((audio_devices != NULL && audio_devices->empty()) || 58 (video_devices != NULL && video_devices->empty())) { 59 return false; 60 } 61 62 // Note: we check requested_[audio|video]_device_id before dereferencing 63 // [audio|video]_devices. If the requested device id is non-empty, then 64 // the corresponding device list must not be NULL. 65 66 if (!request.requested_audio_device_id.empty() && 67 !audio_devices->FindById(request.requested_audio_device_id)) { 68 return false; 69 } 70 71 if (!request.requested_video_device_id.empty() && 72 !video_devices->FindById(request.requested_video_device_id)) { 73 return false; 74 } 75 76 return true; 77 } 78 79 enum DevicePermissionActions { 80 kAllowHttps = 0, 81 kAllowHttp, 82 kDeny, 83 kCancel, 84 kPermissionActionsMax // Must always be last! 85 }; 86 87 } // namespace 88 89 MediaStreamDevicesController::MediaStreamTypeSettings::MediaStreamTypeSettings( 90 Permission permission, const std::string& requested_device_id): 91 permission(permission), requested_device_id(requested_device_id) {} 92 93 MediaStreamDevicesController::MediaStreamTypeSettings:: 94 MediaStreamTypeSettings(): permission(MEDIA_NONE) {} 95 96 MediaStreamDevicesController::MediaStreamTypeSettings:: 97 ~MediaStreamTypeSettings() {} 98 99 MediaStreamDevicesController::MediaStreamDevicesController( 100 content::WebContents* web_contents, 101 const content::MediaStreamRequest& request, 102 const content::MediaResponseCallback& callback) 103 : web_contents_(web_contents), 104 request_(request), 105 callback_(callback) { 106 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); 107 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); 108 109 // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam 110 // and microphone to avoid popping two infobars. 111 // We start with setting the requested media type to allowed or blocked 112 // depending on the policy. If not blocked by policy it may be blocked later 113 // in the two remaining filtering steps (by user setting or by user when 114 // clicking the infobar). 115 // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE 116 // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed. 117 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || 118 request.request_type == content::MEDIA_OPEN_DEVICE) { 119 if (GetDevicePolicy(profile_, 120 request_.security_origin, 121 prefs::kAudioCaptureAllowed, 122 prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) { 123 request_permissions_.insert(std::make_pair( 124 content::MEDIA_DEVICE_AUDIO_CAPTURE, 125 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, 126 request.requested_audio_device_id))); 127 } else { 128 request_permissions_.insert(std::make_pair( 129 content::MEDIA_DEVICE_AUDIO_CAPTURE, 130 MediaStreamTypeSettings(MEDIA_ALLOWED, 131 request.requested_audio_device_id))); 132 } 133 } 134 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE || 135 request.request_type == content::MEDIA_OPEN_DEVICE) { 136 if (GetDevicePolicy(profile_, 137 request_.security_origin, 138 prefs::kVideoCaptureAllowed, 139 prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) { 140 request_permissions_.insert(std::make_pair( 141 content::MEDIA_DEVICE_VIDEO_CAPTURE, 142 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, 143 request.requested_video_device_id))); 144 } else { 145 request_permissions_.insert(std::make_pair( 146 content::MEDIA_DEVICE_VIDEO_CAPTURE, 147 MediaStreamTypeSettings(MEDIA_ALLOWED, 148 request.requested_video_device_id))); 149 } 150 } 151 } 152 153 MediaStreamDevicesController::~MediaStreamDevicesController() { 154 if (!callback_.is_null()) { 155 callback_.Run(content::MediaStreamDevices(), 156 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, 157 scoped_ptr<content::MediaStreamUI>()); 158 } 159 } 160 161 // static 162 void MediaStreamDevicesController::RegisterProfilePrefs( 163 user_prefs::PrefRegistrySyncable* prefs) { 164 prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed, 165 true, 166 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 167 prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed, 168 true, 169 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 170 prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls, 171 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 172 prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls, 173 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 174 } 175 176 // TODO(gbillock): rename? doesn't actually dismiss. More of a 'check profile 177 // and system for compatibility' thing. 178 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() { 179 // Tab capture is allowed for extensions only and infobar is not shown for 180 // extensions. 181 if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE || 182 request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) { 183 Deny(false, content::MEDIA_DEVICE_INVALID_STATE); 184 return true; 185 } 186 187 // Deny the request if the security origin is empty, this happens with 188 // file access without |--allow-file-access-from-files| flag. 189 if (request_.security_origin.is_empty()) { 190 Deny(false, content::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN); 191 return true; 192 } 193 194 // Deny the request if there is no device attached to the OS of the 195 // requested type. If both audio and video is requested, both types must be 196 // available. 197 if (!HasAvailableDevicesForRequest(request_)) { 198 Deny(false, content::MEDIA_DEVICE_NO_HARDWARE); 199 return true; 200 } 201 202 // Check if any allow exception has been made for this request. 203 if (IsRequestAllowedByDefault()) { 204 Accept(false); 205 return true; 206 } 207 208 // Filter any parts of the request that have been blocked by default and deny 209 // it if nothing is left to accept. 210 if (FilterBlockedByDefaultDevices() == 0) { 211 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); 212 return true; 213 } 214 215 // Check if the media default setting is set to block. 216 if (IsDefaultMediaAccessBlocked()) { 217 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); 218 return true; 219 } 220 221 // Show the infobar. 222 return false; 223 } 224 225 bool MediaStreamDevicesController::HasAudio() const { 226 return IsDeviceAudioCaptureRequestedAndAllowed(); 227 } 228 229 bool MediaStreamDevicesController::HasVideo() const { 230 return IsDeviceVideoCaptureRequestedAndAllowed(); 231 } 232 233 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const { 234 return request_.security_origin.spec(); 235 } 236 237 void MediaStreamDevicesController::Accept(bool update_content_setting) { 238 NotifyUIRequestAccepted(); 239 240 // Get the default devices for the request. 241 content::MediaStreamDevices devices; 242 bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed(); 243 bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed(); 244 if (audio_allowed || video_allowed) { 245 switch (request_.request_type) { 246 case content::MEDIA_OPEN_DEVICE: { 247 const content::MediaStreamDevice* device = NULL; 248 // For open device request, when requested device_id is empty, pick 249 // the first available of the given type. If requested device_id is 250 // not empty, return the desired device if it's available. Otherwise, 251 // return no device. 252 if (audio_allowed && 253 request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { 254 if (!request_.requested_audio_device_id.empty()) { 255 device = MediaCaptureDevicesDispatcher::GetInstance()-> 256 GetRequestedAudioDevice(request_.requested_audio_device_id); 257 } else { 258 device = MediaCaptureDevicesDispatcher::GetInstance()-> 259 GetFirstAvailableAudioDevice(); 260 } 261 } else if (video_allowed && 262 request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { 263 // Pepper API opens only one device at a time. 264 if (!request_.requested_video_device_id.empty()) { 265 device = MediaCaptureDevicesDispatcher::GetInstance()-> 266 GetRequestedVideoDevice(request_.requested_video_device_id); 267 } else { 268 device = MediaCaptureDevicesDispatcher::GetInstance()-> 269 GetFirstAvailableVideoDevice(); 270 } 271 } 272 if (device) 273 devices.push_back(*device); 274 break; 275 } 276 case content::MEDIA_GENERATE_STREAM: { 277 bool get_default_audio_device = audio_allowed; 278 bool get_default_video_device = video_allowed; 279 280 // Get the exact audio or video device if an id is specified. 281 if (audio_allowed && !request_.requested_audio_device_id.empty()) { 282 const content::MediaStreamDevice* audio_device = 283 MediaCaptureDevicesDispatcher::GetInstance()-> 284 GetRequestedAudioDevice(request_.requested_audio_device_id); 285 if (audio_device) { 286 devices.push_back(*audio_device); 287 get_default_audio_device = false; 288 } 289 } 290 if (video_allowed && !request_.requested_video_device_id.empty()) { 291 const content::MediaStreamDevice* video_device = 292 MediaCaptureDevicesDispatcher::GetInstance()-> 293 GetRequestedVideoDevice(request_.requested_video_device_id); 294 if (video_device) { 295 devices.push_back(*video_device); 296 get_default_video_device = false; 297 } 298 } 299 300 // If either or both audio and video devices were requested but not 301 // specified by id, get the default devices. 302 if (get_default_audio_device || get_default_video_device) { 303 MediaCaptureDevicesDispatcher::GetInstance()-> 304 GetDefaultDevicesForProfile(profile_, 305 get_default_audio_device, 306 get_default_video_device, 307 &devices); 308 } 309 break; 310 } 311 case content::MEDIA_DEVICE_ACCESS: { 312 // Get the default devices for the request. 313 MediaCaptureDevicesDispatcher::GetInstance()-> 314 GetDefaultDevicesForProfile(profile_, 315 audio_allowed, 316 video_allowed, 317 &devices); 318 break; 319 } 320 case content::MEDIA_ENUMERATE_DEVICES: { 321 // Do nothing. 322 NOTREACHED(); 323 break; 324 } 325 } // switch 326 327 // TODO(raymes): We currently set the content permission for non-https 328 // websites for Pepper requests as well. This is temporary and should be 329 // removed. 330 if (update_content_setting) { 331 if ((IsSchemeSecure() && !devices.empty()) || 332 request_.request_type == content::MEDIA_OPEN_DEVICE) { 333 SetPermission(true); 334 } 335 } 336 337 if (audio_allowed) { 338 profile_->GetHostContentSettingsMap()->UpdateLastUsageByPattern( 339 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin), 340 ContentSettingsPattern::Wildcard(), 341 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); 342 } 343 if (video_allowed) { 344 profile_->GetHostContentSettingsMap()->UpdateLastUsageByPattern( 345 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin), 346 ContentSettingsPattern::Wildcard(), 347 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); 348 } 349 } 350 351 scoped_ptr<content::MediaStreamUI> ui; 352 if (!devices.empty()) { 353 ui = MediaCaptureDevicesDispatcher::GetInstance()-> 354 GetMediaStreamCaptureIndicator()->RegisterMediaStream( 355 web_contents_, devices); 356 } 357 content::MediaResponseCallback cb = callback_; 358 callback_.Reset(); 359 cb.Run(devices, 360 devices.empty() ? 361 content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, 362 ui.Pass()); 363 } 364 365 void MediaStreamDevicesController::Deny( 366 bool update_content_setting, 367 content::MediaStreamRequestResult result) { 368 DLOG(WARNING) << "MediaStreamDevicesController::Deny: " << result; 369 NotifyUIRequestDenied(); 370 371 if (update_content_setting) { 372 CHECK_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, result); 373 SetPermission(false); 374 } 375 376 content::MediaResponseCallback cb = callback_; 377 callback_.Reset(); 378 cb.Run(content::MediaStreamDevices(), 379 result, 380 scoped_ptr<content::MediaStreamUI>()); 381 } 382 383 int MediaStreamDevicesController::GetIconID() const { 384 if (HasVideo()) 385 return IDR_INFOBAR_MEDIA_STREAM_CAMERA; 386 387 return IDR_INFOBAR_MEDIA_STREAM_MIC; 388 } 389 390 base::string16 MediaStreamDevicesController::GetMessageText() const { 391 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO; 392 if (!HasAudio()) 393 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY; 394 else if (!HasVideo()) 395 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY; 396 return l10n_util::GetStringFUTF16( 397 message_id, base::UTF8ToUTF16(GetSecurityOriginSpec())); 398 } 399 400 base::string16 MediaStreamDevicesController::GetMessageTextFragment() const { 401 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT; 402 if (!HasAudio()) 403 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT; 404 else if (!HasVideo()) 405 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT; 406 return l10n_util::GetStringUTF16(message_id); 407 } 408 409 bool MediaStreamDevicesController::HasUserGesture() const { 410 return request_.user_gesture; 411 } 412 413 GURL MediaStreamDevicesController::GetRequestingHostname() const { 414 return request_.security_origin; 415 } 416 417 void MediaStreamDevicesController::PermissionGranted() { 418 GURL origin(GetSecurityOriginSpec()); 419 if (origin.SchemeIsSecure()) { 420 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", 421 kAllowHttps, kPermissionActionsMax); 422 } else { 423 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", 424 kAllowHttp, kPermissionActionsMax); 425 } 426 Accept(true); 427 } 428 429 void MediaStreamDevicesController::PermissionDenied() { 430 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", 431 kDeny, kPermissionActionsMax); 432 Deny(true, content::MEDIA_DEVICE_PERMISSION_DENIED); 433 } 434 435 void MediaStreamDevicesController::Cancelled() { 436 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", 437 kCancel, kPermissionActionsMax); 438 Deny(false, content::MEDIA_DEVICE_PERMISSION_DISMISSED); 439 } 440 441 void MediaStreamDevicesController::RequestFinished() { 442 delete this; 443 } 444 445 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const { 446 // The request from internal objects like chrome://URLs is always allowed. 447 if (CheckAllowAllMediaStreamContentForOrigin(profile_, 448 request_.security_origin)) { 449 return true; 450 } 451 452 struct { 453 bool has_capability; 454 const char* policy_name; 455 const char* list_policy_name; 456 ContentSettingsType settings_type; 457 } device_checks[] = { 458 { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed, 459 prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC }, 460 { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed, 461 prefs::kVideoCaptureAllowedUrls, 462 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA }, 463 }; 464 465 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) { 466 if (!device_checks[i].has_capability) 467 continue; 468 469 MediaStreamDevicePolicy policy = 470 GetDevicePolicy(profile_, 471 request_.security_origin, 472 device_checks[i].policy_name, 473 device_checks[i].list_policy_name); 474 475 if (policy == ALWAYS_DENY) 476 return false; 477 478 if (policy == POLICY_NOT_SET) { 479 // Only load content settings from secure origins unless it is a 480 // content::MEDIA_OPEN_DEVICE (Pepper) request. 481 if (!IsSchemeSecure() && 482 request_.request_type != content::MEDIA_OPEN_DEVICE) { 483 return false; 484 } 485 if (profile_->GetHostContentSettingsMap()->GetContentSetting( 486 request_.security_origin, request_.security_origin, 487 device_checks[i].settings_type, NO_RESOURCE_IDENTIFIER) != 488 CONTENT_SETTING_ALLOW) { 489 return false; 490 } 491 } 492 // If we get here, then either policy is set to ALWAYS_ALLOW or the content 493 // settings allow the request by default. 494 } 495 496 return true; 497 } 498 499 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() { 500 int requested_devices = 0; 501 502 if (IsDeviceAudioCaptureRequestedAndAllowed()) { 503 if (profile_->GetHostContentSettingsMap()->GetContentSetting( 504 request_.security_origin, 505 request_.security_origin, 506 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 507 NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) { 508 request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission = 509 MEDIA_BLOCKED_BY_USER_SETTING; 510 } else { 511 ++requested_devices; 512 } 513 } 514 515 if (IsDeviceVideoCaptureRequestedAndAllowed()) { 516 if (profile_->GetHostContentSettingsMap()->GetContentSetting( 517 request_.security_origin, 518 request_.security_origin, 519 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 520 NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) { 521 request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission = 522 MEDIA_BLOCKED_BY_USER_SETTING; 523 } else { 524 ++requested_devices; 525 } 526 } 527 528 return requested_devices; 529 } 530 531 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const { 532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 533 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the 534 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and 535 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA. 536 ContentSetting current_setting = 537 profile_->GetHostContentSettingsMap()->GetDefaultContentSetting( 538 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL); 539 return (current_setting == CONTENT_SETTING_BLOCK); 540 } 541 542 bool MediaStreamDevicesController::IsSchemeSecure() const { 543 return request_.security_origin.SchemeIsSecure() || 544 request_.security_origin.SchemeIs(extensions::kExtensionScheme); 545 } 546 547 void MediaStreamDevicesController::SetPermission(bool allowed) const { 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 549 ContentSettingsPattern primary_pattern = 550 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin); 551 // Check the pattern is valid or not. When the request is from a file access, 552 // no exception will be made. 553 if (!primary_pattern.IsValid()) 554 return; 555 556 ContentSetting content_setting = allowed ? 557 CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; 558 if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) != 559 request_permissions_.end()) { 560 profile_->GetHostContentSettingsMap()->SetContentSetting( 561 primary_pattern, 562 ContentSettingsPattern::Wildcard(), 563 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 564 std::string(), 565 content_setting); 566 } 567 if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) != 568 request_permissions_.end()) { 569 profile_->GetHostContentSettingsMap()->SetContentSetting( 570 primary_pattern, 571 ContentSettingsPattern::Wildcard(), 572 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 573 std::string(), 574 content_setting); 575 } 576 } 577 578 void MediaStreamDevicesController::NotifyUIRequestAccepted() const { 579 if (!content_settings_) 580 return; 581 582 content_settings_->OnMediaStreamPermissionSet(request_.security_origin, 583 request_permissions_); 584 } 585 586 void MediaStreamDevicesController::NotifyUIRequestDenied() { 587 if (!content_settings_) 588 return; 589 590 if (IsDeviceAudioCaptureRequestedAndAllowed()) { 591 request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission = 592 MEDIA_BLOCKED_BY_USER; 593 } 594 if (IsDeviceVideoCaptureRequestedAndAllowed()) { 595 request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission = 596 MEDIA_BLOCKED_BY_USER; 597 } 598 599 content_settings_->OnMediaStreamPermissionSet(request_.security_origin, 600 request_permissions_); 601 } 602 603 bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed() 604 const { 605 MediaStreamTypeSettingsMap::const_iterator it = 606 request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE); 607 return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() && 608 it->second.permission == MEDIA_ALLOWED); 609 } 610 611 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed() 612 const { 613 MediaStreamTypeSettingsMap::const_iterator it = 614 request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE); 615 return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() && 616 it->second.permission == MEDIA_ALLOWED); 617 } 618 619 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const { 620 #if defined(OS_ANDROID) 621 // Don't approve device requests if the tab was hidden. 622 // TODO(qinmin): Add a test for this. http://crbug.com/396869. 623 return web_contents_->GetRenderWidgetHostView()->IsShowing(); 624 #endif 625 return true; 626 } 627