Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Side by Side Diff: chrome/browser/media/media_capture_devices_dispatcher.cc

Issue 1095393004: Refactor: Make MediaCaptureDevicesDispatcher have pluggable handlers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove ENABLE_EXTENSIONS checks from DesktopCapture & TabCapture. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_capture_devices_dispatcher.h" 5 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/metrics/field_trial.h" 9 #include "base/metrics/field_trial.h"
10 #include "base/prefs/pref_service.h" 10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h" 11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/sha1.h" 12 #include "base/sha1.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/media/desktop_streams_registry.h" 16 #include "chrome/browser/media/desktop_streams_registry.h"
17 #include "chrome/browser/media/media_access_handler.h"
17 #include "chrome/browser/media/media_stream_capture_indicator.h" 18 #include "chrome/browser/media/media_stream_capture_indicator.h"
18 #include "chrome/browser/media/media_stream_device_permissions.h" 19 #include "chrome/browser/media/permission_bubble_media_access_handler.h"
19 #include "chrome/browser/media/media_stream_infobar_delegate.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/browser_window.h" 21 #include "chrome/browser/ui/browser_window.h"
24 #include "chrome/browser/ui/screen_capture_notification_ui.h"
25 #include "chrome/browser/ui/simple_message_box.h"
26 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
27 #include "chrome/common/chrome_switches.h" 22 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/chrome_version_info.h" 23 #include "chrome/common/chrome_version_info.h"
29 #include "chrome/common/pref_names.h" 24 #include "chrome/common/pref_names.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "components/content_settings/core/browser/host_content_settings_map.h"
32 #include "components/pref_registry/pref_registry_syncable.h" 25 #include "components/pref_registry/pref_registry_syncable.h"
33 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/desktop_media_id.h"
35 #include "content/public/browser/media_capture_devices.h" 27 #include "content/public/browser/media_capture_devices.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_source.h" 28 #include "content/public/browser/notification_source.h"
38 #include "content/public/browser/notification_types.h"
39 #include "content/public/browser/render_frame_host.h" 29 #include "content/public/browser/render_frame_host.h"
40 #include "content/public/browser/render_process_host.h" 30 #include "content/public/browser/render_process_host.h"
41 #include "content/public/browser/web_contents.h" 31 #include "content/public/browser/web_contents.h"
42 #include "content/public/common/media_stream_request.h" 32 #include "content/public/common/media_stream_request.h"
43 #include "extensions/common/constants.h" 33 #include "extensions/common/constants.h"
44 #include "media/audio/audio_manager_base.h"
45 #include "media/base/media_switches.h" 34 #include "media/base/media_switches.h"
46 #include "net/base/net_util.h" 35 #include "net/base/net_util.h"
47 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
48 #include "ui/base/l10n/l10n_util.h"
49 36
50 #if defined(OS_CHROMEOS) 37 #if defined(OS_CHROMEOS)
51 #include "ash/shell.h" 38 #include "ash/shell.h"
52 #endif // defined(OS_CHROMEOS) 39 #endif // defined(OS_CHROMEOS)
53 40
54 #if defined(ENABLE_EXTENSIONS) 41 #if defined(ENABLE_EXTENSIONS)
55 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" 42 #include "chrome/browser/media/desktop_capture_access_handler.h"
56 #include "extensions/browser/app_window/app_window.h" 43 #include "chrome/browser/media/extension_media_access_handler.h"
57 #include "extensions/browser/app_window/app_window_registry.h" 44 #include "chrome/browser/media/tab_capture_access_handler.h"
58 #include "extensions/browser/extension_registry.h" 45 #include "extensions/browser/extension_registry.h"
59 #include "extensions/common/extension.h" 46 #include "extensions/common/extension.h"
60 #include "extensions/common/permissions/permissions_data.h" 47 #include "extensions/common/permissions/permissions_data.h"
61 #endif 48 #endif
62 49
63 using content::BrowserThread; 50 using content::BrowserThread;
64 using content::MediaCaptureDevices; 51 using content::MediaCaptureDevices;
65 using content::MediaStreamDevices; 52 using content::MediaStreamDevices;
66 53
67 namespace { 54 namespace {
68 55
69 // A finch experiment to enable the permission bubble for media requests only.
70 bool MediaStreamPermissionBubbleExperimentEnabled() {
71 const std::string group =
72 base::FieldTrialList::FindFullName("MediaStreamPermissionBubble");
73 if (group == "enabled")
74 return true;
75
76 return false;
77 }
78
79 // Finds a device in |devices| that has |device_id|, or NULL if not found. 56 // Finds a device in |devices| that has |device_id|, or NULL if not found.
80 const content::MediaStreamDevice* FindDeviceWithId( 57 const content::MediaStreamDevice* FindDeviceWithId(
81 const content::MediaStreamDevices& devices, 58 const content::MediaStreamDevices& devices,
82 const std::string& device_id) { 59 const std::string& device_id) {
83 content::MediaStreamDevices::const_iterator iter = devices.begin(); 60 content::MediaStreamDevices::const_iterator iter = devices.begin();
84 for (; iter != devices.end(); ++iter) { 61 for (; iter != devices.end(); ++iter) {
85 if (iter->id == device_id) { 62 if (iter->id == device_id) {
86 return &(*iter); 63 return &(*iter);
87 } 64 }
88 } 65 }
89 return NULL; 66 return NULL;
90 } 67 }
91 68
92 #if defined(ENABLE_EXTENSIONS) 69 inline DesktopCaptureAccessHandler* ToDesktopCaptureAccessHandler(
93 // This is a short-term solution to grant camera and/or microphone access to 70 MediaAccessHandler* handler) {
94 // extensions: 71 return static_cast<DesktopCaptureAccessHandler*>(handler);
95 // 1. Virtual keyboard extension.
96 // 2. Flutter gesture recognition extension.
97 // 3. TODO(smus): Airbender experiment 1.
98 // 4. TODO(smus): Airbender experiment 2.
99 // 5. Hotwording component extension.
100 // 6. XKB input method component extension.
101 // 7. M17n/T13n/CJK input method component extension.
102 // Once http://crbug.com/292856 is fixed, remove this whitelist.
103 bool IsMediaRequestWhitelistedForExtension(
104 const extensions::Extension* extension) {
105 return extension->id() == "mppnpdlheglhdfmldimlhpnegondlapf" ||
106 extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo" ||
107 extension->id() == "clffjmdilanldobdnedchkdbofoimcgb" ||
108 extension->id() == "nnckehldicaciogcbchegobnafnjkcne" ||
109 extension->id() == "nbpagnldghgfoolbancepceaanlmhfmd" ||
110 extension->id() == "jkghodnilhceideoidjikpgommlajknk" ||
111 extension->id() == "gjaehgfemfahhmlgpdfknkhdnemmolop";
112 } 72 }
113
114 bool IsBuiltInExtension(const GURL& origin) {
115 return
116 // Feedback Extension.
117 origin.spec() == "chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/";
118 }
119
120 // Returns true of the security origin is associated with casting.
121 bool IsOriginForCasting(const GURL& origin) {
122 // Whitelisted tab casting extensions.
123 return
124 // Dev
125 origin.spec() == "chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/" ||
126 // Canary
127 origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/" ||
128 // Beta (internal)
129 origin.spec() == "chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj/" ||
130 // Google Cast Beta
131 origin.spec() == "chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm/" ||
132 // Google Cast Stable
133 origin.spec() == "chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/" ||
134 // http://crbug.com/457908
135 origin.spec() == "chrome-extension://ekpaaapppgpmolpcldedioblbkmijaca/" ||
136 origin.spec() == "chrome-extension://fjhoaacokmgbjemoflkofnenfaiekifl/";
137 }
138
139 bool IsExtensionWhitelistedForScreenCapture(
140 const extensions::Extension* extension) {
141 #if defined(OS_CHROMEOS)
142 std::string hash = base::SHA1HashString(extension->id());
143 std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
144
145 // crbug.com/446688
146 return hex_hash == "4F25792AF1AA7483936DE29C07806F203C7170A0" ||
147 hex_hash == "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9" ||
148 hex_hash == "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB" ||
149 hex_hash == "81986D4F846CEDDDB962643FA501D1780DD441BB";
150 #else
151 return false;
152 #endif // defined(OS_CHROMEOS)
153 }
154 #endif // defined(ENABLE_EXTENSIONS)
155
156 // Helper to get title of the calling application shown in the screen capture
157 // notification.
158 base::string16 GetApplicationTitle(content::WebContents* web_contents,
159 const extensions::Extension* extension) {
160 // Use extension name as title for extensions and host/origin for drive-by
161 // web.
162 std::string title;
163 #if defined(ENABLE_EXTENSIONS)
164 if (extension) {
165 title = extension->name();
166 return base::UTF8ToUTF16(title);
167 }
168 #endif
169 GURL url = web_contents->GetURL();
170 title = url.SchemeIsSecure() ? net::GetHostAndOptionalPort(url)
171 : url.GetOrigin().spec();
172 return base::UTF8ToUTF16(title);
173 }
174
175 // Helper to get list of media stream devices for desktop capture in |devices|.
176 // Registers to display notification if |display_notification| is true.
177 // Returns an instance of MediaStreamUI to be passed to content layer.
178 scoped_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
179 content::MediaStreamDevices* devices,
180 content::DesktopMediaID media_id,
181 bool capture_audio,
182 bool display_notification,
183 const base::string16& application_title,
184 const base::string16& registered_extension_name) {
185 DCHECK_CURRENTLY_ON(BrowserThread::UI);
186 scoped_ptr<content::MediaStreamUI> ui;
187
188 // Add selected desktop source to the list.
189 devices->push_back(content::MediaStreamDevice(
190 content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen"));
191 if (capture_audio) {
192 // Use the special loopback device ID for system audio capture.
193 devices->push_back(content::MediaStreamDevice(
194 content::MEDIA_DESKTOP_AUDIO_CAPTURE,
195 media::AudioManagerBase::kLoopbackInputDeviceId, "System Audio"));
196 }
197
198 // If required, register to display the notification for stream capture.
199 if (display_notification) {
200 if (application_title == registered_extension_name) {
201 ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
202 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT,
203 application_title));
204 } else {
205 ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
206 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
207 registered_extension_name,
208 application_title));
209 }
210 }
211
212 return ui.Pass();
213 }
214
215 #if !defined(OS_ANDROID)
216 // Find browser or app window from a given |web_contents|.
217 gfx::NativeWindow FindParentWindowForWebContents(
218 content::WebContents* web_contents) {
219 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
220 if (browser && browser->window())
221 return browser->window()->GetNativeWindow();
222
223 const extensions::AppWindowRegistry::AppWindowList& window_list =
224 extensions::AppWindowRegistry::Get(
225 web_contents->GetBrowserContext())->app_windows();
226 for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter =
227 window_list.begin();
228 iter != window_list.end(); ++iter) {
229 if ((*iter)->web_contents() == web_contents)
230 return (*iter)->GetNativeWindow();
231 }
232
233 return NULL;
234 }
235 #endif
236
237 } // namespace 73 } // namespace
238 74
239 MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(
240 const content::MediaStreamRequest& request,
241 const content::MediaResponseCallback& callback)
242 : request(request),
243 callback(callback) {
244 }
245
246 MediaCaptureDevicesDispatcher::PendingAccessRequest::~PendingAccessRequest() {}
247
248 MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { 75 MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
249 return Singleton<MediaCaptureDevicesDispatcher>::get(); 76 return Singleton<MediaCaptureDevicesDispatcher>::get();
250 } 77 }
251 78
252 MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() 79 MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
253 : is_device_enumeration_disabled_(false), 80 : is_device_enumeration_disabled_(false),
254 media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) { 81 media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) {
255 // MediaCaptureDevicesDispatcher is a singleton. It should be created on
256 // UI thread. Otherwise, it will not receive
257 // content::NOTIFICATION_WEB_CONTENTS_DESTROYED, and that will result in
258 // possible use after free.
259 DCHECK_CURRENTLY_ON(BrowserThread::UI); 82 DCHECK_CURRENTLY_ON(BrowserThread::UI);
260 notifications_registrar_.Add(
261 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
262 content::NotificationService::AllSources());
263 83
264 #if defined(OS_MACOSX) 84 #if defined(OS_MACOSX)
265 // AVFoundation is used for video/audio device monitoring and video capture. 85 // AVFoundation is used for video/audio device monitoring and video capture.
266 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( 86 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
267 switches::kForceQTKit)) { 87 switches::kForceQTKit)) {
268 base::CommandLine::ForCurrentProcess()->AppendSwitch( 88 base::CommandLine::ForCurrentProcess()->AppendSwitch(
269 switches::kEnableAVFoundation); 89 switches::kEnableAVFoundation);
270 } 90 }
271 #endif 91 #endif
92
93 #if defined(ENABLE_EXTENSIONS)
94 media_access_handlers_.push_back(new ExtensionMediaAccessHandler());
95 media_access_handlers_.push_back(new DesktopCaptureAccessHandler());
96 media_access_handlers_.push_back(new TabCaptureAccessHandler());
97 #endif
98 media_access_handlers_.push_back(new PermissionBubbleMediaAccessHandler());
272 } 99 }
273 100
274 MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {} 101 MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
275 102
276 void MediaCaptureDevicesDispatcher::RegisterProfilePrefs( 103 void MediaCaptureDevicesDispatcher::RegisterProfilePrefs(
277 user_prefs::PrefRegistrySyncable* registry) { 104 user_prefs::PrefRegistrySyncable* registry) {
278 registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice, 105 registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
279 std::string()); 106 std::string());
280 registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice, 107 registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
281 std::string()); 108 std::string());
282 } 109 }
283 110
111 bool MediaCaptureDevicesDispatcher::IsOriginForCasting(const GURL& origin) {
112 // Whitelisted tab casting extensions.
113 return
114 // Dev
115 origin.spec() == "chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/" ||
116 // Canary
117 origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/" ||
118 // Beta (internal)
119 origin.spec() == "chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj/" ||
120 // Google Cast Beta
121 origin.spec() == "chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm/" ||
122 // Google Cast Stable
123 origin.spec() == "chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/" ||
124 // http://crbug.com/457908
125 origin.spec() == "chrome-extension://ekpaaapppgpmolpcldedioblbkmijaca/" ||
126 origin.spec() == "chrome-extension://fjhoaacokmgbjemoflkofnenfaiekifl/";
127 }
128
284 void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) { 129 void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) {
285 DCHECK_CURRENTLY_ON(BrowserThread::UI); 130 DCHECK_CURRENTLY_ON(BrowserThread::UI);
286 if (!observers_.HasObserver(observer)) 131 if (!observers_.HasObserver(observer))
287 observers_.AddObserver(observer); 132 observers_.AddObserver(observer);
288 } 133 }
289 134
290 void MediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) { 135 void MediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) {
291 DCHECK_CURRENTLY_ON(BrowserThread::UI); 136 DCHECK_CURRENTLY_ON(BrowserThread::UI);
292 observers_.RemoveObserver(observer); 137 observers_.RemoveObserver(observer);
293 } 138 }
294 139
295 const MediaStreamDevices& 140 const MediaStreamDevices&
296 MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() { 141 MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
297 DCHECK_CURRENTLY_ON(BrowserThread::UI); 142 DCHECK_CURRENTLY_ON(BrowserThread::UI);
298 if (is_device_enumeration_disabled_ || !test_audio_devices_.empty()) 143 if (is_device_enumeration_disabled_ || !test_audio_devices_.empty())
299 return test_audio_devices_; 144 return test_audio_devices_;
300 145
301 return MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(); 146 return MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
302 } 147 }
303 148
304 const MediaStreamDevices& 149 const MediaStreamDevices&
305 MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { 150 MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
306 DCHECK_CURRENTLY_ON(BrowserThread::UI); 151 DCHECK_CURRENTLY_ON(BrowserThread::UI);
307 if (is_device_enumeration_disabled_ || !test_video_devices_.empty()) 152 if (is_device_enumeration_disabled_ || !test_video_devices_.empty())
308 return test_video_devices_; 153 return test_video_devices_;
309 154
310 return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(); 155 return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
311 } 156 }
312 157
313 void MediaCaptureDevicesDispatcher::Observe(
314 int type,
315 const content::NotificationSource& source,
316 const content::NotificationDetails& details) {
317 DCHECK_CURRENTLY_ON(BrowserThread::UI);
318 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
319 content::WebContents* web_contents =
320 content::Source<content::WebContents>(source).ptr();
321 pending_requests_.erase(web_contents);
322 }
323 }
324
325 void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest( 158 void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest(
326 content::WebContents* web_contents, 159 content::WebContents* web_contents,
327 const content::MediaStreamRequest& request, 160 const content::MediaStreamRequest& request,
328 const content::MediaResponseCallback& callback, 161 const content::MediaResponseCallback& callback,
329 const extensions::Extension* extension) { 162 const extensions::Extension* extension) {
330 DCHECK_CURRENTLY_ON(BrowserThread::UI); 163 DCHECK_CURRENTLY_ON(BrowserThread::UI);
331 164
332 if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || 165 for (MediaAccessHandler* handler : media_access_handlers_) {
333 request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) { 166 if (handler->SupportsStreamType(request.video_type, extension) ||
334 ProcessDesktopCaptureAccessRequest( 167 handler->SupportsStreamType(request.audio_type, extension)) {
335 web_contents, request, callback, extension); 168 handler->HandleRequest(web_contents, request, callback, extension);
336 } else if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE ||
337 request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) {
338 ProcessTabCaptureAccessRequest(
339 web_contents, request, callback, extension);
340 } else {
341 #if defined(ENABLE_EXTENSIONS)
342 bool is_whitelisted =
343 extension && (extension->is_platform_app() ||
344 IsMediaRequestWhitelistedForExtension(extension));
345 if (is_whitelisted) {
346 // For extensions access is approved based on extension permissions.
347 ProcessMediaAccessRequestFromPlatformAppOrExtension(
348 web_contents, request, callback, extension);
349 return; 169 return;
350 } 170 }
351 #endif
352 ProcessRegularMediaAccessRequest(web_contents, request, callback);
353 } 171 }
172 callback.Run(content::MediaStreamDevices(),
173 content::MEDIA_DEVICE_NOT_SUPPORTED, nullptr);
354 } 174 }
355 175
356 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( 176 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
357 content::WebContents* web_contents, 177 content::WebContents* web_contents,
358 const GURL& security_origin, 178 const GURL& security_origin,
359 content::MediaStreamType type) { 179 content::MediaStreamType type) {
360 DCHECK_CURRENTLY_ON(BrowserThread::UI); 180 DCHECK_CURRENTLY_ON(BrowserThread::UI);
361 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || 181 return CheckMediaAccessPermission(web_contents, security_origin, type,
362 type == content::MEDIA_DEVICE_VIDEO_CAPTURE); 182 nullptr);
363
364 Profile* profile =
365 Profile::FromBrowserContext(web_contents->GetBrowserContext());
366
367 ContentSettingsType contentSettingsType =
368 type == content::MEDIA_DEVICE_AUDIO_CAPTURE
369 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
370 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
371
372 if (CheckAllowAllMediaStreamContentForOrigin(
373 profile, security_origin, contentSettingsType)) {
374 return true;
375 }
376
377 const char* policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
378 ? prefs::kAudioCaptureAllowed
379 : prefs::kVideoCaptureAllowed;
380 const char* list_policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
381 ? prefs::kAudioCaptureAllowedUrls
382 : prefs::kVideoCaptureAllowedUrls;
383 if (GetDevicePolicy(
384 profile, security_origin, policy_name, list_policy_name) ==
385 ALWAYS_ALLOW) {
386 return true;
387 }
388
389 // There's no secondary URL for these content types, hence duplicating
390 // |security_origin|.
391 if (profile->GetHostContentSettingsMap()->GetContentSetting(
392 security_origin,
393 security_origin,
394 contentSettingsType,
395 content_settings::ResourceIdentifier()) == CONTENT_SETTING_ALLOW) {
396 return true;
397 }
398
399 return false;
400 } 183 }
401 184
402 #if defined(ENABLE_EXTENSIONS)
403 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( 185 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
404 content::WebContents* web_contents, 186 content::WebContents* web_contents,
405 const GURL& security_origin, 187 const GURL& security_origin,
406 content::MediaStreamType type, 188 content::MediaStreamType type,
407 const extensions::Extension* extension) { 189 const extensions::Extension* extension) {
408 DCHECK_CURRENTLY_ON(BrowserThread::UI); 190 DCHECK_CURRENTLY_ON(BrowserThread::UI);
409 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || 191 for (MediaAccessHandler* handler : media_access_handlers_) {
410 type == content::MEDIA_DEVICE_VIDEO_CAPTURE); 192 if (handler->SupportsStreamType(type, extension)) {
411 193 return handler->CheckMediaAccessPermission(web_contents, security_origin,
412 if (extension->is_platform_app() || 194 type, extension);
413 IsMediaRequestWhitelistedForExtension(extension)) {
414 return extension->permissions_data()->HasAPIPermission(
415 type == content::MEDIA_DEVICE_AUDIO_CAPTURE
416 ? extensions::APIPermission::kAudioCapture
417 : extensions::APIPermission::kVideoCapture);
418 }
419
420 return CheckMediaAccessPermission(web_contents, security_origin, type);
421 }
422 #endif
423
424 void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest(
425 content::WebContents* web_contents,
426 const content::MediaStreamRequest& request,
427 const content::MediaResponseCallback& callback,
428 const extensions::Extension* extension) {
429 content::MediaStreamDevices devices;
430 scoped_ptr<content::MediaStreamUI> ui;
431
432 if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
433 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
434 return;
435 }
436
437 // If the device id wasn't specified then this is a screen capture request
438 // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
439 if (request.requested_video_device_id.empty()) {
440 ProcessScreenCaptureAccessRequest(
441 web_contents, request, callback, extension);
442 return;
443 }
444
445 // The extension name that the stream is registered with.
446 std::string original_extension_name;
447 // Resolve DesktopMediaID for the specified device id.
448 content::DesktopMediaID media_id;
449 // TODO(miu): Replace "main RenderFrame" IDs with the request's actual
450 // RenderFrame IDs once the desktop capture extension API implementation is
451 // fixed. http://crbug.com/304341
452 content::WebContents* const web_contents_for_stream =
453 content::WebContents::FromRenderFrameHost(
454 content::RenderFrameHost::FromID(request.render_process_id,
455 request.render_frame_id));
456 content::RenderFrameHost* const main_frame = web_contents_for_stream ?
457 web_contents_for_stream->GetMainFrame() : NULL;
458 if (main_frame) {
459 media_id = GetDesktopStreamsRegistry()->RequestMediaForStreamId(
460 request.requested_video_device_id,
461 main_frame->GetProcess()->GetID(),
462 main_frame->GetRoutingID(),
463 request.security_origin,
464 &original_extension_name);
465 }
466
467 // Received invalid device id.
468 if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
469 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
470 return;
471 }
472
473 bool loopback_audio_supported = false;
474 #if defined(USE_CRAS) || defined(OS_WIN)
475 // Currently loopback audio capture is supported only on Windows and ChromeOS.
476 loopback_audio_supported = true;
477 #endif
478
479 // Audio is only supported for screen capture streams.
480 bool capture_audio =
481 (media_id.type == content::DesktopMediaID::TYPE_SCREEN &&
482 request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
483 loopback_audio_supported);
484
485 ui = GetDevicesForDesktopCapture(
486 &devices, media_id, capture_audio, true,
487 GetApplicationTitle(web_contents, extension),
488 base::UTF8ToUTF16(original_extension_name));
489
490 callback.Run(devices, content::MEDIA_DEVICE_OK, ui.Pass());
491 }
492
493 void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest(
494 content::WebContents* web_contents,
495 const content::MediaStreamRequest& request,
496 const content::MediaResponseCallback& callback,
497 const extensions::Extension* extension) {
498 content::MediaStreamDevices devices;
499 scoped_ptr<content::MediaStreamUI> ui;
500
501 DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE);
502
503 bool loopback_audio_supported = false;
504 #if defined(USE_CRAS) || defined(OS_WIN)
505 // Currently loopback audio capture is supported only on Windows and ChromeOS.
506 loopback_audio_supported = true;
507 #endif
508
509 bool component_extension = false;
510 #if defined(ENABLE_EXTENSIONS)
511 component_extension =
512 extension && extension->location() == extensions::Manifest::COMPONENT;
513 #endif
514
515 bool screen_capture_enabled =
516 base::CommandLine::ForCurrentProcess()->HasSwitch(
517 switches::kEnableUserMediaScreenCapturing);
518 #if defined(ENABLE_EXTENSIONS)
519 screen_capture_enabled |=
520 IsOriginForCasting(request.security_origin) ||
521 IsExtensionWhitelistedForScreenCapture(extension) ||
522 IsBuiltInExtension(request.security_origin);
523 #endif
524
525 const bool origin_is_secure =
526 request.security_origin.SchemeIsSecure() ||
527 request.security_origin.SchemeIs(extensions::kExtensionScheme) ||
528 base::CommandLine::ForCurrentProcess()->HasSwitch(
529 switches::kAllowHttpScreenCapture);
530
531 // If basic conditions (screen capturing is enabled and origin is secure)
532 // aren't fulfilled, we'll use "invalid state" as result. Otherwise, we set
533 // it after checking permission.
534 // TODO(grunell): It would be good to change this result for something else,
535 // probably a new one.
536 content::MediaStreamRequestResult result =
537 content::MEDIA_DEVICE_INVALID_STATE;
538
539 // Approve request only when the following conditions are met:
540 // 1. Screen capturing is enabled via command line switch or white-listed for
541 // the given origin.
542 // 2. Request comes from a page with a secure origin or from an extension.
543 if (screen_capture_enabled && origin_is_secure) {
544 // Get title of the calling application prior to showing the message box.
545 // chrome::ShowMessageBox() starts a nested message loop which may allow
546 // |web_contents| to be destroyed on the UI thread before the message box
547 // is closed. See http://crbug.com/326690.
548 base::string16 application_title =
549 GetApplicationTitle(web_contents, extension);
550 #if !defined(OS_ANDROID)
551 gfx::NativeWindow parent_window =
552 FindParentWindowForWebContents(web_contents);
553 #else
554 gfx::NativeWindow parent_window = NULL;
555 #endif
556 web_contents = NULL;
557
558 bool whitelisted_extension = false;
559 #if defined(ENABLE_EXTENSIONS)
560 whitelisted_extension = IsExtensionWhitelistedForScreenCapture(
561 extension);
562 #endif
563
564 // For whitelisted or component extensions, bypass message box.
565 bool user_approved = false;
566 if (!whitelisted_extension && !component_extension) {
567 base::string16 application_name =
568 base::UTF8ToUTF16(request.security_origin.spec());
569 #if defined(ENABLE_EXTENSIONS)
570 if (extension)
571 application_name = base::UTF8ToUTF16(extension->name());
572 #endif
573 base::string16 confirmation_text = l10n_util::GetStringFUTF16(
574 request.audio_type == content::MEDIA_NO_SERVICE ?
575 IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT :
576 IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT,
577 application_name);
578 chrome::MessageBoxResult result = chrome::ShowMessageBox(
579 parent_window,
580 l10n_util::GetStringFUTF16(
581 IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name),
582 confirmation_text,
583 chrome::MESSAGE_BOX_TYPE_QUESTION);
584 user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES);
585 }
586
587 if (user_approved || component_extension || whitelisted_extension) {
588 content::DesktopMediaID screen_id;
589 #if defined(OS_CHROMEOS)
590 screen_id = content::DesktopMediaID::RegisterAuraWindow(
591 ash::Shell::GetInstance()->GetPrimaryRootWindow());
592 #else // defined(OS_CHROMEOS)
593 screen_id =
594 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
595 webrtc::kFullDesktopScreenId);
596 #endif // !defined(OS_CHROMEOS)
597
598 bool capture_audio =
599 (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
600 loopback_audio_supported);
601
602 // Unless we're being invoked from a component extension, register to
603 // display the notification for stream capture.
604 bool display_notification = !component_extension;
605
606 ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio,
607 display_notification, application_title,
608 application_title);
609 DCHECK(!devices.empty());
610 }
611
612 // The only case when devices can be empty is if the user has denied
613 // permission.
614 result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED
615 : content::MEDIA_DEVICE_OK;
616 }
617
618 callback.Run(devices, result, ui.Pass());
619 }
620
621 void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest(
622 content::WebContents* web_contents,
623 const content::MediaStreamRequest& request,
624 const content::MediaResponseCallback& callback,
625 const extensions::Extension* extension) {
626 content::MediaStreamDevices devices;
627 scoped_ptr<content::MediaStreamUI> ui;
628
629 #if defined(ENABLE_EXTENSIONS)
630 Profile* profile =
631 Profile::FromBrowserContext(web_contents->GetBrowserContext());
632 extensions::TabCaptureRegistry* tab_capture_registry =
633 extensions::TabCaptureRegistry::Get(profile);
634 if (!tab_capture_registry) {
635 NOTREACHED();
636 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
637 return;
638 }
639 const bool tab_capture_allowed = tab_capture_registry->VerifyRequest(
640 request.render_process_id, request.render_frame_id, extension->id());
641
642 if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE &&
643 tab_capture_allowed &&
644 extension->permissions_data()->HasAPIPermission(
645 extensions::APIPermission::kTabCapture)) {
646 devices.push_back(content::MediaStreamDevice(
647 content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string()));
648 }
649
650 if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE &&
651 tab_capture_allowed &&
652 extension->permissions_data()->HasAPIPermission(
653 extensions::APIPermission::kTabCapture)) {
654 devices.push_back(content::MediaStreamDevice(
655 content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string()));
656 }
657
658 if (!devices.empty()) {
659 ui = media_stream_capture_indicator_->RegisterMediaStream(
660 web_contents, devices);
661 }
662 callback.Run(
663 devices,
664 devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE :
665 content::MEDIA_DEVICE_OK,
666 ui.Pass());
667 #else // defined(ENABLE_EXTENSIONS)
668 callback.Run(devices, content::MEDIA_DEVICE_TAB_CAPTURE_FAILURE, ui.Pass());
669 #endif // defined(ENABLE_EXTENSIONS)
670 }
671
672 #if defined(ENABLE_EXTENSIONS)
673 void MediaCaptureDevicesDispatcher::
674 ProcessMediaAccessRequestFromPlatformAppOrExtension(
675 content::WebContents* web_contents,
676 const content::MediaStreamRequest& request,
677 const content::MediaResponseCallback& callback,
678 const extensions::Extension* extension) {
679 // TODO(vrk): This code is largely duplicated in
680 // MediaStreamDevicesController::Accept(). Move this code into a shared method
681 // between the two classes.
682
683 Profile* profile =
684 Profile::FromBrowserContext(web_contents->GetBrowserContext());
685
686 bool audio_allowed =
687 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
688 extension->permissions_data()->HasAPIPermission(
689 extensions::APIPermission::kAudioCapture) &&
690 GetDevicePolicy(profile, extension->url(),
691 prefs::kAudioCaptureAllowed,
692 prefs::kAudioCaptureAllowedUrls) != ALWAYS_DENY;
693 bool video_allowed =
694 request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
695 extension->permissions_data()->HasAPIPermission(
696 extensions::APIPermission::kVideoCapture) &&
697 GetDevicePolicy(profile, extension->url(),
698 prefs::kVideoCaptureAllowed,
699 prefs::kVideoCaptureAllowedUrls) != ALWAYS_DENY;
700
701 bool get_default_audio_device = audio_allowed;
702 bool get_default_video_device = video_allowed;
703
704 content::MediaStreamDevices devices;
705
706 // Set an initial error result. If neither audio or video is allowed, we'll
707 // never try to get any device below but will just create |ui| and return an
708 // empty list with "invalid state" result. If at least one is allowed, we'll
709 // try to get device(s), and if failure, we want to return "no hardware"
710 // result.
711 // TODO(grunell): The invalid state result should be changed to a new denied
712 // result + a dcheck to ensure at least one of audio or video types is
713 // capture.
714 content::MediaStreamRequestResult result =
715 (audio_allowed || video_allowed) ? content::MEDIA_DEVICE_NO_HARDWARE
716 : content::MEDIA_DEVICE_INVALID_STATE;
717
718 // Get the exact audio or video device if an id is specified.
719 // We only set any error result here and before running the callback change
720 // it to OK if we have any device.
721 if (audio_allowed && !request.requested_audio_device_id.empty()) {
722 const content::MediaStreamDevice* audio_device =
723 GetRequestedAudioDevice(request.requested_audio_device_id);
724 if (audio_device) {
725 devices.push_back(*audio_device);
726 get_default_audio_device = false;
727 } 195 }
728 } 196 }
729 if (video_allowed && !request.requested_video_device_id.empty()) { 197 return false;
730 const content::MediaStreamDevice* video_device =
731 GetRequestedVideoDevice(request.requested_video_device_id);
732 if (video_device) {
733 devices.push_back(*video_device);
734 get_default_video_device = false;
735 }
736 }
737
738 // If either or both audio and video devices were requested but not
739 // specified by id, get the default devices.
740 if (get_default_audio_device || get_default_video_device) {
741 GetDefaultDevicesForProfile(profile,
742 get_default_audio_device,
743 get_default_video_device,
744 &devices);
745 }
746
747 scoped_ptr<content::MediaStreamUI> ui;
748 if (!devices.empty()) {
749 result = content::MEDIA_DEVICE_OK;
750 ui = media_stream_capture_indicator_->RegisterMediaStream(
751 web_contents, devices);
752 }
753
754 callback.Run(devices, result, ui.Pass());
755 }
756 #endif
757
758 void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest(
759 content::WebContents* web_contents,
760 const content::MediaStreamRequest& request,
761 const content::MediaResponseCallback& callback) {
762 DCHECK_CURRENTLY_ON(BrowserThread::UI);
763
764 RequestsQueue& queue = pending_requests_[web_contents];
765 queue.push_back(PendingAccessRequest(request, callback));
766
767 // If this is the only request then show the infobar.
768 if (queue.size() == 1)
769 ProcessQueuedAccessRequest(web_contents);
770 }
771
772 void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(
773 content::WebContents* web_contents) {
774 DCHECK_CURRENTLY_ON(BrowserThread::UI);
775
776 std::map<content::WebContents*, RequestsQueue>::iterator it =
777 pending_requests_.find(web_contents);
778
779 if (it == pending_requests_.end() || it->second.empty()) {
780 // Don't do anything if the tab was closed.
781 return;
782 }
783
784 DCHECK(!it->second.empty());
785
786 if (PermissionBubbleManager::Enabled() ||
787 MediaStreamPermissionBubbleExperimentEnabled()) {
788 scoped_ptr<MediaStreamDevicesController> controller(
789 new MediaStreamDevicesController(web_contents,
790 it->second.front().request,
791 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse,
792 base::Unretained(this), web_contents)));
793 if (controller->DismissInfoBarAndTakeActionOnSettings())
794 return;
795 PermissionBubbleManager* bubble_manager =
796 PermissionBubbleManager::FromWebContents(web_contents);
797 if (bubble_manager)
798 bubble_manager->AddRequest(controller.release());
799 return;
800 }
801
802 // TODO(gbillock): delete this block and the MediaStreamInfoBarDelegate
803 // when we've transitioned to bubbles. (crbug/337458)
804 MediaStreamInfoBarDelegate::Create(
805 web_contents, it->second.front().request,
806 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse,
807 base::Unretained(this), web_contents));
808 }
809
810 void MediaCaptureDevicesDispatcher::OnAccessRequestResponse(
811 content::WebContents* web_contents,
812 const content::MediaStreamDevices& devices,
813 content::MediaStreamRequestResult result,
814 scoped_ptr<content::MediaStreamUI> ui) {
815 DCHECK_CURRENTLY_ON(BrowserThread::UI);
816
817 std::map<content::WebContents*, RequestsQueue>::iterator it =
818 pending_requests_.find(web_contents);
819 if (it == pending_requests_.end()) {
820 // WebContents has been destroyed. Don't need to do anything.
821 return;
822 }
823
824 RequestsQueue& queue(it->second);
825 if (queue.empty())
826 return;
827
828 content::MediaResponseCallback callback = queue.front().callback;
829 queue.pop_front();
830
831 if (!queue.empty()) {
832 // Post a task to process next queued request. It has to be done
833 // asynchronously to make sure that calling infobar is not destroyed until
834 // after this function returns.
835 BrowserThread::PostTask(
836 BrowserThread::UI, FROM_HERE,
837 base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest,
838 base::Unretained(this), web_contents));
839 }
840
841 callback.Run(devices, result, ui.Pass());
842 } 198 }
843 199
844 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( 200 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile(
845 Profile* profile, 201 Profile* profile,
846 bool audio, 202 bool audio,
847 bool video, 203 bool video,
848 content::MediaStreamDevices* devices) { 204 content::MediaStreamDevices* devices) {
849 DCHECK_CURRENTLY_ON(BrowserThread::UI); 205 DCHECK_CURRENTLY_ON(BrowserThread::UI);
850 DCHECK(audio || video); 206 DCHECK(audio || video);
851 207
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
983 OnUpdateVideoDevices(devices)); 339 OnUpdateVideoDevices(devices));
984 } 340 }
985 341
986 void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread( 342 void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread(
987 int render_process_id, 343 int render_process_id,
988 int render_frame_id, 344 int render_frame_id,
989 int page_request_id, 345 int page_request_id,
990 const GURL& security_origin, 346 const GURL& security_origin,
991 content::MediaStreamType stream_type, 347 content::MediaStreamType stream_type,
992 content::MediaRequestState state) { 348 content::MediaRequestState state) {
993 // Track desktop capture sessions. Tracking is necessary to avoid unbalanced 349 for (MediaAccessHandler* handler : media_access_handlers_) {
994 // session counts since not all requests will reach MEDIA_REQUEST_STATE_DONE, 350 if (handler->SupportsStreamType(stream_type, nullptr)) {
995 // but they will all reach MEDIA_REQUEST_STATE_CLOSING. 351 handler->UpdateMediaRequestState(render_process_id, render_frame_id,
996 if (stream_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) { 352 page_request_id, stream_type, state);
997 if (state == content::MEDIA_REQUEST_STATE_DONE) { 353 return;
Sergey Ulanov 2015/06/03 22:31:58 this should be break, not return.
changbin 2015/06/05 06:40:33 Done.
998 DesktopCaptureSession session = { render_process_id, render_frame_id,
999 page_request_id };
1000 desktop_capture_sessions_.push_back(session);
1001 } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
1002 for (DesktopCaptureSessions::iterator it =
1003 desktop_capture_sessions_.begin();
1004 it != desktop_capture_sessions_.end();
1005 ++it) {
1006 if (it->render_process_id == render_process_id &&
1007 it->render_frame_id == render_frame_id &&
1008 it->page_request_id == page_request_id) {
1009 desktop_capture_sessions_.erase(it);
1010 break;
1011 }
1012 }
1013 } 354 }
1014 } 355 }
1015 356
1016 // Cancel the request.
1017 if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
1018 bool found = false;
1019 for (RequestsQueues::iterator rqs_it = pending_requests_.begin();
1020 rqs_it != pending_requests_.end(); ++rqs_it) {
1021 RequestsQueue& queue = rqs_it->second;
1022 for (RequestsQueue::iterator it = queue.begin();
1023 it != queue.end(); ++it) {
1024 if (it->request.render_process_id == render_process_id &&
1025 it->request.render_frame_id == render_frame_id &&
1026 it->request.page_request_id == page_request_id) {
1027 queue.erase(it);
1028 found = true;
1029 break;
1030 }
1031 }
1032 if (found)
1033 break;
1034 }
1035 }
1036
1037 #if defined(OS_CHROMEOS) 357 #if defined(OS_CHROMEOS)
1038 if (IsOriginForCasting(security_origin) && IsVideoMediaType(stream_type)) { 358 if (IsOriginForCasting(security_origin) && IsVideoMediaType(stream_type)) {
1039 // Notify ash that casting state has changed. 359 // Notify ash that casting state has changed.
1040 if (state == content::MEDIA_REQUEST_STATE_DONE) { 360 if (state == content::MEDIA_REQUEST_STATE_DONE) {
1041 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(true); 361 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(true);
1042 } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) { 362 } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
1043 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(false); 363 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(false);
1044 } 364 }
1045 } 365 }
1046 #endif 366 #endif
1047 367
1048 FOR_EACH_OBSERVER(Observer, observers_, 368 FOR_EACH_OBSERVER(Observer, observers_,
1049 OnRequestUpdate(render_process_id, 369 OnRequestUpdate(render_process_id,
1050 render_frame_id, 370 render_frame_id,
1051 stream_type, 371 stream_type,
1052 state)); 372 state));
1053 } 373 }
1054 374
1055 void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread( 375 void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread(
1056 int render_process_id, 376 int render_process_id,
1057 int render_frame_id) { 377 int render_frame_id) {
1058 DCHECK_CURRENTLY_ON(BrowserThread::UI); 378 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1059 FOR_EACH_OBSERVER(Observer, observers_, 379 FOR_EACH_OBSERVER(Observer, observers_,
1060 OnCreatingAudioStream(render_process_id, render_frame_id)); 380 OnCreatingAudioStream(render_process_id, render_frame_id));
1061 } 381 }
1062 382
1063 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() { 383 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() {
1064 DCHECK_CURRENTLY_ON(BrowserThread::UI); 384 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1065 return desktop_capture_sessions_.size() > 0; 385 for (MediaAccessHandler* handler : media_access_handlers_) {
386 if (handler->SupportsStreamType(content::MEDIA_DESKTOP_VIDEO_CAPTURE,
387 NULL)) {
388 return ToDesktopCaptureAccessHandler(handler)->IsCaptureInProgress();
389 }
390 }
391 return false;
1066 } 392 }
1067 393
1068 void MediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices( 394 void MediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices(
1069 const MediaStreamDevices& devices) { 395 const MediaStreamDevices& devices) {
1070 test_audio_devices_ = devices; 396 test_audio_devices_ = devices;
1071 } 397 }
1072 398
1073 void MediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices( 399 void MediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices(
1074 const MediaStreamDevices& devices) { 400 const MediaStreamDevices& devices) {
1075 test_video_devices_ = devices; 401 test_video_devices_ = devices;
1076 } 402 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698