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.
5 #include "chrome/browser/media/media_stream_devices_controller.h"
7 #include "base/command_line.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/values.h"
10 #include "chrome/browser/content_settings/content_settings_provider.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/prefs/scoped_user_pref_update.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/content_settings.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/user_prefs/pref_registry_syncable.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/media_stream_request.h"
24 using content::BrowserThread
;
28 bool HasAnyAvailableDevice() {
29 const content::MediaStreamDevices
& audio_devices
=
30 MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
31 const content::MediaStreamDevices
& video_devices
=
32 MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();
34 return !audio_devices
.empty() || !video_devices
.empty();
39 MediaStreamDevicesController::MediaStreamDevicesController(
41 TabSpecificContentSettings
* content_settings
,
42 const content::MediaStreamRequest
& request
,
43 const content::MediaResponseCallback
& callback
)
45 content_settings_(content_settings
),
48 microphone_requested_(
49 request
.audio_type
== content::MEDIA_DEVICE_AUDIO_CAPTURE
),
51 request
.video_type
== content::MEDIA_DEVICE_VIDEO_CAPTURE
) {
52 // Don't call GetDevicePolicy from the initializer list since the
53 // implementation depends on member variables.
54 if (microphone_requested_
&&
55 GetDevicePolicy(prefs::kAudioCaptureAllowed
) == ALWAYS_DENY
) {
56 microphone_requested_
= false;
59 if (webcam_requested_
&&
60 GetDevicePolicy(prefs::kVideoCaptureAllowed
) == ALWAYS_DENY
) {
61 webcam_requested_
= false;
65 MediaStreamDevicesController::~MediaStreamDevicesController() {}
68 void MediaStreamDevicesController::RegisterUserPrefs(
69 PrefRegistrySyncable
* prefs
) {
70 prefs
->RegisterBooleanPref(prefs::kVideoCaptureAllowed
,
72 PrefRegistrySyncable::UNSYNCABLE_PREF
);
73 prefs
->RegisterBooleanPref(prefs::kAudioCaptureAllowed
,
75 PrefRegistrySyncable::UNSYNCABLE_PREF
);
79 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() {
80 // If this is a no UI check for policies only go straight to accept - policy
81 // check will be done automatically on the way.
82 if (request_
.request_type
== content::MEDIA_OPEN_DEVICE
) {
87 // Tab capture is allowed for extensions only and infobar is not shown for
89 if (request_
.audio_type
== content::MEDIA_TAB_AUDIO_CAPTURE
||
90 request_
.video_type
== content::MEDIA_TAB_VIDEO_CAPTURE
) {
95 // Deny the request if the security origin is empty, this happens with
96 // file access without |--allow-file-access-from-files| flag.
97 if (request_
.security_origin
.is_empty()) {
102 // Deny the request if there is no device attached to the OS.
103 if (!HasAnyAvailableDevice()) {
108 // Check if any allow exception has been made for this request.
109 if (IsRequestAllowedByDefault()) {
114 // Check if any block exception has been made for this request.
115 if (IsRequestBlockedByDefault()) {
120 // Check if the media default setting is set to block.
121 if (IsDefaultMediaAccessBlocked()) {
130 const std::string
& MediaStreamDevicesController::GetSecurityOriginSpec() const {
131 return request_
.security_origin
.spec();
134 void MediaStreamDevicesController::Accept(bool update_content_setting
) {
135 if (content_settings_
)
136 content_settings_
->OnMediaStreamAllowed();
138 // Get the default devices for the request.
139 content::MediaStreamDevices devices
;
140 if (microphone_requested_
|| webcam_requested_
) {
141 switch (request_
.request_type
) {
142 case content::MEDIA_OPEN_DEVICE
:
143 // For open device request pick the desired device or fall back to the
144 // first available of the given type.
145 MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
146 request_
.requested_device_id
,
147 microphone_requested_
,
151 case content::MEDIA_DEVICE_ACCESS
:
152 case content::MEDIA_GENERATE_STREAM
:
153 case content::MEDIA_ENUMERATE_DEVICES
:
154 // Get the default devices for the request.
155 MediaCaptureDevicesDispatcher::GetInstance()->
156 GetDefaultDevicesForProfile(profile_
,
157 microphone_requested_
,
163 if (update_content_setting
&& IsSchemeSecure() && !devices
.empty())
167 callback_
.Run(devices
);
170 void MediaStreamDevicesController::Deny(bool update_content_setting
) {
171 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
172 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
173 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
174 if (content_settings_
) {
175 content_settings_
->OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM
,
179 if (update_content_setting
)
180 SetPermission(false);
182 callback_
.Run(content::MediaStreamDevices());
185 MediaStreamDevicesController::DevicePolicy
186 MediaStreamDevicesController::GetDevicePolicy(const char* policy_name
) const {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
189 PrefService
* prefs
= profile_
->GetPrefs();
190 if (!prefs
->IsManagedPreference(policy_name
))
191 return POLICY_NOT_SET
;
193 return prefs
->GetBoolean(policy_name
) ? ALWAYS_ALLOW
: ALWAYS_DENY
;
196 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const {
197 // The request from internal objects like chrome://URLs is always allowed.
198 if (ShouldAlwaysAllowOrigin())
203 const char* policy_name
;
204 ContentSettingsType settings_type
;
205 } device_checks
[] = {
206 { microphone_requested_
, prefs::kAudioCaptureAllowed
,
207 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
},
208 { webcam_requested_
, prefs::kVideoCaptureAllowed
,
209 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
},
212 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(device_checks
); ++i
) {
213 if (!device_checks
[i
].has_capability
)
216 DevicePolicy policy
= GetDevicePolicy(device_checks
[i
].policy_name
);
217 if (policy
== ALWAYS_DENY
||
218 (policy
== POLICY_NOT_SET
&&
219 profile_
->GetHostContentSettingsMap()->GetContentSetting(
220 request_
.security_origin
, request_
.security_origin
,
221 device_checks
[i
].settings_type
, NO_RESOURCE_IDENTIFIER
) !=
222 CONTENT_SETTING_ALLOW
)) {
225 // If we get here, then either policy is set to ALWAYS_ALLOW or the content
226 // settings allow the request by default.
232 bool MediaStreamDevicesController::IsRequestBlockedByDefault() const {
233 if (microphone_requested_
&&
234 profile_
->GetHostContentSettingsMap()->GetContentSetting(
235 request_
.security_origin
,
236 request_
.security_origin
,
237 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
,
238 NO_RESOURCE_IDENTIFIER
) != CONTENT_SETTING_BLOCK
) {
242 if (webcam_requested_
&&
243 profile_
->GetHostContentSettingsMap()->GetContentSetting(
244 request_
.security_origin
,
245 request_
.security_origin
,
246 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
,
247 NO_RESOURCE_IDENTIFIER
) != CONTENT_SETTING_BLOCK
) {
254 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
256 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
257 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
258 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
259 ContentSetting current_setting
=
260 profile_
->GetHostContentSettingsMap()->GetDefaultContentSetting(
261 CONTENT_SETTINGS_TYPE_MEDIASTREAM
, NULL
);
262 return (current_setting
== CONTENT_SETTING_BLOCK
);
265 bool MediaStreamDevicesController::IsSchemeSecure() const {
266 return (request_
.security_origin
.SchemeIsSecure());
269 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() const {
270 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
271 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
272 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
273 return profile_
->GetHostContentSettingsMap()->ShouldAllowAllContent(
274 request_
.security_origin
, request_
.security_origin
,
275 CONTENT_SETTINGS_TYPE_MEDIASTREAM
);
278 void MediaStreamDevicesController::SetPermission(bool allowed
) const {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
280 #if defined(OS_ANDROID)
281 // We do not support sticky operations on Android yet.
284 ContentSettingsPattern primary_pattern
=
285 ContentSettingsPattern::FromURLNoWildcard(request_
.security_origin
);
286 // Check the pattern is valid or not. When the request is from a file access,
287 // no exception will be made.
288 if (!primary_pattern
.IsValid())
291 ContentSetting content_setting
= allowed
?
292 CONTENT_SETTING_ALLOW
: CONTENT_SETTING_BLOCK
;
293 if (microphone_requested_
) {
294 profile_
->GetHostContentSettingsMap()->SetContentSetting(
296 ContentSettingsPattern::Wildcard(),
297 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
,
301 if (webcam_requested_
) {
302 profile_
->GetHostContentSettingsMap()->SetContentSetting(
304 ContentSettingsPattern::Wildcard(),
305 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
,