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/prefs/pref_service.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/values.h"
11 #include "chrome/browser/content_settings/content_settings_provider.h"
12 #include "chrome/browser/content_settings/host_content_settings_map.h"
13 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
14 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
15 #include "chrome/browser/media/media_stream_capture_indicator.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/content_settings.h"
20 #include "chrome/common/content_settings_pattern.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/user_prefs/pref_registry_syncable.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/common/media_stream_request.h"
25 #include "extensions/common/constants.h"
26
27 #if defined(OS_CHROMEOS)
28 #include "chrome/browser/chromeos/login/user_manager.h"
29 #endif
30
31 using content::BrowserThread;
32
33 namespace {
34
HasAnyAvailableDevice()35 bool HasAnyAvailableDevice() {
36 const content::MediaStreamDevices& audio_devices =
37 MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
38 const content::MediaStreamDevices& video_devices =
39 MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();
40
41 return !audio_devices.empty() || !video_devices.empty();
42 }
43
IsInKioskMode()44 bool IsInKioskMode() {
45 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
46 return true;
47
48 #if defined(OS_CHROMEOS)
49 const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
50 return user_manager && user_manager->IsLoggedInAsKioskApp();
51 #else
52 return false;
53 #endif
54 }
55
56 } // namespace
57
MediaStreamTypeSettings(Permission permission,const std::string & requested_device_id)58 MediaStreamDevicesController::MediaStreamTypeSettings::MediaStreamTypeSettings(
59 Permission permission, const std::string& requested_device_id):
60 permission(permission), requested_device_id(requested_device_id) {}
61
62 MediaStreamDevicesController::MediaStreamTypeSettings::
MediaStreamTypeSettings()63 MediaStreamTypeSettings(): permission(MEDIA_NONE) {}
64
65 MediaStreamDevicesController::MediaStreamTypeSettings::
~MediaStreamTypeSettings()66 ~MediaStreamTypeSettings() {}
67
MediaStreamDevicesController(content::WebContents * web_contents,const content::MediaStreamRequest & request,const content::MediaResponseCallback & callback)68 MediaStreamDevicesController::MediaStreamDevicesController(
69 content::WebContents* web_contents,
70 const content::MediaStreamRequest& request,
71 const content::MediaResponseCallback& callback)
72 : web_contents_(web_contents),
73 request_(request),
74 callback_(callback) {
75 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
76 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
77
78 // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
79 // and microphone to avoid popping two infobars.
80 // We start with setting the requested media type to allowed or blocked
81 // depending on the policy. If not blocked by policy it may be blocked later
82 // in the two remaining filtering steps (by user setting or by user when
83 // clicking the infobar).
84 // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE
85 // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed.
86 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
87 request.request_type == content::MEDIA_OPEN_DEVICE) {
88 if (GetDevicePolicy(prefs::kAudioCaptureAllowed,
89 prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
90 request_permissions_.insert(std::make_pair(
91 content::MEDIA_DEVICE_AUDIO_CAPTURE,
92 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
93 request.requested_audio_device_id)));
94 } else {
95 request_permissions_.insert(std::make_pair(
96 content::MEDIA_DEVICE_AUDIO_CAPTURE,
97 MediaStreamTypeSettings(MEDIA_ALLOWED,
98 request.requested_audio_device_id)));
99 }
100 }
101 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
102 request.request_type == content::MEDIA_OPEN_DEVICE) {
103 if (GetDevicePolicy(prefs::kVideoCaptureAllowed,
104 prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
105 request_permissions_.insert(std::make_pair(
106 content::MEDIA_DEVICE_VIDEO_CAPTURE,
107 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
108 request.requested_video_device_id)));
109 } else {
110 request_permissions_.insert(std::make_pair(
111 content::MEDIA_DEVICE_VIDEO_CAPTURE,
112 MediaStreamTypeSettings(MEDIA_ALLOWED,
113 request.requested_video_device_id)));
114 }
115 }
116 }
117
~MediaStreamDevicesController()118 MediaStreamDevicesController::~MediaStreamDevicesController() {
119 if (!callback_.is_null()) {
120 callback_.Run(content::MediaStreamDevices(),
121 scoped_ptr<content::MediaStreamUI>());
122 }
123 }
124
125 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * prefs)126 void MediaStreamDevicesController::RegisterProfilePrefs(
127 user_prefs::PrefRegistrySyncable* prefs) {
128 prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed,
129 true,
130 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
131 prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed,
132 true,
133 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
134 prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls,
135 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
136 prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls,
137 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
138 }
139
140
DismissInfoBarAndTakeActionOnSettings()141 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() {
142 // Tab capture is allowed for extensions only and infobar is not shown for
143 // extensions.
144 if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
145 request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
146 Deny(false);
147 return true;
148 }
149
150 // Deny the request if the security origin is empty, this happens with
151 // file access without |--allow-file-access-from-files| flag.
152 if (request_.security_origin.is_empty()) {
153 Deny(false);
154 return true;
155 }
156
157 // Deny the request if there is no device attached to the OS.
158 if (!HasAnyAvailableDevice()) {
159 Deny(false);
160 return true;
161 }
162
163 // Check if any allow exception has been made for this request.
164 if (IsRequestAllowedByDefault()) {
165 Accept(false);
166 return true;
167 }
168
169 // Filter any parts of the request that have been blocked by default and deny
170 // it if nothing is left to accept.
171 if (FilterBlockedByDefaultDevices() == 0) {
172 Deny(false);
173 return true;
174 }
175
176 // Check if the media default setting is set to block.
177 if (IsDefaultMediaAccessBlocked()) {
178 Deny(false);
179 return true;
180 }
181
182 if (request_.request_type == content::MEDIA_OPEN_DEVICE) {
183 bool no_matched_audio_device =
184 (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
185 !request_.requested_audio_device_id.empty() &&
186 MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedAudioDevice(
187 request_.requested_audio_device_id) == NULL);
188 bool no_matched_video_device =
189 (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
190 !request_.requested_video_device_id.empty() &&
191 MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedVideoDevice(
192 request_.requested_video_device_id) == NULL);
193 if (no_matched_audio_device || no_matched_video_device) {
194 Deny(false);
195 return true;
196 }
197 }
198
199 // Show the infobar.
200 return false;
201 }
202
HasAudio() const203 bool MediaStreamDevicesController::HasAudio() const {
204 return IsDeviceAudioCaptureRequestedAndAllowed();
205 }
206
HasVideo() const207 bool MediaStreamDevicesController::HasVideo() const {
208 return IsDeviceVideoCaptureRequestedAndAllowed();
209 }
210
GetSecurityOriginSpec() const211 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const {
212 return request_.security_origin.spec();
213 }
214
Accept(bool update_content_setting)215 void MediaStreamDevicesController::Accept(bool update_content_setting) {
216 NotifyUIRequestAccepted();
217
218 // Get the default devices for the request.
219 content::MediaStreamDevices devices;
220 bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed();
221 bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed();
222 if (audio_allowed || video_allowed) {
223 switch (request_.request_type) {
224 case content::MEDIA_OPEN_DEVICE: {
225 const content::MediaStreamDevice* device = NULL;
226 // For open device request, when requested device_id is empty, pick
227 // the first available of the given type. If requested device_id is
228 // not empty, return the desired device if it's available. Otherwise,
229 // return no device.
230 if (audio_allowed &&
231 request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
232 if (!request_.requested_audio_device_id.empty()) {
233 device = MediaCaptureDevicesDispatcher::GetInstance()->
234 GetRequestedAudioDevice(request_.requested_audio_device_id);
235 } else {
236 device = MediaCaptureDevicesDispatcher::GetInstance()->
237 GetFirstAvailableAudioDevice();
238 }
239 } else if (video_allowed &&
240 request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
241 // Pepper API opens only one device at a time.
242 if (!request_.requested_video_device_id.empty()) {
243 device = MediaCaptureDevicesDispatcher::GetInstance()->
244 GetRequestedVideoDevice(request_.requested_video_device_id);
245 } else {
246 device = MediaCaptureDevicesDispatcher::GetInstance()->
247 GetFirstAvailableVideoDevice();
248 }
249 }
250 if (device)
251 devices.push_back(*device);
252 break;
253 }
254 case content::MEDIA_GENERATE_STREAM: {
255 bool get_default_audio_device = audio_allowed;
256 bool get_default_video_device = video_allowed;
257
258 // Get the exact audio or video device if an id is specified.
259 if (audio_allowed && !request_.requested_audio_device_id.empty()) {
260 const content::MediaStreamDevice* audio_device =
261 MediaCaptureDevicesDispatcher::GetInstance()->
262 GetRequestedAudioDevice(request_.requested_audio_device_id);
263 if (audio_device) {
264 devices.push_back(*audio_device);
265 get_default_audio_device = false;
266 }
267 }
268 if (video_allowed && !request_.requested_video_device_id.empty()) {
269 const content::MediaStreamDevice* video_device =
270 MediaCaptureDevicesDispatcher::GetInstance()->
271 GetRequestedVideoDevice(request_.requested_video_device_id);
272 if (video_device) {
273 devices.push_back(*video_device);
274 get_default_video_device = false;
275 }
276 }
277
278 // If either or both audio and video devices were requested but not
279 // specified by id, get the default devices.
280 if (get_default_audio_device || get_default_video_device) {
281 MediaCaptureDevicesDispatcher::GetInstance()->
282 GetDefaultDevicesForProfile(profile_,
283 get_default_audio_device,
284 get_default_video_device,
285 &devices);
286 }
287 break;
288 }
289 case content::MEDIA_DEVICE_ACCESS: {
290 // Get the default devices for the request.
291 MediaCaptureDevicesDispatcher::GetInstance()->
292 GetDefaultDevicesForProfile(profile_,
293 audio_allowed,
294 video_allowed,
295 &devices);
296 break;
297 }
298 case content::MEDIA_ENUMERATE_DEVICES: {
299 // Do nothing.
300 NOTREACHED();
301 break;
302 }
303 } // switch
304
305 // TODO(raymes): We currently set the content permission for non-https
306 // websites for Pepper requests as well. This is temporary and should be
307 // removed.
308 if (update_content_setting) {
309 if ((IsSchemeSecure() && !devices.empty()) ||
310 request_.request_type == content::MEDIA_OPEN_DEVICE) {
311 SetPermission(true);
312 }
313 }
314 }
315
316 scoped_ptr<content::MediaStreamUI> ui;
317 if (!devices.empty()) {
318 ui = MediaCaptureDevicesDispatcher::GetInstance()->
319 GetMediaStreamCaptureIndicator()->RegisterMediaStream(
320 web_contents_, devices);
321 }
322 content::MediaResponseCallback cb = callback_;
323 callback_.Reset();
324 cb.Run(devices, ui.Pass());
325 }
326
Deny(bool update_content_setting)327 void MediaStreamDevicesController::Deny(bool update_content_setting) {
328 NotifyUIRequestDenied();
329
330 if (update_content_setting)
331 SetPermission(false);
332
333 content::MediaResponseCallback cb = callback_;
334 callback_.Reset();
335 cb.Run(content::MediaStreamDevices(), scoped_ptr<content::MediaStreamUI>());
336 }
337
338 MediaStreamDevicesController::DevicePolicy
GetDevicePolicy(const char * policy_name,const char * whitelist_policy_name) const339 MediaStreamDevicesController::GetDevicePolicy(
340 const char* policy_name,
341 const char* whitelist_policy_name) const {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343
344 // If the security origin policy matches a value in the whitelist, allow it.
345 // Otherwise, check the |policy_name| master switch for the default behavior.
346
347 PrefService* prefs = profile_->GetPrefs();
348
349 // TODO(tommi): Remove the kiosk mode check when the whitelist below
350 // is visible in the media exceptions UI.
351 // See discussion here: https://codereview.chromium.org/15738004/
352 if (IsInKioskMode()) {
353 const base::ListValue* list = prefs->GetList(whitelist_policy_name);
354 std::string value;
355 for (size_t i = 0; i < list->GetSize(); ++i) {
356 if (list->GetString(i, &value)) {
357 ContentSettingsPattern pattern =
358 ContentSettingsPattern::FromString(value);
359 if (pattern == ContentSettingsPattern::Wildcard()) {
360 DLOG(WARNING) << "Ignoring wildcard URL pattern: " << value;
361 continue;
362 }
363 DLOG_IF(ERROR, !pattern.IsValid()) << "Invalid URL pattern: " << value;
364 if (pattern.IsValid() && pattern.Matches(request_.security_origin))
365 return ALWAYS_ALLOW;
366 }
367 }
368 }
369
370 // If a match was not found, check if audio capture is otherwise disallowed
371 // or if the user should be prompted. Setting the policy value to "true"
372 // is equal to not setting it at all, so from hereon out, we will return
373 // either POLICY_NOT_SET (prompt) or ALWAYS_DENY (no prompt, no access).
374 if (!prefs->GetBoolean(policy_name))
375 return ALWAYS_DENY;
376
377 return POLICY_NOT_SET;
378 }
379
IsRequestAllowedByDefault() const380 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const {
381 // The request from internal objects like chrome://URLs is always allowed.
382 if (ShouldAlwaysAllowOrigin())
383 return true;
384
385 struct {
386 bool has_capability;
387 const char* policy_name;
388 const char* list_policy_name;
389 ContentSettingsType settings_type;
390 } device_checks[] = {
391 { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed,
392 prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC },
393 { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed,
394 prefs::kVideoCaptureAllowedUrls,
395 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA },
396 };
397
398 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) {
399 if (!device_checks[i].has_capability)
400 continue;
401
402 DevicePolicy policy = GetDevicePolicy(device_checks[i].policy_name,
403 device_checks[i].list_policy_name);
404
405 if (policy == ALWAYS_DENY)
406 return false;
407
408 if (policy == POLICY_NOT_SET) {
409 // Only load content settings from secure origins unless it is a
410 // content::MEDIA_OPEN_DEVICE (Pepper) request.
411 if (!IsSchemeSecure() &&
412 request_.request_type != content::MEDIA_OPEN_DEVICE) {
413 return false;
414 }
415 if (profile_->GetHostContentSettingsMap()->GetContentSetting(
416 request_.security_origin, request_.security_origin,
417 device_checks[i].settings_type, NO_RESOURCE_IDENTIFIER) !=
418 CONTENT_SETTING_ALLOW) {
419 return false;
420 }
421 }
422 // If we get here, then either policy is set to ALWAYS_ALLOW or the content
423 // settings allow the request by default.
424 }
425
426 return true;
427 }
428
FilterBlockedByDefaultDevices()429 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() {
430 int requested_devices = 0;
431
432 if (IsDeviceAudioCaptureRequestedAndAllowed()) {
433 if (profile_->GetHostContentSettingsMap()->GetContentSetting(
434 request_.security_origin,
435 request_.security_origin,
436 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
437 NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
438 request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
439 MEDIA_BLOCKED_BY_USER_SETTING;
440 } else {
441 ++requested_devices;
442 }
443 }
444
445 if (IsDeviceVideoCaptureRequestedAndAllowed()) {
446 if (profile_->GetHostContentSettingsMap()->GetContentSetting(
447 request_.security_origin,
448 request_.security_origin,
449 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
450 NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
451 request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
452 MEDIA_BLOCKED_BY_USER_SETTING;
453 } else {
454 ++requested_devices;
455 }
456 }
457
458 return requested_devices;
459 }
460
IsDefaultMediaAccessBlocked() const461 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
463 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
464 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
465 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
466 ContentSetting current_setting =
467 profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
468 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
469 return (current_setting == CONTENT_SETTING_BLOCK);
470 }
471
IsSchemeSecure() const472 bool MediaStreamDevicesController::IsSchemeSecure() const {
473 return request_.security_origin.SchemeIsSecure() ||
474 request_.security_origin.SchemeIs(extensions::kExtensionScheme) ||
475 CommandLine::ForCurrentProcess()->HasSwitch(
476 switches::kDisableUserMediaSecurity);
477 }
478
ShouldAlwaysAllowOrigin() const479 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() const {
480 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
481 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
482 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
483 return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent(
484 request_.security_origin, request_.security_origin,
485 CONTENT_SETTINGS_TYPE_MEDIASTREAM);
486 }
487
SetPermission(bool allowed) const488 void MediaStreamDevicesController::SetPermission(bool allowed) const {
489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
490 ContentSettingsPattern primary_pattern =
491 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin);
492 // Check the pattern is valid or not. When the request is from a file access,
493 // no exception will be made.
494 if (!primary_pattern.IsValid())
495 return;
496
497 ContentSetting content_setting = allowed ?
498 CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
499 if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) !=
500 request_permissions_.end()) {
501 profile_->GetHostContentSettingsMap()->SetContentSetting(
502 primary_pattern,
503 ContentSettingsPattern::Wildcard(),
504 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
505 std::string(),
506 content_setting);
507 }
508 if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) !=
509 request_permissions_.end()) {
510 profile_->GetHostContentSettingsMap()->SetContentSetting(
511 primary_pattern,
512 ContentSettingsPattern::Wildcard(),
513 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
514 std::string(),
515 content_setting);
516 }
517 }
518
NotifyUIRequestAccepted() const519 void MediaStreamDevicesController::NotifyUIRequestAccepted() const {
520 if (!content_settings_)
521 return;
522
523 content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
524 request_permissions_);
525 }
526
NotifyUIRequestDenied()527 void MediaStreamDevicesController::NotifyUIRequestDenied() {
528 if (!content_settings_)
529 return;
530
531 if (IsDeviceAudioCaptureRequestedAndAllowed()) {
532 request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
533 MEDIA_BLOCKED_BY_USER;
534 }
535 if (IsDeviceVideoCaptureRequestedAndAllowed()) {
536 request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
537 MEDIA_BLOCKED_BY_USER;
538 }
539
540 content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
541 request_permissions_);
542 }
543
IsDeviceAudioCaptureRequestedAndAllowed() const544 bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed()
545 const {
546 MediaStreamTypeSettingsMap::const_iterator it =
547 request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
548 return (it != request_permissions_.end() &&
549 it->second.permission == MEDIA_ALLOWED);
550 }
551
IsDeviceVideoCaptureRequestedAndAllowed() const552 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed()
553 const {
554 MediaStreamTypeSettingsMap::const_iterator it =
555 request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
556 return (it != request_permissions_.end() &&
557 it->second.permission == MEDIA_ALLOWED);
558 }
559