Home | History | Annotate | Download | only in media
      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/command_line.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/prefs/pref_service.h"
     10 #include "base/prefs/scoped_user_pref_update.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/content_settings/content_settings_provider.h"
     14 #include "chrome/browser/content_settings/host_content_settings_map.h"
     15 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
     16 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
     17 #include "chrome/browser/media/media_stream_capture_indicator.h"
     18 #include "chrome/browser/profiles/profile.h"
     19 #include "chrome/browser/ui/browser.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/content_settings.h"
     22 #include "chrome/common/content_settings_pattern.h"
     23 #include "chrome/common/pref_names.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/generated_resources.h"
     30 #include "grit/theme_resources.h"
     31 #include "ui/base/l10n/l10n_util.h"
     32 
     33 #if defined(OS_CHROMEOS)
     34 #include "chrome/browser/chromeos/login/users/user_manager.h"
     35 #endif
     36 
     37 using content::BrowserThread;
     38 
     39 namespace {
     40 
     41 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) {
     42   const content::MediaStreamDevices* audio_devices =
     43       request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ?
     44           &MediaCaptureDevicesDispatcher::GetInstance()
     45               ->GetAudioCaptureDevices() :
     46           NULL;
     47 
     48   const content::MediaStreamDevices* video_devices =
     49       request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ?
     50           &MediaCaptureDevicesDispatcher::GetInstance()
     51               ->GetVideoCaptureDevices() :
     52           NULL;
     53 
     54   // Check if we're being asked for audio and/or video and that either of those
     55   // lists is empty.  If they are, we do not have devices available for the
     56   // request.
     57   // TODO(tommi): It's kind of strange to have this here since if we fail this
     58   // test, there'll be a UI shown that indicates to the user that access to
     59   // non-existing audio/video devices has been denied.  The user won't have
     60   // any way to change that but there will be a UI shown which indicates that
     61   // access is blocked.
     62   if ((audio_devices != NULL && audio_devices->empty()) ||
     63       (video_devices != NULL && video_devices->empty())) {
     64     return false;
     65   }
     66 
     67   // Note: we check requested_[audio|video]_device_id before dereferencing
     68   // [audio|video]_devices.  If the requested device id is non-empty, then
     69   // the corresponding device list must not be NULL.
     70 
     71   if (!request.requested_audio_device_id.empty() &&
     72       !audio_devices->FindById(request.requested_audio_device_id)) {
     73     return false;
     74   }
     75 
     76   if (!request.requested_video_device_id.empty() &&
     77       !video_devices->FindById(request.requested_video_device_id)) {
     78     return false;
     79   }
     80 
     81   return true;
     82 }
     83 
     84 bool IsInKioskMode() {
     85   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
     86     return true;
     87 
     88 #if defined(OS_CHROMEOS)
     89   const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
     90   return user_manager && user_manager->IsLoggedInAsKioskApp();
     91 #else
     92   return false;
     93 #endif
     94 }
     95 
     96 enum DevicePermissionActions {
     97   kAllowHttps = 0,
     98   kAllowHttp,
     99   kDeny,
    100   kCancel,
    101   kPermissionActionsMax  // Must always be last!
    102 };
    103 
    104 }  // namespace
    105 
    106 MediaStreamDevicesController::MediaStreamTypeSettings::MediaStreamTypeSettings(
    107     Permission permission, const std::string& requested_device_id):
    108     permission(permission), requested_device_id(requested_device_id) {}
    109 
    110 MediaStreamDevicesController::MediaStreamTypeSettings::
    111     MediaStreamTypeSettings(): permission(MEDIA_NONE) {}
    112 
    113 MediaStreamDevicesController::MediaStreamTypeSettings::
    114     ~MediaStreamTypeSettings() {}
    115 
    116 MediaStreamDevicesController::MediaStreamDevicesController(
    117     content::WebContents* web_contents,
    118     const content::MediaStreamRequest& request,
    119     const content::MediaResponseCallback& callback)
    120     : web_contents_(web_contents),
    121       request_(request),
    122       callback_(callback) {
    123   profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
    124   content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
    125 
    126   // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
    127   // and microphone to avoid popping two infobars.
    128   // We start with setting the requested media type to allowed or blocked
    129   // depending on the policy. If not blocked by policy it may be blocked later
    130   // in the two remaining filtering steps (by user setting or by user when
    131   // clicking the infobar).
    132   // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE
    133   // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed.
    134   if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
    135       request.request_type == content::MEDIA_OPEN_DEVICE) {
    136     if (GetDevicePolicy(prefs::kAudioCaptureAllowed,
    137                         prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
    138       request_permissions_.insert(std::make_pair(
    139           content::MEDIA_DEVICE_AUDIO_CAPTURE,
    140           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
    141                                   request.requested_audio_device_id)));
    142     } else {
    143       request_permissions_.insert(std::make_pair(
    144           content::MEDIA_DEVICE_AUDIO_CAPTURE,
    145           MediaStreamTypeSettings(MEDIA_ALLOWED,
    146                                   request.requested_audio_device_id)));
    147     }
    148   }
    149   if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
    150       request.request_type == content::MEDIA_OPEN_DEVICE) {
    151     if (GetDevicePolicy(prefs::kVideoCaptureAllowed,
    152                         prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
    153       request_permissions_.insert(std::make_pair(
    154           content::MEDIA_DEVICE_VIDEO_CAPTURE,
    155           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
    156                                   request.requested_video_device_id)));
    157     } else {
    158       request_permissions_.insert(std::make_pair(
    159           content::MEDIA_DEVICE_VIDEO_CAPTURE,
    160           MediaStreamTypeSettings(MEDIA_ALLOWED,
    161                                   request.requested_video_device_id)));
    162     }
    163   }
    164 }
    165 
    166 MediaStreamDevicesController::~MediaStreamDevicesController() {
    167   if (!callback_.is_null()) {
    168     callback_.Run(content::MediaStreamDevices(),
    169                   content::MEDIA_DEVICE_INVALID_STATE,
    170                   scoped_ptr<content::MediaStreamUI>());
    171   }
    172 }
    173 
    174 // static
    175 void MediaStreamDevicesController::RegisterProfilePrefs(
    176     user_prefs::PrefRegistrySyncable* prefs) {
    177   prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed,
    178                              true,
    179                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    180   prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed,
    181                              true,
    182                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    183   prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls,
    184                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    185   prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls,
    186                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    187 }
    188 
    189 // TODO(gbillock): rename? doesn't actually dismiss. More of a 'check profile
    190 // and system for compatibility' thing.
    191 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() {
    192   // Tab capture is allowed for extensions only and infobar is not shown for
    193   // extensions.
    194   if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
    195       request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
    196     Deny(false, content::MEDIA_DEVICE_INVALID_STATE);
    197     return true;
    198   }
    199 
    200   // Deny the request if the security origin is empty, this happens with
    201   // file access without |--allow-file-access-from-files| flag.
    202   if (request_.security_origin.is_empty()) {
    203     Deny(false, content::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
    204     return true;
    205   }
    206 
    207   // Deny the request if there is no device attached to the OS of the
    208   // requested type. If both audio and video is requested, both types must be
    209   // available.
    210   if (!HasAvailableDevicesForRequest(request_)) {
    211     Deny(false, content::MEDIA_DEVICE_NO_HARDWARE);
    212     return true;
    213   }
    214 
    215   // Check if any allow exception has been made for this request.
    216   if (IsRequestAllowedByDefault()) {
    217     Accept(false);
    218     return true;
    219   }
    220 
    221   // Filter any parts of the request that have been blocked by default and deny
    222   // it if nothing is left to accept.
    223   if (FilterBlockedByDefaultDevices() == 0) {
    224     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
    225     return true;
    226   }
    227 
    228   // Check if the media default setting is set to block.
    229   if (IsDefaultMediaAccessBlocked()) {
    230     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
    231     return true;
    232   }
    233 
    234   // Show the infobar.
    235   return false;
    236 }
    237 
    238 bool MediaStreamDevicesController::HasAudio() const {
    239   return IsDeviceAudioCaptureRequestedAndAllowed();
    240 }
    241 
    242 bool MediaStreamDevicesController::HasVideo() const {
    243   return IsDeviceVideoCaptureRequestedAndAllowed();
    244 }
    245 
    246 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const {
    247   return request_.security_origin.spec();
    248 }
    249 
    250 void MediaStreamDevicesController::Accept(bool update_content_setting) {
    251   NotifyUIRequestAccepted();
    252 
    253   // Get the default devices for the request.
    254   content::MediaStreamDevices devices;
    255   bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed();
    256   bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed();
    257   if (audio_allowed || video_allowed) {
    258     switch (request_.request_type) {
    259       case content::MEDIA_OPEN_DEVICE: {
    260         const content::MediaStreamDevice* device = NULL;
    261         // For open device request, when requested device_id is empty, pick
    262         // the first available of the given type. If requested device_id is
    263         // not empty, return the desired device if it's available. Otherwise,
    264         // return no device.
    265         if (audio_allowed &&
    266             request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
    267           if (!request_.requested_audio_device_id.empty()) {
    268             device = MediaCaptureDevicesDispatcher::GetInstance()->
    269                 GetRequestedAudioDevice(request_.requested_audio_device_id);
    270           } else {
    271             device = MediaCaptureDevicesDispatcher::GetInstance()->
    272                 GetFirstAvailableAudioDevice();
    273           }
    274         } else if (video_allowed &&
    275             request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
    276           // Pepper API opens only one device at a time.
    277           if (!request_.requested_video_device_id.empty()) {
    278             device = MediaCaptureDevicesDispatcher::GetInstance()->
    279                 GetRequestedVideoDevice(request_.requested_video_device_id);
    280           } else {
    281             device = MediaCaptureDevicesDispatcher::GetInstance()->
    282                 GetFirstAvailableVideoDevice();
    283           }
    284         }
    285         if (device)
    286           devices.push_back(*device);
    287         break;
    288       }
    289       case content::MEDIA_GENERATE_STREAM: {
    290         bool get_default_audio_device = audio_allowed;
    291         bool get_default_video_device = video_allowed;
    292 
    293         // Get the exact audio or video device if an id is specified.
    294         if (audio_allowed && !request_.requested_audio_device_id.empty()) {
    295           const content::MediaStreamDevice* audio_device =
    296               MediaCaptureDevicesDispatcher::GetInstance()->
    297                   GetRequestedAudioDevice(request_.requested_audio_device_id);
    298           if (audio_device) {
    299             devices.push_back(*audio_device);
    300             get_default_audio_device = false;
    301           }
    302         }
    303         if (video_allowed && !request_.requested_video_device_id.empty()) {
    304           const content::MediaStreamDevice* video_device =
    305               MediaCaptureDevicesDispatcher::GetInstance()->
    306                   GetRequestedVideoDevice(request_.requested_video_device_id);
    307           if (video_device) {
    308             devices.push_back(*video_device);
    309             get_default_video_device = false;
    310           }
    311         }
    312 
    313         // If either or both audio and video devices were requested but not
    314         // specified by id, get the default devices.
    315         if (get_default_audio_device || get_default_video_device) {
    316           MediaCaptureDevicesDispatcher::GetInstance()->
    317               GetDefaultDevicesForProfile(profile_,
    318                                           get_default_audio_device,
    319                                           get_default_video_device,
    320                                           &devices);
    321         }
    322         break;
    323       }
    324       case content::MEDIA_DEVICE_ACCESS: {
    325         // Get the default devices for the request.
    326         MediaCaptureDevicesDispatcher::GetInstance()->
    327             GetDefaultDevicesForProfile(profile_,
    328                                         audio_allowed,
    329                                         video_allowed,
    330                                         &devices);
    331         break;
    332       }
    333       case content::MEDIA_ENUMERATE_DEVICES: {
    334         // Do nothing.
    335         NOTREACHED();
    336         break;
    337       }
    338     }  // switch
    339 
    340     // TODO(raymes): We currently set the content permission for non-https
    341     // websites for Pepper requests as well. This is temporary and should be
    342     // removed.
    343     if (update_content_setting) {
    344       if ((IsSchemeSecure() && !devices.empty()) ||
    345           request_.request_type == content::MEDIA_OPEN_DEVICE) {
    346         SetPermission(true);
    347       }
    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 MediaStreamDevicesController::DevicePolicy
    446 MediaStreamDevicesController::GetDevicePolicy(
    447     const char* policy_name,
    448     const char* whitelist_policy_name) const {
    449   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    450 
    451   // If the security origin policy matches a value in the whitelist, allow it.
    452   // Otherwise, check the |policy_name| master switch for the default behavior.
    453 
    454   PrefService* prefs = profile_->GetPrefs();
    455 
    456   // TODO(tommi): Remove the kiosk mode check when the whitelist below
    457   // is visible in the media exceptions UI.
    458   // See discussion here: https://codereview.chromium.org/15738004/
    459   if (IsInKioskMode()) {
    460     const base::ListValue* list = prefs->GetList(whitelist_policy_name);
    461     std::string value;
    462     for (size_t i = 0; i < list->GetSize(); ++i) {
    463       if (list->GetString(i, &value)) {
    464         ContentSettingsPattern pattern =
    465             ContentSettingsPattern::FromString(value);
    466         if (pattern == ContentSettingsPattern::Wildcard()) {
    467           DLOG(WARNING) << "Ignoring wildcard URL pattern: " << value;
    468           continue;
    469         }
    470         DLOG_IF(ERROR, !pattern.IsValid()) << "Invalid URL pattern: " << value;
    471         if (pattern.IsValid() && pattern.Matches(request_.security_origin))
    472           return ALWAYS_ALLOW;
    473       }
    474     }
    475   }
    476 
    477   // If a match was not found, check if audio capture is otherwise disallowed
    478   // or if the user should be prompted.  Setting the policy value to "true"
    479   // is equal to not setting it at all, so from hereon out, we will return
    480   // either POLICY_NOT_SET (prompt) or ALWAYS_DENY (no prompt, no access).
    481   if (!prefs->GetBoolean(policy_name))
    482     return ALWAYS_DENY;
    483 
    484   return POLICY_NOT_SET;
    485 }
    486 
    487 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const {
    488   // The request from internal objects like chrome://URLs is always allowed.
    489   if (ShouldAlwaysAllowOrigin())
    490     return true;
    491 
    492   struct {
    493     bool has_capability;
    494     const char* policy_name;
    495     const char* list_policy_name;
    496     ContentSettingsType settings_type;
    497   } device_checks[] = {
    498     { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed,
    499       prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC },
    500     { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed,
    501       prefs::kVideoCaptureAllowedUrls,
    502       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA },
    503   };
    504 
    505   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) {
    506     if (!device_checks[i].has_capability)
    507       continue;
    508 
    509     DevicePolicy policy = GetDevicePolicy(device_checks[i].policy_name,
    510                                           device_checks[i].list_policy_name);
    511 
    512     if (policy == ALWAYS_DENY)
    513       return false;
    514 
    515     if (policy == POLICY_NOT_SET) {
    516       // Only load content settings from secure origins unless it is a
    517       // content::MEDIA_OPEN_DEVICE (Pepper) request.
    518       if (!IsSchemeSecure() &&
    519           request_.request_type != content::MEDIA_OPEN_DEVICE) {
    520         return false;
    521       }
    522       if (profile_->GetHostContentSettingsMap()->GetContentSetting(
    523               request_.security_origin, request_.security_origin,
    524               device_checks[i].settings_type, NO_RESOURCE_IDENTIFIER) !=
    525               CONTENT_SETTING_ALLOW) {
    526         return false;
    527       }
    528     }
    529     // If we get here, then either policy is set to ALWAYS_ALLOW or the content
    530     // settings allow the request by default.
    531   }
    532 
    533   return true;
    534 }
    535 
    536 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() {
    537   int requested_devices = 0;
    538 
    539   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
    540     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
    541         request_.security_origin,
    542         request_.security_origin,
    543         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
    544         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
    545       request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
    546           MEDIA_BLOCKED_BY_USER_SETTING;
    547     } else {
    548       ++requested_devices;
    549     }
    550   }
    551 
    552   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
    553     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
    554         request_.security_origin,
    555         request_.security_origin,
    556         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
    557         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
    558       request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
    559           MEDIA_BLOCKED_BY_USER_SETTING;
    560     } else {
    561       ++requested_devices;
    562     }
    563   }
    564 
    565   return requested_devices;
    566 }
    567 
    568 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const {
    569   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    570   // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
    571   // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
    572   // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
    573   ContentSetting current_setting =
    574       profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
    575           CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
    576   return (current_setting == CONTENT_SETTING_BLOCK);
    577 }
    578 
    579 bool MediaStreamDevicesController::IsSchemeSecure() const {
    580   return request_.security_origin.SchemeIsSecure() ||
    581       request_.security_origin.SchemeIs(extensions::kExtensionScheme);
    582 }
    583 
    584 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() const {
    585   // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
    586   // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
    587   // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
    588   return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent(
    589       request_.security_origin, request_.security_origin,
    590       CONTENT_SETTINGS_TYPE_MEDIASTREAM);
    591 }
    592 
    593 void MediaStreamDevicesController::SetPermission(bool allowed) const {
    594   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    595   ContentSettingsPattern primary_pattern =
    596       ContentSettingsPattern::FromURLNoWildcard(request_.security_origin);
    597   // Check the pattern is valid or not. When the request is from a file access,
    598   // no exception will be made.
    599   if (!primary_pattern.IsValid())
    600     return;
    601 
    602   ContentSetting content_setting = allowed ?
    603       CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
    604   if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) !=
    605       request_permissions_.end()) {
    606     profile_->GetHostContentSettingsMap()->SetContentSetting(
    607         primary_pattern,
    608         ContentSettingsPattern::Wildcard(),
    609         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
    610         std::string(),
    611         content_setting);
    612   }
    613   if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) !=
    614       request_permissions_.end()) {
    615     profile_->GetHostContentSettingsMap()->SetContentSetting(
    616         primary_pattern,
    617         ContentSettingsPattern::Wildcard(),
    618         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
    619         std::string(),
    620         content_setting);
    621   }
    622 }
    623 
    624 void MediaStreamDevicesController::NotifyUIRequestAccepted() const {
    625   if (!content_settings_)
    626     return;
    627 
    628   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
    629                                                 request_permissions_);
    630 }
    631 
    632 void MediaStreamDevicesController::NotifyUIRequestDenied() {
    633   if (!content_settings_)
    634     return;
    635 
    636   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
    637     request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
    638         MEDIA_BLOCKED_BY_USER;
    639   }
    640   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
    641     request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
    642         MEDIA_BLOCKED_BY_USER;
    643   }
    644 
    645   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
    646                                                 request_permissions_);
    647 }
    648 
    649 bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed()
    650     const {
    651   MediaStreamTypeSettingsMap::const_iterator it =
    652       request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
    653   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
    654           it->second.permission == MEDIA_ALLOWED);
    655 }
    656 
    657 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed()
    658     const {
    659   MediaStreamTypeSettingsMap::const_iterator it =
    660       request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
    661   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
    662           it->second.permission == MEDIA_ALLOWED);
    663 }
    664 
    665 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const {
    666 #if defined(OS_ANDROID)
    667   // Don't approve device requests if the tab was hidden.
    668   // TODO(qinmin): Add a test for this. http://crbug.com/396869.
    669   return web_contents_->GetRenderWidgetHostView()->IsShowing();
    670 #endif
    671   return true;
    672 }
    673