| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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/webrtc/desktop_capture_access_handler.h" | 5 #include "chrome/browser/media/webrtc/desktop_capture_access_handler.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 if (extension) { | 55 if (extension) { |
| 56 title = extension->name(); | 56 title = extension->name(); |
| 57 return base::UTF8ToUTF16(title); | 57 return base::UTF8ToUTF16(title); |
| 58 } | 58 } |
| 59 GURL url = web_contents->GetURL(); | 59 GURL url = web_contents->GetURL(); |
| 60 title = content::IsOriginSecure(url) ? net::GetHostAndOptionalPort(url) | 60 title = content::IsOriginSecure(url) ? net::GetHostAndOptionalPort(url) |
| 61 : url.GetOrigin().spec(); | 61 : url.GetOrigin().spec(); |
| 62 return base::UTF8ToUTF16(title); | 62 return base::UTF8ToUTF16(title); |
| 63 } | 63 } |
| 64 | 64 |
| 65 // Returns whether an on-screen notification should appear after desktop capture |
| 66 // is approved for |extension|. Component extensions do not display a |
| 67 // notification. |
| 68 bool ShouldDisplayNotification(const extensions::Extension* extension) { |
| 69 return !(extension && |
| 70 (extension->location() == extensions::Manifest::COMPONENT || |
| 71 extension->location() == extensions::Manifest::EXTERNAL_COMPONENT)); |
| 72 } |
| 73 |
| 65 base::string16 GetStopSharingUIString( | 74 base::string16 GetStopSharingUIString( |
| 66 const base::string16& application_title, | 75 const base::string16& application_title, |
| 67 const base::string16& registered_extension_name, | 76 const base::string16& registered_extension_name, |
| 68 bool capture_audio, | 77 bool capture_audio, |
| 69 content::DesktopMediaID::Type capture_type) { | 78 content::DesktopMediaID::Type capture_type) { |
| 70 if (!capture_audio) { | 79 if (!capture_audio) { |
| 71 if (application_title == registered_extension_name) { | 80 if (application_title == registered_extension_name) { |
| 72 switch (capture_type) { | 81 switch (capture_type) { |
| 73 case content::DesktopMediaID::TYPE_SCREEN: | 82 case content::DesktopMediaID::TYPE_SCREEN: |
| 74 return l10n_util::GetStringFUTF16( | 83 return l10n_util::GetStringFUTF16( |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 content::MediaStreamDevices* devices, | 149 content::MediaStreamDevices* devices, |
| 141 content::DesktopMediaID media_id, | 150 content::DesktopMediaID media_id, |
| 142 bool capture_audio, | 151 bool capture_audio, |
| 143 bool mute_system_audio, | 152 bool mute_system_audio, |
| 144 bool display_notification, | 153 bool display_notification, |
| 145 const base::string16& application_title, | 154 const base::string16& application_title, |
| 146 const base::string16& registered_extension_name) { | 155 const base::string16& registered_extension_name) { |
| 147 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 156 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 148 std::unique_ptr<content::MediaStreamUI> ui; | 157 std::unique_ptr<content::MediaStreamUI> ui; |
| 149 | 158 |
| 159 DVLOG(2) << __FUNCTION__ << ": media_id " << media_id.ToString() |
| 160 << ", capture_audio " << capture_audio << ", mute_system_audio " |
| 161 << mute_system_audio << ", display_notification " |
| 162 << display_notification << ", application_title " |
| 163 << application_title << ", extension_name " |
| 164 << registered_extension_name; |
| 165 |
| 150 // Add selected desktop source to the list. | 166 // Add selected desktop source to the list. |
| 151 devices->push_back(content::MediaStreamDevice( | 167 devices->push_back(content::MediaStreamDevice( |
| 152 content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); | 168 content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); |
| 153 if (capture_audio) { | 169 if (capture_audio) { |
| 154 if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { | 170 if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { |
| 155 devices->push_back( | 171 devices->push_back( |
| 156 content::MediaStreamDevice(content::MEDIA_DESKTOP_AUDIO_CAPTURE, | 172 content::MediaStreamDevice(content::MEDIA_DESKTOP_AUDIO_CAPTURE, |
| 157 media_id.ToString(), "Tab audio")); | 173 media_id.ToString(), "Tab audio")); |
| 158 } else if (mute_system_audio) { | 174 } else if (mute_system_audio) { |
| 159 // Use the special loopback device ID for system audio capture. | 175 // Use the special loopback device ID for system audio capture. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE); | 239 DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE); |
| 224 | 240 |
| 225 UpdateExtensionTrusted(request, extension); | 241 UpdateExtensionTrusted(request, extension); |
| 226 | 242 |
| 227 bool loopback_audio_supported = false; | 243 bool loopback_audio_supported = false; |
| 228 #if defined(USE_CRAS) || defined(OS_WIN) | 244 #if defined(USE_CRAS) || defined(OS_WIN) |
| 229 // Currently loopback audio capture is supported only on Windows and ChromeOS. | 245 // Currently loopback audio capture is supported only on Windows and ChromeOS. |
| 230 loopback_audio_supported = true; | 246 loopback_audio_supported = true; |
| 231 #endif | 247 #endif |
| 232 | 248 |
| 233 bool component_extension = false; | |
| 234 component_extension = | |
| 235 extension && extension->location() == extensions::Manifest::COMPONENT; | |
| 236 | |
| 237 bool screen_capture_enabled = | 249 bool screen_capture_enabled = |
| 238 base::CommandLine::ForCurrentProcess()->HasSwitch( | 250 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 239 switches::kEnableUserMediaScreenCapturing) || | 251 switches::kEnableUserMediaScreenCapturing) || |
| 240 MediaCaptureDevicesDispatcher::IsOriginForCasting( | 252 MediaCaptureDevicesDispatcher::IsOriginForCasting( |
| 241 request.security_origin) || | 253 request.security_origin) || |
| 242 IsExtensionWhitelistedForScreenCapture(extension) || | 254 IsExtensionWhitelistedForScreenCapture(extension) || |
| 243 IsBuiltInExtension(request.security_origin); | 255 IsBuiltInExtension(request.security_origin); |
| 244 | 256 |
| 245 const bool origin_is_secure = | 257 const bool origin_is_secure = |
| 246 content::IsOriginSecure(request.security_origin) || | 258 content::IsOriginSecure(request.security_origin) || |
| (...skipping 20 matching lines...) Expand all Loading... |
| 267 base::string16 application_title = | 279 base::string16 application_title = |
| 268 GetApplicationTitle(web_contents, extension); | 280 GetApplicationTitle(web_contents, extension); |
| 269 #if !defined(OS_ANDROID) | 281 #if !defined(OS_ANDROID) |
| 270 gfx::NativeWindow parent_window = | 282 gfx::NativeWindow parent_window = |
| 271 FindParentWindowForWebContents(web_contents); | 283 FindParentWindowForWebContents(web_contents); |
| 272 #else | 284 #else |
| 273 gfx::NativeWindow parent_window = NULL; | 285 gfx::NativeWindow parent_window = NULL; |
| 274 #endif | 286 #endif |
| 275 web_contents = NULL; | 287 web_contents = NULL; |
| 276 | 288 |
| 277 bool whitelisted_extension = | 289 // Some extensions do not require user approval, because they provide their |
| 278 IsExtensionWhitelistedForScreenCapture(extension); | 290 // own user approval UI. |
| 279 | 291 bool is_approved = IsDefaultApproved(extension); |
| 280 // For whitelisted or component extensions, bypass message box. | 292 if (!is_approved) { |
| 281 bool user_approved = false; | |
| 282 if (!whitelisted_extension && !component_extension) { | |
| 283 base::string16 application_name = | 293 base::string16 application_name = |
| 284 base::UTF8ToUTF16(request.security_origin.spec()); | 294 base::UTF8ToUTF16(request.security_origin.spec()); |
| 285 if (extension) | 295 if (extension) |
| 286 application_name = base::UTF8ToUTF16(extension->name()); | 296 application_name = base::UTF8ToUTF16(extension->name()); |
| 287 base::string16 confirmation_text = l10n_util::GetStringFUTF16( | 297 base::string16 confirmation_text = l10n_util::GetStringFUTF16( |
| 288 request.audio_type == content::MEDIA_NO_SERVICE | 298 request.audio_type == content::MEDIA_NO_SERVICE |
| 289 ? IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT | 299 ? IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT |
| 290 : IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT, | 300 : IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT, |
| 291 application_name); | 301 application_name); |
| 292 chrome::MessageBoxResult result = chrome::ShowQuestionMessageBox( | 302 chrome::MessageBoxResult result = chrome::ShowQuestionMessageBox( |
| 293 parent_window, | 303 parent_window, |
| 294 l10n_util::GetStringFUTF16( | 304 l10n_util::GetStringFUTF16( |
| 295 IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name), | 305 IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name), |
| 296 confirmation_text); | 306 confirmation_text); |
| 297 user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES); | 307 is_approved = (result == chrome::MESSAGE_BOX_RESULT_YES); |
| 298 } | 308 } |
| 299 | 309 |
| 300 if (user_approved || component_extension || whitelisted_extension) { | 310 if (is_approved) { |
| 301 content::DesktopMediaID screen_id; | 311 content::DesktopMediaID screen_id; |
| 302 #if defined(OS_CHROMEOS) | 312 #if defined(OS_CHROMEOS) |
| 303 screen_id = content::DesktopMediaID::RegisterAuraWindow( | 313 screen_id = content::DesktopMediaID::RegisterAuraWindow( |
| 304 content::DesktopMediaID::TYPE_SCREEN, | 314 content::DesktopMediaID::TYPE_SCREEN, |
| 305 ash::Shell::GetInstance()->GetPrimaryRootWindow()); | 315 ash::Shell::GetInstance()->GetPrimaryRootWindow()); |
| 306 #else // defined(OS_CHROMEOS) | 316 #else // defined(OS_CHROMEOS) |
| 307 screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, | 317 screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, |
| 308 webrtc::kFullDesktopScreenId); | 318 webrtc::kFullDesktopScreenId); |
| 309 #endif // !defined(OS_CHROMEOS) | 319 #endif // !defined(OS_CHROMEOS) |
| 310 | 320 |
| 311 bool capture_audio = | 321 bool capture_audio = |
| 312 (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE && | 322 (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE && |
| 313 loopback_audio_supported); | 323 loopback_audio_supported); |
| 314 | 324 |
| 315 // Unless we're being invoked from a component extension, register to | 325 // Determine if the extension is required to display a notification. |
| 316 // display the notification for stream capture. | 326 const bool display_notification = ShouldDisplayNotification(extension); |
| 317 bool display_notification = !component_extension; | |
| 318 | 327 |
| 319 ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio, true, | 328 ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio, true, |
| 320 display_notification, application_title, | 329 display_notification, application_title, |
| 321 application_title); | 330 application_title); |
| 322 DCHECK(!devices.empty()); | 331 DCHECK(!devices.empty()); |
| 323 } | 332 } |
| 324 | 333 |
| 325 // The only case when devices can be empty is if the user has denied | 334 // The only case when devices can be empty is if the user has denied |
| 326 // permission. | 335 // permission. |
| 327 result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED | 336 result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED |
| 328 : content::MEDIA_DEVICE_OK; | 337 : content::MEDIA_DEVICE_OK; |
| 329 } | 338 } |
| 330 | 339 |
| 331 callback.Run(devices, result, std::move(ui)); | 340 callback.Run(devices, result, std::move(ui)); |
| 332 } | 341 } |
| 333 | 342 |
| 343 bool DesktopCaptureAccessHandler::IsDefaultApproved( |
| 344 const extensions::Extension* extension) { |
| 345 return extension && |
| 346 (extension->location() == extensions::Manifest::COMPONENT || |
| 347 extension->location() == extensions::Manifest::EXTERNAL_COMPONENT || |
| 348 IsExtensionWhitelistedForScreenCapture(extension)); |
| 349 } |
| 350 |
| 334 bool DesktopCaptureAccessHandler::SupportsStreamType( | 351 bool DesktopCaptureAccessHandler::SupportsStreamType( |
| 335 const content::MediaStreamType type, | 352 const content::MediaStreamType type, |
| 336 const extensions::Extension* extension) { | 353 const extensions::Extension* extension) { |
| 337 return type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || | 354 return type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || |
| 338 type == content::MEDIA_DESKTOP_AUDIO_CAPTURE; | 355 type == content::MEDIA_DESKTOP_AUDIO_CAPTURE; |
| 339 } | 356 } |
| 340 | 357 |
| 341 bool DesktopCaptureAccessHandler::CheckMediaAccessPermission( | 358 bool DesktopCaptureAccessHandler::CheckMediaAccessPermission( |
| 342 content::WebContents* web_contents, | 359 content::WebContents* web_contents, |
| 343 const GURL& security_origin, | 360 const GURL& security_origin, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 loopback_audio_supported) || | 435 loopback_audio_supported) || |
| 419 media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS; | 436 media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS; |
| 420 | 437 |
| 421 const bool check_audio_permission = | 438 const bool check_audio_permission = |
| 422 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 439 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 423 extensions::switches::kDisableDesktopCaptureAudio); | 440 extensions::switches::kDisableDesktopCaptureAudio); |
| 424 const bool capture_audio = | 441 const bool capture_audio = |
| 425 (check_audio_permission ? audio_permitted : true) && audio_requested && | 442 (check_audio_permission ? audio_permitted : true) && audio_requested && |
| 426 audio_supported; | 443 audio_supported; |
| 427 | 444 |
| 445 // Determine if the extension is required to display a notification. |
| 446 const bool display_notification = ShouldDisplayNotification(extension); |
| 447 |
| 428 ui = GetDevicesForDesktopCapture(&devices, media_id, capture_audio, false, | 448 ui = GetDevicesForDesktopCapture(&devices, media_id, capture_audio, false, |
| 429 true, | 449 display_notification, |
| 430 GetApplicationTitle(web_contents, extension), | 450 GetApplicationTitle(web_contents, extension), |
| 431 base::UTF8ToUTF16(original_extension_name)); | 451 base::UTF8ToUTF16(original_extension_name)); |
| 432 UpdateExtensionTrusted(request, extension); | 452 UpdateExtensionTrusted(request, extension); |
| 433 callback.Run(devices, content::MEDIA_DEVICE_OK, std::move(ui)); | 453 callback.Run(devices, content::MEDIA_DEVICE_OK, std::move(ui)); |
| 434 } | 454 } |
| 435 | |
| OLD | NEW |