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

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

Issue 2307083002: Cleanup: move WebRTC related files from chrome/browser/media to chrome/browser/media/webrtc/ (Closed)
Patch Set: Removed file wrongly resuscitated during rebase Created 4 years, 3 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
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/desktop_capture_access_handler.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/media/desktop_streams_registry.h"
15 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_finder.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/screen_capture_notification_ui.h"
20 #include "chrome/browser/ui/simple_message_box.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/desktop_media_id.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/media_stream_request.h"
29 #include "content/public/common/origin_util.h"
30 #include "extensions/browser/app_window/app_window.h"
31 #include "extensions/browser/app_window/app_window_registry.h"
32 #include "extensions/common/constants.h"
33 #include "extensions/common/extension.h"
34 #include "extensions/common/switches.h"
35 #include "media/audio/audio_device_description.h"
36 #include "net/base/url_util.h"
37 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
38 #include "ui/base/l10n/l10n_util.h"
39
40 #if defined(OS_CHROMEOS)
41 #include "ash/shell.h"
42 #endif // defined(OS_CHROMEOS)
43
44 using content::BrowserThread;
45
46 namespace {
47
48 // Helper to get title of the calling application shown in the screen capture
49 // notification.
50 base::string16 GetApplicationTitle(content::WebContents* web_contents,
51 const extensions::Extension* extension) {
52 // Use extension name as title for extensions and host/origin for drive-by
53 // web.
54 std::string title;
55 if (extension) {
56 title = extension->name();
57 return base::UTF8ToUTF16(title);
58 }
59 GURL url = web_contents->GetURL();
60 title = content::IsOriginSecure(url) ? net::GetHostAndOptionalPort(url)
61 : url.GetOrigin().spec();
62 return base::UTF8ToUTF16(title);
63 }
64
65 base::string16 GetStopSharingUIString(
66 const base::string16& application_title,
67 const base::string16& registered_extension_name,
68 bool capture_audio,
69 content::DesktopMediaID::Type capture_type) {
70 if (!capture_audio) {
71 if (application_title == registered_extension_name) {
72 switch (capture_type) {
73 case content::DesktopMediaID::TYPE_SCREEN:
74 return l10n_util::GetStringFUTF16(
75 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, application_title);
76 case content::DesktopMediaID::TYPE_WINDOW:
77 return l10n_util::GetStringFUTF16(
78 IDS_MEDIA_WINDOW_CAPTURE_NOTIFICATION_TEXT, application_title);
79 case content::DesktopMediaID::TYPE_WEB_CONTENTS:
80 return l10n_util::GetStringFUTF16(
81 IDS_MEDIA_TAB_CAPTURE_NOTIFICATION_TEXT, application_title);
82 case content::DesktopMediaID::TYPE_NONE:
83 NOTREACHED();
84 }
85 } else {
86 switch (capture_type) {
87 case content::DesktopMediaID::TYPE_SCREEN:
88 return l10n_util::GetStringFUTF16(
89 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
90 registered_extension_name, application_title);
91 case content::DesktopMediaID::TYPE_WINDOW:
92 return l10n_util::GetStringFUTF16(
93 IDS_MEDIA_WINDOW_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
94 registered_extension_name, application_title);
95 case content::DesktopMediaID::TYPE_WEB_CONTENTS:
96 return l10n_util::GetStringFUTF16(
97 IDS_MEDIA_TAB_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
98 registered_extension_name, application_title);
99 case content::DesktopMediaID::TYPE_NONE:
100 NOTREACHED();
101 }
102 }
103 } else { // The case with audio
104 if (application_title == registered_extension_name) {
105 switch (capture_type) {
106 case content::DesktopMediaID::TYPE_SCREEN:
107 return l10n_util::GetStringFUTF16(
108 IDS_MEDIA_SCREEN_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT,
109 application_title);
110 case content::DesktopMediaID::TYPE_WEB_CONTENTS:
111 return l10n_util::GetStringFUTF16(
112 IDS_MEDIA_TAB_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT,
113 application_title);
114 case content::DesktopMediaID::TYPE_NONE:
115 case content::DesktopMediaID::TYPE_WINDOW:
116 NOTREACHED();
117 }
118 } else {
119 switch (capture_type) {
120 case content::DesktopMediaID::TYPE_SCREEN:
121 return l10n_util::GetStringFUTF16(
122 IDS_MEDIA_SCREEN_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT_DELEGATED,
123 registered_extension_name, application_title);
124 case content::DesktopMediaID::TYPE_WEB_CONTENTS:
125 return l10n_util::GetStringFUTF16(
126 IDS_MEDIA_TAB_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT_DELEGATED,
127 registered_extension_name, application_title);
128 case content::DesktopMediaID::TYPE_NONE:
129 case content::DesktopMediaID::TYPE_WINDOW:
130 NOTREACHED();
131 }
132 }
133 }
134 return base::string16();
135 }
136 // Helper to get list of media stream devices for desktop capture in |devices|.
137 // Registers to display notification if |display_notification| is true.
138 // Returns an instance of MediaStreamUI to be passed to content layer.
139 std::unique_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
140 content::MediaStreamDevices* devices,
141 content::DesktopMediaID media_id,
142 bool capture_audio,
143 bool mute_system_audio,
144 bool display_notification,
145 const base::string16& application_title,
146 const base::string16& registered_extension_name) {
147 DCHECK_CURRENTLY_ON(BrowserThread::UI);
148 std::unique_ptr<content::MediaStreamUI> ui;
149
150 // Add selected desktop source to the list.
151 devices->push_back(content::MediaStreamDevice(
152 content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen"));
153 if (capture_audio) {
154 if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
155 devices->push_back(
156 content::MediaStreamDevice(content::MEDIA_DESKTOP_AUDIO_CAPTURE,
157 media_id.ToString(), "Tab audio"));
158 } else if (mute_system_audio) {
159 // Use the special loopback device ID for system audio capture.
160 devices->push_back(content::MediaStreamDevice(
161 content::MEDIA_DESKTOP_AUDIO_CAPTURE,
162 media::AudioDeviceDescription::kLoopbackWithMuteDeviceId,
163 "System Audio"));
164 } else {
165 // Use the special loopback device ID for system audio capture.
166 devices->push_back(content::MediaStreamDevice(
167 content::MEDIA_DESKTOP_AUDIO_CAPTURE,
168 media::AudioDeviceDescription::kLoopbackInputDeviceId,
169 "System Audio"));
170 }
171 }
172
173 // If required, register to display the notification for stream capture.
174 if (!display_notification) {
175 return ui;
176 }
177
178 ui = ScreenCaptureNotificationUI::Create(GetStopSharingUIString(
179 application_title, registered_extension_name, capture_audio,
180 media_id.type));
181
182 return ui;
183 }
184
185 #if !defined(OS_ANDROID)
186 // Find browser or app window from a given |web_contents|.
187 gfx::NativeWindow FindParentWindowForWebContents(
188 content::WebContents* web_contents) {
189 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
190 if (browser && browser->window())
191 return browser->window()->GetNativeWindow();
192
193 const extensions::AppWindowRegistry::AppWindowList& window_list =
194 extensions::AppWindowRegistry::Get(web_contents->GetBrowserContext())
195 ->app_windows();
196 for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter =
197 window_list.begin();
198 iter != window_list.end(); ++iter) {
199 if ((*iter)->web_contents() == web_contents)
200 return (*iter)->GetNativeWindow();
201 }
202
203 return NULL;
204 }
205 #endif
206
207 } // namespace
208
209 DesktopCaptureAccessHandler::DesktopCaptureAccessHandler() {
210 }
211
212 DesktopCaptureAccessHandler::~DesktopCaptureAccessHandler() {
213 }
214
215 void DesktopCaptureAccessHandler::ProcessScreenCaptureAccessRequest(
216 content::WebContents* web_contents,
217 const content::MediaStreamRequest& request,
218 const content::MediaResponseCallback& callback,
219 const extensions::Extension* extension) {
220 content::MediaStreamDevices devices;
221 std::unique_ptr<content::MediaStreamUI> ui;
222
223 DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE);
224
225 UpdateExtensionTrusted(request, extension);
226
227 bool loopback_audio_supported = false;
228 #if defined(USE_CRAS) || defined(OS_WIN)
229 // Currently loopback audio capture is supported only on Windows and ChromeOS.
230 loopback_audio_supported = true;
231 #endif
232
233 bool component_extension = false;
234 component_extension =
235 extension && extension->location() == extensions::Manifest::COMPONENT;
236
237 bool screen_capture_enabled =
238 base::CommandLine::ForCurrentProcess()->HasSwitch(
239 switches::kEnableUserMediaScreenCapturing) ||
240 MediaCaptureDevicesDispatcher::IsOriginForCasting(
241 request.security_origin) ||
242 IsExtensionWhitelistedForScreenCapture(extension) ||
243 IsBuiltInExtension(request.security_origin);
244
245 const bool origin_is_secure =
246 content::IsOriginSecure(request.security_origin) ||
247 base::CommandLine::ForCurrentProcess()->HasSwitch(
248 switches::kAllowHttpScreenCapture);
249
250 // If basic conditions (screen capturing is enabled and origin is secure)
251 // aren't fulfilled, we'll use "invalid state" as result. Otherwise, we set
252 // it after checking permission.
253 // TODO(grunell): It would be good to change this result for something else,
254 // probably a new one.
255 content::MediaStreamRequestResult result =
256 content::MEDIA_DEVICE_INVALID_STATE;
257
258 // Approve request only when the following conditions are met:
259 // 1. Screen capturing is enabled via command line switch or white-listed for
260 // the given origin.
261 // 2. Request comes from a page with a secure origin or from an extension.
262 if (screen_capture_enabled && origin_is_secure) {
263 // Get title of the calling application prior to showing the message box.
264 // chrome::ShowQuestionMessageBox() starts a nested message loop which may
265 // allow |web_contents| to be destroyed on the UI thread before the messag
266 // box is closed. See http://crbug.com/326690.
267 base::string16 application_title =
268 GetApplicationTitle(web_contents, extension);
269 #if !defined(OS_ANDROID)
270 gfx::NativeWindow parent_window =
271 FindParentWindowForWebContents(web_contents);
272 #else
273 gfx::NativeWindow parent_window = NULL;
274 #endif
275 web_contents = NULL;
276
277 bool whitelisted_extension =
278 IsExtensionWhitelistedForScreenCapture(extension);
279
280 // For whitelisted or component extensions, bypass message box.
281 bool user_approved = false;
282 if (!whitelisted_extension && !component_extension) {
283 base::string16 application_name =
284 base::UTF8ToUTF16(request.security_origin.spec());
285 if (extension)
286 application_name = base::UTF8ToUTF16(extension->name());
287 base::string16 confirmation_text = l10n_util::GetStringFUTF16(
288 request.audio_type == content::MEDIA_NO_SERVICE
289 ? IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT
290 : IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT,
291 application_name);
292 chrome::MessageBoxResult result = chrome::ShowQuestionMessageBox(
293 parent_window,
294 l10n_util::GetStringFUTF16(
295 IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name),
296 confirmation_text);
297 user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES);
298 }
299
300 if (user_approved || component_extension || whitelisted_extension) {
301 content::DesktopMediaID screen_id;
302 #if defined(OS_CHROMEOS)
303 screen_id = content::DesktopMediaID::RegisterAuraWindow(
304 content::DesktopMediaID::TYPE_SCREEN,
305 ash::Shell::GetInstance()->GetPrimaryRootWindow());
306 #else // defined(OS_CHROMEOS)
307 screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
308 webrtc::kFullDesktopScreenId);
309 #endif // !defined(OS_CHROMEOS)
310
311 bool capture_audio =
312 (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
313 loopback_audio_supported);
314
315 // Unless we're being invoked from a component extension, register to
316 // display the notification for stream capture.
317 bool display_notification = !component_extension;
318
319 ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio, true,
320 display_notification, application_title,
321 application_title);
322 DCHECK(!devices.empty());
323 }
324
325 // The only case when devices can be empty is if the user has denied
326 // permission.
327 result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED
328 : content::MEDIA_DEVICE_OK;
329 }
330
331 callback.Run(devices, result, std::move(ui));
332 }
333
334 bool DesktopCaptureAccessHandler::SupportsStreamType(
335 const content::MediaStreamType type,
336 const extensions::Extension* extension) {
337 return type == content::MEDIA_DESKTOP_VIDEO_CAPTURE ||
338 type == content::MEDIA_DESKTOP_AUDIO_CAPTURE;
339 }
340
341 bool DesktopCaptureAccessHandler::CheckMediaAccessPermission(
342 content::WebContents* web_contents,
343 const GURL& security_origin,
344 content::MediaStreamType type,
345 const extensions::Extension* extension) {
346 return false;
347 }
348
349 void DesktopCaptureAccessHandler::HandleRequest(
350 content::WebContents* web_contents,
351 const content::MediaStreamRequest& request,
352 const content::MediaResponseCallback& callback,
353 const extensions::Extension* extension) {
354 content::MediaStreamDevices devices;
355 std::unique_ptr<content::MediaStreamUI> ui;
356
357 if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
358 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, std::move(ui));
359 return;
360 }
361
362 // If the device id wasn't specified then this is a screen capture request
363 // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
364 if (request.requested_video_device_id.empty()) {
365 ProcessScreenCaptureAccessRequest(web_contents, request, callback,
366 extension);
367 return;
368 }
369
370 // The extension name that the stream is registered with.
371 std::string original_extension_name;
372 // Resolve DesktopMediaID for the specified device id.
373 content::DesktopMediaID media_id;
374 // TODO(miu): Replace "main RenderFrame" IDs with the request's actual
375 // RenderFrame IDs once the desktop capture extension API implementation is
376 // fixed. http://crbug.com/304341
377 content::WebContents* const web_contents_for_stream =
378 content::WebContents::FromRenderFrameHost(
379 content::RenderFrameHost::FromID(request.render_process_id,
380 request.render_frame_id));
381 content::RenderFrameHost* const main_frame =
382 web_contents_for_stream ? web_contents_for_stream->GetMainFrame() : NULL;
383 if (main_frame) {
384 media_id = MediaCaptureDevicesDispatcher::GetInstance()
385 ->GetDesktopStreamsRegistry()
386 ->RequestMediaForStreamId(request.requested_video_device_id,
387 main_frame->GetProcess()->GetID(),
388 main_frame->GetRoutingID(),
389 request.security_origin,
390 &original_extension_name);
391 }
392
393 // Received invalid device id.
394 if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
395 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, std::move(ui));
396 return;
397 }
398
399 bool loopback_audio_supported = false;
400 #if defined(USE_CRAS) || defined(OS_WIN)
401 // Currently loopback audio capture is supported only on Windows and ChromeOS.
402 loopback_audio_supported = true;
403 #endif
404
405 // This value essentially from the checkbox on picker window, so it
406 // corresponds to user permission.
407 const bool audio_permitted = media_id.audio_share;
408
409 // This value essentially from whether getUserMedia requests audio stream.
410 const bool audio_requested =
411 request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE;
412
413 // This value shows for a given capture type, whether the system or our code
414 // can support audio sharing. Currently audio is only supported for screen and
415 // tab/webcontents capture streams.
416 const bool audio_supported =
417 (media_id.type == content::DesktopMediaID::TYPE_SCREEN &&
418 loopback_audio_supported) ||
419 media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS;
420
421 const bool check_audio_permission =
422 !base::CommandLine::ForCurrentProcess()->HasSwitch(
423 extensions::switches::kDisableDesktopCaptureAudio);
424 const bool capture_audio =
425 (check_audio_permission ? audio_permitted : true) && audio_requested &&
426 audio_supported;
427
428 ui = GetDevicesForDesktopCapture(&devices, media_id, capture_audio, false,
429 true,
430 GetApplicationTitle(web_contents, extension),
431 base::UTF8ToUTF16(original_extension_name));
432 UpdateExtensionTrusted(request, extension);
433 callback.Run(devices, content::MEDIA_DEVICE_OK, std::move(ui));
434 }
435
OLDNEW
« no previous file with comments | « chrome/browser/media/desktop_capture_access_handler.h ('k') | chrome/browser/media/desktop_media_list.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698