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/values.h" | 7 #include "base/values.h" |
8 #include "chrome/browser/content_settings/content_settings_provider.h" | 8 #include "chrome/browser/content_settings/content_settings_provider.h" |
9 #include "chrome/browser/content_settings/host_content_settings_map.h" | 9 #include "chrome/browser/content_settings/host_content_settings_map.h" |
10 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 10 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
11 #include "chrome/browser/profiles/profile.h" | 11 #include "chrome/browser/profiles/profile.h" |
12 #include "chrome/browser/ui/browser.h" | 12 #include "chrome/browser/ui/browser.h" |
13 #include "chrome/common/content_settings.h" | 13 #include "chrome/common/content_settings.h" |
14 #include "chrome/common/pref_names.h" | 14 #include "chrome/common/pref_names.h" |
| 15 #include "content/public/common/media_stream_request.h" |
15 | 16 |
16 using content::BrowserThread; | 17 using content::BrowserThread; |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
20 // A predicate that checks if a StreamDeviceInfo object has the same ID as the | |
21 // device ID specified at construction. | |
22 class DeviceIdEquals { | |
23 public: | |
24 explicit DeviceIdEquals(const std::string& device_id) | |
25 : device_id_(device_id) { | |
26 } | |
27 | |
28 bool operator() (const content::MediaStreamDevice& device) { | |
29 return device.device_id == device_id_; | |
30 } | |
31 | |
32 private: | |
33 std::string device_id_; | |
34 }; | |
35 | |
36 // A predicate that checks if a StreamDeviceInfo object has the same device | 21 // A predicate that checks if a StreamDeviceInfo object has the same device |
37 // name as the device name specified at construction. | 22 // name as the device name specified at construction. |
38 class DeviceNameEquals { | 23 class DeviceNameEquals { |
39 public: | 24 public: |
40 explicit DeviceNameEquals(const std::string& device_name) | 25 explicit DeviceNameEquals(const std::string& device_name) |
41 : device_name_(device_name) { | 26 : device_name_(device_name) { |
42 } | 27 } |
43 | 28 |
44 bool operator() (const content::MediaStreamDevice& device) { | 29 bool operator() (const content::MediaStreamDevice& device) { |
45 return device.name == device_name_; | 30 return device.name == device_name_; |
46 } | 31 } |
47 | 32 |
48 private: | 33 private: |
49 std::string device_name_; | 34 std::string device_name_; |
50 }; | 35 }; |
51 | 36 |
52 // Whether |request| contains any device of given |type|. | |
53 bool HasDevice(const content::MediaStreamRequest& request, | |
54 content::MediaStreamDeviceType type) { | |
55 content::MediaStreamDeviceMap::const_iterator device_it = | |
56 request.devices.find(type); | |
57 return device_it != request.devices.end() && !device_it->second.empty(); | |
58 } | |
59 | |
60 const char kAudioKey[] = "audio"; | 37 const char kAudioKey[] = "audio"; |
61 const char kVideoKey[] = "video"; | 38 const char kVideoKey[] = "video"; |
62 | 39 |
63 } // namespace | 40 } // namespace |
64 | 41 |
65 MediaStreamDevicesController::MediaStreamDevicesController( | 42 MediaStreamDevicesController::MediaStreamDevicesController( |
66 Profile* profile, | 43 Profile* profile, |
67 const content::MediaStreamRequest* request, | 44 const content::MediaStreamRequest* request, |
68 const content::MediaResponseCallback& callback) | 45 const content::MediaResponseCallback& callback) |
69 : profile_(profile), | 46 : has_audio_(false), |
| 47 has_video_(false), |
| 48 profile_(profile), |
70 request_(*request), | 49 request_(*request), |
71 callback_(callback) { | 50 callback_(callback) { |
72 has_audio_ = | 51 for (content::MediaStreamDeviceMap::const_iterator it = |
73 HasDevice(request_, content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE); | 52 request_.devices.begin(); |
74 has_video_ = | 53 it != request_.devices.end(); ++it) { |
75 HasDevice(request_, content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); | 54 if (content::IsAudioMediaType(it->first)) { |
| 55 has_audio_ |= !it->second.empty(); |
| 56 } else if (content::IsVideoMediaType(it->first)) { |
| 57 has_video_ |= !it->second.empty(); |
| 58 } |
| 59 } |
76 } | 60 } |
77 | 61 |
78 MediaStreamDevicesController::~MediaStreamDevicesController() {} | 62 MediaStreamDevicesController::~MediaStreamDevicesController() {} |
79 | 63 |
80 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() { | 64 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() { |
81 // Deny the request if the security origin is empty, this happens with | 65 // Deny the request if the security origin is empty, this happens with |
82 // file access without |--allow-file-access-from-files| flag. | 66 // file access without |--allow-file-access-from-files| flag. |
83 if (request_.security_origin.is_empty()) { | 67 if (request_.security_origin.is_empty()) { |
84 Deny(); | 68 Deny(); |
85 return true; | 69 return true; |
(...skipping 25 matching lines...) Expand all Loading... |
111 return false; | 95 return false; |
112 } | 96 } |
113 | 97 |
114 // Dismiss the infobar by selecting the "always allowed" devices. | 98 // Dismiss the infobar by selecting the "always allowed" devices. |
115 Accept(audio, video, false); | 99 Accept(audio, video, false); |
116 return true; | 100 return true; |
117 } | 101 } |
118 | 102 |
119 content::MediaStreamDevices | 103 content::MediaStreamDevices |
120 MediaStreamDevicesController::GetAudioDevices() const { | 104 MediaStreamDevicesController::GetAudioDevices() const { |
121 if (!has_audio_) | 105 content::MediaStreamDevices all_audio_devices; |
122 return content::MediaStreamDevices(); | 106 if (has_audio_) |
123 | 107 FindSubsetOfDevices(&content::IsAudioMediaType, &all_audio_devices); |
124 content::MediaStreamDeviceMap::const_iterator it = | 108 return all_audio_devices; |
125 request_.devices.find(content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE); | |
126 DCHECK(it != request_.devices.end()); | |
127 return it->second; | |
128 } | 109 } |
129 | 110 |
130 content::MediaStreamDevices | 111 content::MediaStreamDevices |
131 MediaStreamDevicesController::GetVideoDevices() const { | 112 MediaStreamDevicesController::GetVideoDevices() const { |
132 if (!has_video_) | 113 content::MediaStreamDevices all_video_devices; |
133 return content::MediaStreamDevices(); | 114 if (has_video_) |
134 | 115 FindSubsetOfDevices(&content::IsVideoMediaType, &all_video_devices); |
135 content::MediaStreamDeviceMap::const_iterator it = | 116 return all_video_devices; |
136 request_.devices.find(content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); | |
137 DCHECK(it != request_.devices.end()); | |
138 return it->second; | |
139 } | 117 } |
140 | 118 |
141 const GURL& MediaStreamDevicesController::GetSecurityOrigin() const { | 119 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const { |
142 return request_.security_origin; | 120 return request_.security_origin.spec(); |
| 121 } |
| 122 |
| 123 bool MediaStreamDevicesController::IsSafeToAlwaysAllowAudio() const { |
| 124 return IsSafeToAlwaysAllow( |
| 125 &content::IsAudioMediaType, content::MEDIA_DEVICE_AUDIO_CAPTURE); |
| 126 } |
| 127 |
| 128 bool MediaStreamDevicesController::IsSafeToAlwaysAllowVideo() const { |
| 129 return IsSafeToAlwaysAllow( |
| 130 &content::IsVideoMediaType, content::MEDIA_DEVICE_VIDEO_CAPTURE); |
143 } | 131 } |
144 | 132 |
145 void MediaStreamDevicesController::Accept(const std::string& audio_id, | 133 void MediaStreamDevicesController::Accept(const std::string& audio_id, |
146 const std::string& video_id, | 134 const std::string& video_id, |
147 bool always_allow) { | 135 bool always_allow) { |
148 content::MediaStreamDevices devices; | 136 content::MediaStreamDevices devices; |
149 std::string audio_device, video_device; | 137 std::string audio_device_name, video_device_name; |
150 if (has_audio_) { | 138 |
151 AddDeviceWithId(content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE, | 139 const content::MediaStreamDevice* const audio_device = |
152 audio_id, &devices, &audio_device); | 140 FindFirstDeviceWithIdInSubset(&content::IsAudioMediaType, audio_id); |
| 141 if (audio_device) { |
| 142 if (audio_device->type != content::MEDIA_DEVICE_AUDIO_CAPTURE) |
| 143 always_allow = false; // Override for virtual audio device type. |
| 144 devices.push_back(*audio_device); |
| 145 audio_device_name = audio_device->name; |
153 } | 146 } |
154 if (has_video_) { | 147 |
155 AddDeviceWithId(content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE, | 148 const content::MediaStreamDevice* const video_device = |
156 video_id, &devices, &video_device); | 149 FindFirstDeviceWithIdInSubset(&content::IsVideoMediaType, video_id); |
| 150 if (video_device) { |
| 151 if (video_device->type != content::MEDIA_DEVICE_VIDEO_CAPTURE) |
| 152 always_allow = false; // Override for virtual video device type. |
| 153 devices.push_back(*video_device); |
| 154 video_device_name = video_device->name; |
157 } | 155 } |
| 156 |
158 DCHECK(!devices.empty()); | 157 DCHECK(!devices.empty()); |
159 | 158 |
160 if (always_allow) | 159 if (always_allow) |
161 AlwaysAllowOriginAndDevices(audio_device, video_device); | 160 AlwaysAllowOriginAndDevices(audio_device_name, video_device_name); |
162 | 161 |
163 callback_.Run(devices); | 162 callback_.Run(devices); |
164 } | 163 } |
165 | 164 |
166 void MediaStreamDevicesController::Deny() { | 165 void MediaStreamDevicesController::Deny() { |
167 callback_.Run(content::MediaStreamDevices()); | 166 callback_.Run(content::MediaStreamDevices()); |
168 } | 167 } |
169 | 168 |
170 void MediaStreamDevicesController::AddDeviceWithId( | 169 bool MediaStreamDevicesController::IsSafeToAlwaysAllow( |
171 content::MediaStreamDeviceType type, | 170 FilterByDeviceTypeFunc is_included, |
172 const std::string& id, | 171 content::MediaStreamDeviceType device_type) const { |
173 content::MediaStreamDevices* devices, | 172 DCHECK(device_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || |
174 std::string* device_name) { | 173 device_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); |
175 DCHECK(devices); | |
176 content::MediaStreamDeviceMap::const_iterator device_it = | |
177 request_.devices.find(type); | |
178 if (device_it == request_.devices.end()) | |
179 return; | |
180 | 174 |
181 content::MediaStreamDevices::const_iterator it = std::find_if( | 175 if (!request_.security_origin.SchemeIsSecure()) |
182 device_it->second.begin(), device_it->second.end(), DeviceIdEquals(id)); | 176 return false; |
183 if (it == device_it->second.end()) | |
184 return; | |
185 | 177 |
186 devices->push_back(*it); | 178 // If non-physical devices are available for the choosing, then it's not safe. |
187 *device_name = it->name; | 179 bool safe_devices_found = false; |
| 180 for (content::MediaStreamDeviceMap::const_iterator it = |
| 181 request_.devices.begin(); |
| 182 it != request_.devices.end(); ++it) { |
| 183 if (it->first != device_type && is_included(it->first)) |
| 184 return false; |
| 185 safe_devices_found = true; |
| 186 } |
| 187 |
| 188 return safe_devices_found; |
188 } | 189 } |
189 | 190 |
190 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() { | 191 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() { |
191 return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent( | 192 return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent( |
192 request_.security_origin, request_.security_origin, | 193 request_.security_origin, request_.security_origin, |
193 CONTENT_SETTINGS_TYPE_MEDIASTREAM); | 194 CONTENT_SETTINGS_TYPE_MEDIASTREAM); |
194 } | 195 } |
195 | 196 |
196 bool MediaStreamDevicesController::IsMediaDeviceBlocked() { | 197 bool MediaStreamDevicesController::IsMediaDeviceBlocked() { |
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 26 matching lines...) Expand all Loading... |
224 } | 225 } |
225 | 226 |
226 void MediaStreamDevicesController::GetAlwaysAllowedDevices( | 227 void MediaStreamDevicesController::GetAlwaysAllowedDevices( |
227 std::string* audio_id, std::string* video_id) { | 228 std::string* audio_id, std::string* video_id) { |
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
229 DCHECK(audio_id->empty()); | 230 DCHECK(audio_id->empty()); |
230 DCHECK(video_id->empty()); | 231 DCHECK(video_id->empty()); |
231 // If the request is from internal objects like chrome://URLs, use the first | 232 // If the request is from internal objects like chrome://URLs, use the first |
232 // devices on the lists. | 233 // devices on the lists. |
233 if (ShouldAlwaysAllowOrigin()) { | 234 if (ShouldAlwaysAllowOrigin()) { |
234 if (has_audio_) { | 235 if (has_audio_) |
235 *audio_id = | 236 *audio_id = GetFirstDeviceId(content::MEDIA_DEVICE_AUDIO_CAPTURE); |
236 GetFirstDeviceId(content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE); | 237 if (has_video_) |
237 } | 238 *video_id = GetFirstDeviceId(content::MEDIA_DEVICE_VIDEO_CAPTURE); |
238 if (has_video_) { | |
239 *video_id = | |
240 GetFirstDeviceId(content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); | |
241 } | |
242 return; | 239 return; |
243 } | 240 } |
244 | 241 |
245 // "Always allowed" option is only available for secure connection. | 242 // "Always allowed" option is only available for secure connection. |
246 if (!request_.security_origin.SchemeIsSecure()) | 243 if (!request_.security_origin.SchemeIsSecure()) |
247 return; | 244 return; |
248 | 245 |
249 // Checks the media exceptions to get the "always allowed" devices. | 246 // Checks the media exceptions to get the "always allowed" devices. |
250 scoped_ptr<Value> value( | 247 scoped_ptr<Value> value( |
251 profile_->GetHostContentSettingsMap()->GetWebsiteSetting( | 248 profile_->GetHostContentSettingsMap()->GetWebsiteSetting( |
252 request_.security_origin, | 249 request_.security_origin, |
253 request_.security_origin, | 250 request_.security_origin, |
254 CONTENT_SETTINGS_TYPE_MEDIASTREAM, | 251 CONTENT_SETTINGS_TYPE_MEDIASTREAM, |
255 NO_RESOURCE_IDENTIFIER, | 252 NO_RESOURCE_IDENTIFIER, |
256 NULL)); | 253 NULL)); |
257 if (!value.get()) { | 254 if (!value.get()) { |
258 NOTREACHED(); | 255 NOTREACHED(); |
259 return; | 256 return; |
260 } | 257 } |
261 | 258 |
262 const DictionaryValue* value_dict = NULL; | 259 const DictionaryValue* value_dict = NULL; |
263 if (!value->GetAsDictionary(&value_dict) || value_dict->empty()) | 260 if (!value->GetAsDictionary(&value_dict) || value_dict->empty()) |
264 return; | 261 return; |
265 | 262 |
266 std::string audio_name, video_name; | 263 std::string audio_name, video_name; |
267 value_dict->GetString(kAudioKey, &audio_name); | 264 value_dict->GetString(kAudioKey, &audio_name); |
268 value_dict->GetString(kVideoKey, &video_name); | 265 value_dict->GetString(kVideoKey, &video_name); |
269 | 266 |
270 if (has_audio_ && !audio_name.empty()) { | 267 if (has_audio_ && !audio_name.empty()) |
271 *audio_id = GetDeviceIdByName( | 268 *audio_id = GetDeviceIdByName(content::MEDIA_DEVICE_AUDIO_CAPTURE, |
272 content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE, audio_name); | 269 audio_name); |
273 } | 270 if (has_video_ && !video_name.empty()) |
274 if (has_video_ && !video_name.empty()) { | 271 *video_id = GetDeviceIdByName(content::MEDIA_DEVICE_VIDEO_CAPTURE, |
275 *video_id = GetDeviceIdByName( | 272 video_name); |
276 content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE, video_name); | |
277 } | |
278 } | 273 } |
279 | 274 |
280 std::string MediaStreamDevicesController::GetDeviceIdByName( | 275 std::string MediaStreamDevicesController::GetDeviceIdByName( |
281 content::MediaStreamDeviceType type, | 276 content::MediaStreamDeviceType type, |
282 const std::string& name) { | 277 const std::string& name) { |
283 content::MediaStreamDeviceMap::const_iterator device_it = | 278 content::MediaStreamDeviceMap::const_iterator device_it = |
284 request_.devices.find(type); | 279 request_.devices.find(type); |
285 if (device_it != request_.devices.end()) { | 280 if (device_it != request_.devices.end()) { |
286 content::MediaStreamDevices::const_iterator it = std::find_if( | 281 content::MediaStreamDevices::const_iterator it = std::find_if( |
287 device_it->second.begin(), device_it->second.end(), | 282 device_it->second.begin(), device_it->second.end(), |
288 DeviceNameEquals(name)); | 283 DeviceNameEquals(name)); |
289 if (it != device_it->second.end()) | 284 if (it != device_it->second.end()) |
290 return it->device_id; | 285 return it->device_id; |
291 } | 286 } |
292 | 287 |
293 // Device is not available, return an empty string. | 288 // Device is not available, return an empty string. |
294 return std::string(); | 289 return std::string(); |
295 } | 290 } |
296 | 291 |
297 std::string MediaStreamDevicesController::GetFirstDeviceId( | 292 std::string MediaStreamDevicesController::GetFirstDeviceId( |
298 content::MediaStreamDeviceType type) { | 293 content::MediaStreamDeviceType type) { |
299 content::MediaStreamDeviceMap::const_iterator device_it = | 294 content::MediaStreamDeviceMap::const_iterator device_it = |
300 request_.devices.find(type); | 295 request_.devices.find(type); |
301 if (device_it != request_.devices.end()) | 296 if (device_it != request_.devices.end()) |
302 return device_it->second.begin()->device_id; | 297 return device_it->second.begin()->device_id; |
303 | 298 |
304 return std::string(); | 299 return std::string(); |
305 } | 300 } |
| 301 |
| 302 void MediaStreamDevicesController::FindSubsetOfDevices( |
| 303 FilterByDeviceTypeFunc is_included, |
| 304 content::MediaStreamDevices* out) const { |
| 305 for (content::MediaStreamDeviceMap::const_iterator it = |
| 306 request_.devices.begin(); |
| 307 it != request_.devices.end(); ++it) { |
| 308 if (is_included(it->first)) |
| 309 out->insert(out->end(), it->second.begin(), it->second.end()); |
| 310 } |
| 311 } |
| 312 |
| 313 const content::MediaStreamDevice* |
| 314 MediaStreamDevicesController::FindFirstDeviceWithIdInSubset( |
| 315 FilterByDeviceTypeFunc is_included, |
| 316 const std::string& device_id) const { |
| 317 for (content::MediaStreamDeviceMap::const_iterator it = |
| 318 request_.devices.begin(); |
| 319 it != request_.devices.end(); ++it) { |
| 320 if (!is_included(it->first)) continue; |
| 321 for (content::MediaStreamDevices::const_iterator device_it = |
| 322 it->second.begin(); |
| 323 device_it != it->second.end(); ++device_it) { |
| 324 const content::MediaStreamDevice& candidate = *device_it; |
| 325 if (candidate.device_id == device_id) |
| 326 return &candidate; |
| 327 } |
| 328 } |
| 329 return NULL; |
| 330 } |
OLD | NEW |