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