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/media_stream_devices_controller.h" | 5 #include "chrome/browser/media/media_stream_devices_controller.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
10 #include "base/prefs/scoped_user_pref_update.h" | 10 #include "base/prefs/scoped_user_pref_update.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/browser/content_settings/content_settings_provider.h" | 13 #include "chrome/browser/content_settings/content_settings_provider.h" |
14 #include "chrome/browser/content_settings/host_content_settings_map.h" | 14 #include "chrome/browser/content_settings/host_content_settings_map.h" |
15 #include "chrome/browser/content_settings/tab_specific_content_settings.h" | 15 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
16 #include "chrome/browser/media/media_capture_devices_dispatcher.h" | 16 #include "chrome/browser/media/media_capture_devices_dispatcher.h" |
17 #include "chrome/browser/media/media_stream_capture_indicator.h" | 17 #include "chrome/browser/media/media_stream_capture_indicator.h" |
18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/browser/ui/browser.h" | 19 #include "chrome/browser/ui/browser.h" |
20 #include "chrome/common/chrome_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
21 #include "chrome/common/content_settings.h" | 21 #include "chrome/common/content_settings.h" |
22 #include "chrome/common/content_settings_pattern.h" | 22 #include "chrome/common/content_settings_pattern.h" |
23 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
24 #include "components/pref_registry/pref_registry_syncable.h" | 24 #include "components/pref_registry/pref_registry_syncable.h" |
25 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
26 #include "content/public/browser/navigation_entry.h" | |
27 #include "content/public/common/media_stream_request.h" | 26 #include "content/public/common/media_stream_request.h" |
28 #include "extensions/common/constants.h" | 27 #include "extensions/common/constants.h" |
29 #include "grit/generated_resources.h" | 28 #include "grit/generated_resources.h" |
30 #include "grit/theme_resources.h" | 29 #include "grit/theme_resources.h" |
31 #include "ui/base/l10n/l10n_util.h" | 30 #include "ui/base/l10n/l10n_util.h" |
32 | 31 |
33 #if defined(OS_CHROMEOS) | 32 #if defined(OS_CHROMEOS) |
34 #include "chrome/browser/chromeos/login/users/user_manager.h" | 33 #include "chrome/browser/chromeos/login/users/user_manager.h" |
35 #endif | 34 #endif |
36 | 35 |
37 using content::BrowserThread; | 36 using content::BrowserThread; |
38 | 37 |
39 namespace { | 38 namespace { |
40 | 39 |
41 // This prefix is combined with request security origins to store media access | |
42 // permissions that the user has granted a specific page navigation instance. | |
43 // The string value stored with the navigation instance will contain one or more | |
44 // kMediaPermissionXxx constants that indicates the permission(s) that the user | |
45 // has granted the page. | |
46 const char kMediaPermissionKeyPrefix[] = "media_permissions#"; | |
47 const base::char16 kMediaPermissionAudio = static_cast<base::char16>('a'); | |
48 const base::char16 kMediaPermissionVideo = static_cast<base::char16>('v'); | |
49 | |
50 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) { | 40 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) { |
51 const content::MediaStreamDevices* audio_devices = | 41 const content::MediaStreamDevices* audio_devices = |
52 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ? | 42 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ? |
53 &MediaCaptureDevicesDispatcher::GetInstance() | 43 &MediaCaptureDevicesDispatcher::GetInstance() |
54 ->GetAudioCaptureDevices() : | 44 ->GetAudioCaptureDevices() : |
55 NULL; | 45 NULL; |
56 | 46 |
57 const content::MediaStreamDevices* video_devices = | 47 const content::MediaStreamDevices* video_devices = |
58 request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ? | 48 request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ? |
59 &MediaCaptureDevicesDispatcher::GetInstance() | 49 &MediaCaptureDevicesDispatcher::GetInstance() |
(...skipping 23 matching lines...) Expand all Loading... |
83 } | 73 } |
84 | 74 |
85 if (!request.requested_video_device_id.empty() && | 75 if (!request.requested_video_device_id.empty() && |
86 !video_devices->FindById(request.requested_video_device_id)) { | 76 !video_devices->FindById(request.requested_video_device_id)) { |
87 return false; | 77 return false; |
88 } | 78 } |
89 | 79 |
90 return true; | 80 return true; |
91 } | 81 } |
92 | 82 |
93 base::string16 GetMediaPermissionsFromNavigationEntry( | |
94 content::NavigationEntry* navigation_entry, | |
95 const content::MediaStreamRequest& request) { | |
96 const std::string key(kMediaPermissionKeyPrefix + | |
97 request.security_origin.spec()); | |
98 | |
99 base::string16 permissions; | |
100 if (!navigation_entry->GetExtraData(key, &permissions)) { | |
101 DCHECK(permissions.empty()); | |
102 } | |
103 | |
104 return permissions; | |
105 } | |
106 | |
107 void SetMediaPermissionsForNavigationEntry( | |
108 content::NavigationEntry* navigation_entry, | |
109 const content::MediaStreamRequest& request, | |
110 const base::string16& permissions) { | |
111 const std::string key(kMediaPermissionKeyPrefix + | |
112 request.security_origin.spec()); | |
113 permissions.empty() ? | |
114 navigation_entry->ClearExtraData(key) : | |
115 navigation_entry->SetExtraData(key, permissions); | |
116 } | |
117 | |
118 void SetMediaPermissionsForNavigationEntry( | |
119 content::NavigationEntry* navigation_entry, | |
120 const content::MediaStreamRequest& request, | |
121 bool allow_audio, | |
122 bool allow_video) { | |
123 base::string16 permissions; | |
124 if (allow_audio) | |
125 permissions += kMediaPermissionAudio; | |
126 if (allow_video) | |
127 permissions += kMediaPermissionVideo; | |
128 SetMediaPermissionsForNavigationEntry(navigation_entry, request, permissions); | |
129 } | |
130 | |
131 bool IsRequestAllowedByNavigationEntry( | |
132 content::NavigationEntry* navigation_entry, | |
133 const content::MediaStreamRequest& request) { | |
134 using content::MEDIA_NO_SERVICE; | |
135 using content::MEDIA_DEVICE_AUDIO_CAPTURE; | |
136 using content::MEDIA_DEVICE_VIDEO_CAPTURE; | |
137 | |
138 // If we aren't being asked for at least one of these two, fail right away. | |
139 if (!navigation_entry || | |
140 (request.audio_type != MEDIA_DEVICE_AUDIO_CAPTURE && | |
141 request.video_type != MEDIA_DEVICE_VIDEO_CAPTURE)) { | |
142 return false; | |
143 } | |
144 | |
145 base::string16 permissions = | |
146 GetMediaPermissionsFromNavigationEntry(navigation_entry, request); | |
147 | |
148 bool audio_requested_and_granted = | |
149 request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE && | |
150 permissions.find(kMediaPermissionAudio) != base::string16::npos; | |
151 | |
152 bool video_requested_and_granted = | |
153 request.video_type == MEDIA_DEVICE_VIDEO_CAPTURE && | |
154 permissions.find(kMediaPermissionVideo) != base::string16::npos; | |
155 | |
156 return | |
157 (audio_requested_and_granted || request.audio_type == MEDIA_NO_SERVICE) && | |
158 (video_requested_and_granted || request.video_type == MEDIA_NO_SERVICE); | |
159 } | |
160 | |
161 | |
162 bool IsInKioskMode() { | 83 bool IsInKioskMode() { |
163 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) | 84 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) |
164 return true; | 85 return true; |
165 | 86 |
166 #if defined(OS_CHROMEOS) | 87 #if defined(OS_CHROMEOS) |
167 const chromeos::UserManager* user_manager = chromeos::UserManager::Get(); | 88 const chromeos::UserManager* user_manager = chromeos::UserManager::Get(); |
168 return user_manager && user_manager->IsLoggedInAsKioskApp(); | 89 return user_manager && user_manager->IsLoggedInAsKioskApp(); |
169 #else | 90 #else |
170 return false; | 91 return false; |
171 #endif | 92 #endif |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); | 223 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); |
303 return true; | 224 return true; |
304 } | 225 } |
305 | 226 |
306 // Check if the media default setting is set to block. | 227 // Check if the media default setting is set to block. |
307 if (IsDefaultMediaAccessBlocked()) { | 228 if (IsDefaultMediaAccessBlocked()) { |
308 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); | 229 Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED); |
309 return true; | 230 return true; |
310 } | 231 } |
311 | 232 |
312 // Check if the navigation entry has previously been granted access. | |
313 // We do this after the IsDefaultMediaAccessBlocked check to handle the use | |
314 // case where the user modifies the content settings to 'deny' after having | |
315 // previously granted the page access and the permissions in the | |
316 // NavigationEntry are out of date. | |
317 content::NavigationEntry* navigation_entry = | |
318 web_contents_->GetController().GetVisibleEntry(); | |
319 if (IsRequestAllowedByNavigationEntry(navigation_entry, request_)) { | |
320 Accept(false); | |
321 return true; | |
322 } | |
323 | |
324 // Show the infobar. | 233 // Show the infobar. |
325 return false; | 234 return false; |
326 } | 235 } |
327 | 236 |
328 bool MediaStreamDevicesController::HasAudio() const { | 237 bool MediaStreamDevicesController::HasAudio() const { |
329 return IsDeviceAudioCaptureRequestedAndAllowed(); | 238 return IsDeviceAudioCaptureRequestedAndAllowed(); |
330 } | 239 } |
331 | 240 |
332 bool MediaStreamDevicesController::HasVideo() const { | 241 bool MediaStreamDevicesController::HasVideo() const { |
333 return IsDeviceVideoCaptureRequestedAndAllowed(); | 242 return IsDeviceVideoCaptureRequestedAndAllowed(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 | 311 |
403 // If either or both audio and video devices were requested but not | 312 // If either or both audio and video devices were requested but not |
404 // specified by id, get the default devices. | 313 // specified by id, get the default devices. |
405 if (get_default_audio_device || get_default_video_device) { | 314 if (get_default_audio_device || get_default_video_device) { |
406 MediaCaptureDevicesDispatcher::GetInstance()-> | 315 MediaCaptureDevicesDispatcher::GetInstance()-> |
407 GetDefaultDevicesForProfile(profile_, | 316 GetDefaultDevicesForProfile(profile_, |
408 get_default_audio_device, | 317 get_default_audio_device, |
409 get_default_video_device, | 318 get_default_video_device, |
410 &devices); | 319 &devices); |
411 } | 320 } |
412 | |
413 // For pages accessed via http (not https), tag this navigation entry | |
414 // with the granted permissions. This avoids repeated prompts for | |
415 // device access. | |
416 if (!IsSchemeSecure()) { | |
417 content::NavigationEntry* navigation_entry = | |
418 web_contents_->GetController().GetVisibleEntry(); | |
419 if (navigation_entry) { | |
420 SetMediaPermissionsForNavigationEntry( | |
421 navigation_entry, request_, audio_allowed, video_allowed); | |
422 } | |
423 } | |
424 break; | 321 break; |
425 } | 322 } |
426 case content::MEDIA_DEVICE_ACCESS: { | 323 case content::MEDIA_DEVICE_ACCESS: { |
427 // Get the default devices for the request. | 324 // Get the default devices for the request. |
428 MediaCaptureDevicesDispatcher::GetInstance()-> | 325 MediaCaptureDevicesDispatcher::GetInstance()-> |
429 GetDefaultDevicesForProfile(profile_, | 326 GetDefaultDevicesForProfile(profile_, |
430 audio_allowed, | 327 audio_allowed, |
431 video_allowed, | 328 video_allowed, |
432 &devices); | 329 &devices); |
433 break; | 330 break; |
(...skipping 29 matching lines...) Expand all Loading... |
463 content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, | 360 content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, |
464 ui.Pass()); | 361 ui.Pass()); |
465 } | 362 } |
466 | 363 |
467 void MediaStreamDevicesController::Deny( | 364 void MediaStreamDevicesController::Deny( |
468 bool update_content_setting, | 365 bool update_content_setting, |
469 content::MediaStreamRequestResult result) { | 366 content::MediaStreamRequestResult result) { |
470 DLOG(WARNING) << "MediaStreamDevicesController::Deny: " << result; | 367 DLOG(WARNING) << "MediaStreamDevicesController::Deny: " << result; |
471 NotifyUIRequestDenied(); | 368 NotifyUIRequestDenied(); |
472 | 369 |
473 // Clear previously allowed permissions from the navigation entry if any. | |
474 content::NavigationEntry* navigation_entry = | |
475 web_contents_->GetController().GetVisibleEntry(); | |
476 if (navigation_entry) { | |
477 SetMediaPermissionsForNavigationEntry( | |
478 navigation_entry, request_, false, false); | |
479 } | |
480 | |
481 if (update_content_setting) { | 370 if (update_content_setting) { |
482 CHECK_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, result); | 371 CHECK_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, result); |
483 SetPermission(false); | 372 SetPermission(false); |
484 } | 373 } |
485 | 374 |
486 content::MediaResponseCallback cb = callback_; | 375 content::MediaResponseCallback cb = callback_; |
487 callback_.Reset(); | 376 callback_.Reset(); |
488 cb.Run(content::MediaStreamDevices(), | 377 cb.Run(content::MediaStreamDevices(), |
489 result, | 378 result, |
490 scoped_ptr<content::MediaStreamUI>()); | 379 scoped_ptr<content::MediaStreamUI>()); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 it->second.permission == MEDIA_ALLOWED); | 653 it->second.permission == MEDIA_ALLOWED); |
765 } | 654 } |
766 | 655 |
767 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed() | 656 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed() |
768 const { | 657 const { |
769 MediaStreamTypeSettingsMap::const_iterator it = | 658 MediaStreamTypeSettingsMap::const_iterator it = |
770 request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE); | 659 request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE); |
771 return (it != request_permissions_.end() && | 660 return (it != request_permissions_.end() && |
772 it->second.permission == MEDIA_ALLOWED); | 661 it->second.permission == MEDIA_ALLOWED); |
773 } | 662 } |
OLD | NEW |