1 // Copyright 2018 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/webrtc/desktop_capture_devices_util.h"
6 
7 #include <string>
8 #include <utility>
9 
10 #include "base/strings/string_util.h"
11 #include "build/build_config.h"
12 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
13 #include "chrome/browser/ui/screen_capture_notification_ui.h"
14 #include "chrome/browser/ui/tab_sharing/tab_sharing_ui.h"
15 #include "chrome/common/chrome_features.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "media/audio/audio_device_description.h"
19 #include "media/mojo/mojom/display_media_information.mojom.h"
20 #include "ui/base/l10n/l10n_util.h"
21 
22 namespace {
23 
24 media::mojom::DisplayMediaInformationPtr
DesktopMediaIDToDisplayMediaInformation(const content::DesktopMediaID & media_id)25 DesktopMediaIDToDisplayMediaInformation(
26     const content::DesktopMediaID& media_id) {
27   media::mojom::DisplayCaptureSurfaceType display_surface =
28       media::mojom::DisplayCaptureSurfaceType::MONITOR;
29   bool logical_surface = true;
30   media::mojom::CursorCaptureType cursor =
31       media::mojom::CursorCaptureType::NEVER;
32 #if defined(USE_AURA)
33   const bool uses_aura =
34       media_id.window_id != content::DesktopMediaID::kNullId ? true : false;
35 #else
36   const bool uses_aura = false;
37 #endif  // defined(USE_AURA)
38   switch (media_id.type) {
39     case content::DesktopMediaID::TYPE_SCREEN:
40       display_surface = media::mojom::DisplayCaptureSurfaceType::MONITOR;
41       cursor = uses_aura ? media::mojom::CursorCaptureType::MOTION
42                          : media::mojom::CursorCaptureType::ALWAYS;
43       break;
44     case content::DesktopMediaID::TYPE_WINDOW:
45       display_surface = media::mojom::DisplayCaptureSurfaceType::WINDOW;
46       cursor = uses_aura ? media::mojom::CursorCaptureType::MOTION
47                          : media::mojom::CursorCaptureType::ALWAYS;
48       break;
49     case content::DesktopMediaID::TYPE_WEB_CONTENTS:
50       display_surface = media::mojom::DisplayCaptureSurfaceType::BROWSER;
51       cursor = media::mojom::CursorCaptureType::MOTION;
52       break;
53     case content::DesktopMediaID::TYPE_NONE:
54       break;
55   }
56 
57   return media::mojom::DisplayMediaInformation::New(display_surface,
58                                                     logical_surface, cursor);
59 }
60 
GetStopSharingUIString(const base::string16 & application_title,const base::string16 & registered_extension_name,bool capture_audio,content::DesktopMediaID::Type capture_type)61 base::string16 GetStopSharingUIString(
62     const base::string16& application_title,
63     const base::string16& registered_extension_name,
64     bool capture_audio,
65     content::DesktopMediaID::Type capture_type) {
66   if (!capture_audio) {
67     if (application_title == registered_extension_name) {
68       switch (capture_type) {
69         case content::DesktopMediaID::TYPE_SCREEN:
70           return l10n_util::GetStringFUTF16(
71               IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, application_title);
72         case content::DesktopMediaID::TYPE_WINDOW:
73           return l10n_util::GetStringFUTF16(
74               IDS_MEDIA_WINDOW_CAPTURE_NOTIFICATION_TEXT, application_title);
75         case content::DesktopMediaID::TYPE_WEB_CONTENTS:
76           return l10n_util::GetStringFUTF16(
77               IDS_MEDIA_TAB_CAPTURE_NOTIFICATION_TEXT, application_title);
78         case content::DesktopMediaID::TYPE_NONE:
79           NOTREACHED();
80       }
81     } else {
82       switch (capture_type) {
83         case content::DesktopMediaID::TYPE_SCREEN:
84           return l10n_util::GetStringFUTF16(
85               IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
86               registered_extension_name, application_title);
87         case content::DesktopMediaID::TYPE_WINDOW:
88           return l10n_util::GetStringFUTF16(
89               IDS_MEDIA_WINDOW_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
90               registered_extension_name, application_title);
91         case content::DesktopMediaID::TYPE_WEB_CONTENTS:
92           return l10n_util::GetStringFUTF16(
93               IDS_MEDIA_TAB_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
94               registered_extension_name, application_title);
95         case content::DesktopMediaID::TYPE_NONE:
96           NOTREACHED();
97       }
98     }
99   } else {  // The case with audio
100     if (application_title == registered_extension_name) {
101       switch (capture_type) {
102         case content::DesktopMediaID::TYPE_SCREEN:
103           return l10n_util::GetStringFUTF16(
104               IDS_MEDIA_SCREEN_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT,
105               application_title);
106         case content::DesktopMediaID::TYPE_WEB_CONTENTS:
107           return l10n_util::GetStringFUTF16(
108               IDS_MEDIA_TAB_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT,
109               application_title);
110         case content::DesktopMediaID::TYPE_NONE:
111         case content::DesktopMediaID::TYPE_WINDOW:
112           NOTREACHED();
113       }
114     } else {
115       switch (capture_type) {
116         case content::DesktopMediaID::TYPE_SCREEN:
117           return l10n_util::GetStringFUTF16(
118               IDS_MEDIA_SCREEN_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT_DELEGATED,
119               registered_extension_name, application_title);
120         case content::DesktopMediaID::TYPE_WEB_CONTENTS:
121           return l10n_util::GetStringFUTF16(
122               IDS_MEDIA_TAB_CAPTURE_WITH_AUDIO_NOTIFICATION_TEXT_DELEGATED,
123               registered_extension_name, application_title);
124         case content::DesktopMediaID::TYPE_NONE:
125         case content::DesktopMediaID::TYPE_WINDOW:
126           NOTREACHED();
127       }
128     }
129   }
130   return base::string16();
131 }
132 
133 }  // namespace
134 
GetDevicesForDesktopCapture(content::WebContents * web_contents,blink::MediaStreamDevices * devices,const content::DesktopMediaID & media_id,blink::mojom::MediaStreamType devices_video_type,blink::mojom::MediaStreamType devices_audio_type,bool capture_audio,bool disable_local_echo,bool display_notification,const base::string16 & application_title,const base::string16 & registered_extension_name)135 std::unique_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
136     content::WebContents* web_contents,
137     blink::MediaStreamDevices* devices,
138     const content::DesktopMediaID& media_id,
139     blink::mojom::MediaStreamType devices_video_type,
140     blink::mojom::MediaStreamType devices_audio_type,
141     bool capture_audio,
142     bool disable_local_echo,
143     bool display_notification,
144     const base::string16& application_title,
145     const base::string16& registered_extension_name) {
146   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
147 
148   DVLOG(2) << __func__ << ": media_id " << media_id.ToString()
149            << ", capture_audio " << capture_audio << ", disable_local_echo "
150            << disable_local_echo << ", display_notification "
151            << display_notification << ", application_title "
152            << application_title << ", extension_name "
153            << registered_extension_name;
154 
155   // Add selected desktop source to the list.
156   auto device = blink::MediaStreamDevice(
157       devices_video_type, media_id.ToString(), media_id.ToString());
158   device.display_media_info = DesktopMediaIDToDisplayMediaInformation(media_id);
159   devices->push_back(device);
160   if (capture_audio) {
161     if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
162       content::WebContentsMediaCaptureId web_id = media_id.web_contents_id;
163       web_id.disable_local_echo = disable_local_echo;
164       devices->push_back(blink::MediaStreamDevice(
165           devices_audio_type, web_id.ToString(), "Tab audio"));
166     } else if (disable_local_echo) {
167       // Use the special loopback device ID for system audio capture.
168       devices->push_back(blink::MediaStreamDevice(
169           devices_audio_type,
170           media::AudioDeviceDescription::kLoopbackWithMuteDeviceId,
171           "System Audio"));
172     } else {
173       // Use the special loopback device ID for system audio capture.
174       devices->push_back(blink::MediaStreamDevice(
175           devices_audio_type,
176           media::AudioDeviceDescription::kLoopbackInputDeviceId,
177           "System Audio"));
178     }
179   }
180 
181   // If required, register to display the notification for stream capture.
182   std::unique_ptr<MediaStreamUI> notification_ui;
183   if (display_notification) {
184     if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS &&
185         base::FeatureList::IsEnabled(
186             features::kDesktopCaptureTabSharingInfobar)) {
187       notification_ui = TabSharingUI::Create(media_id, application_title);
188     } else {
189       notification_ui = ScreenCaptureNotificationUI::Create(
190           GetStopSharingUIString(application_title, registered_extension_name,
191                                  capture_audio, media_id.type));
192     }
193   }
194 
195   return MediaCaptureDevicesDispatcher::GetInstance()
196       ->GetMediaStreamCaptureIndicator()
197       ->RegisterMediaStream(web_contents, *devices, std::move(notification_ui));
198 }
199