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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/command_line.h"
13 #include "base/metrics/field_trial.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "build/build_config.h"
18 #include "chrome/browser/media/media_access_handler.h"
19 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
20 #include "chrome/browser/media/webrtc/permission_bubble_media_access_handler.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "components/prefs/pref_service.h"
26 #include "components/prefs/scoped_user_pref_update.h"
27 #include "content/public/browser/browser_task_traits.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/media_capture_devices.h"
30 #include "content/public/browser/notification_source.h"
31 #include "content/public/browser/render_frame_host.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "extensions/buildflags/buildflags.h"
35 #include "extensions/common/constants.h"
36 #include "media/base/media_switches.h"
37 #include "third_party/blink/public/common/features.h"
38 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
39 
40 #if defined(OS_ANDROID)
41 #include "content/public/common/content_features.h"
42 #else  // !OS_ANDROID
43 #include "chrome/browser/media/webrtc/display_media_access_handler.h"
44 #endif  //  defined(OS_ANDROID)
45 
46 #if defined(OS_CHROMEOS)
47 #include "ash/shell.h"
48 #include "chrome/browser/media/chromeos_login_media_access_handler.h"
49 #include "chrome/browser/media/public_session_media_access_handler.h"
50 #include "chrome/browser/media/public_session_tab_capture_access_handler.h"
51 #endif  // defined(OS_CHROMEOS)
52 
53 #if BUILDFLAG(ENABLE_EXTENSIONS)
54 #include "chrome/browser/media/extension_media_access_handler.h"
55 #include "chrome/browser/media/webrtc/desktop_capture_access_handler.h"
56 #include "chrome/browser/media/webrtc/tab_capture_access_handler.h"
57 #include "extensions/browser/extension_registry.h"
58 #include "extensions/common/extension.h"
59 #include "extensions/common/permissions/permissions_data.h"
60 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
61 
62 using blink::MediaStreamDevices;
63 using content::BrowserThread;
64 using content::MediaCaptureDevices;
65 
66 namespace {
67 
WebContentsFromIds(int render_process_id,int render_frame_id)68 content::WebContents* WebContentsFromIds(int render_process_id,
69                                          int render_frame_id) {
70   content::WebContents* web_contents =
71       content::WebContents::FromRenderFrameHost(
72           content::RenderFrameHost::FromID(render_process_id, render_frame_id));
73   return web_contents;
74 }
75 
76 }  // namespace
77 
GetInstance()78 MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
79   return base::Singleton<MediaCaptureDevicesDispatcher>::get();
80 }
81 
MediaCaptureDevicesDispatcher()82 MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
83     : is_device_enumeration_disabled_(false),
84       media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) {
85   DCHECK_CURRENTLY_ON(BrowserThread::UI);
86 
87 #if !defined(OS_ANDROID)
88   media_access_handlers_.push_back(
89       std::make_unique<DisplayMediaAccessHandler>());
90 #endif  //  defined(OS_ANDROID)
91 
92 #if BUILDFLAG(ENABLE_EXTENSIONS)
93 #if defined(OS_CHROMEOS)
94   media_access_handlers_.push_back(
95       std::make_unique<ChromeOSLoginMediaAccessHandler>());
96   // Wrapper around ExtensionMediaAccessHandler used in Public Sessions.
97   media_access_handlers_.push_back(
98       std::make_unique<PublicSessionMediaAccessHandler>());
99 #else
100   media_access_handlers_.push_back(
101       std::make_unique<ExtensionMediaAccessHandler>());
102 #endif
103   media_access_handlers_.push_back(
104       std::make_unique<DesktopCaptureAccessHandler>());
105 #if defined(OS_CHROMEOS)
106   // Wrapper around TabCaptureAccessHandler used in Public Sessions.
107   media_access_handlers_.push_back(
108       std::make_unique<PublicSessionTabCaptureAccessHandler>());
109 #else
110   media_access_handlers_.push_back(std::make_unique<TabCaptureAccessHandler>());
111 #endif
112 #endif
113   media_access_handlers_.push_back(
114       std::make_unique<PermissionBubbleMediaAccessHandler>());
115 }
116 
~MediaCaptureDevicesDispatcher()117 MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
118 
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)119 void MediaCaptureDevicesDispatcher::RegisterProfilePrefs(
120     user_prefs::PrefRegistrySyncable* registry) {
121   registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
122                                std::string());
123   registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
124                                std::string());
125 }
126 
IsOriginForCasting(const GURL & origin)127 bool MediaCaptureDevicesDispatcher::IsOriginForCasting(const GURL& origin) {
128   // Allowed tab casting extensions.
129   return
130       // Media Router Dev
131       origin.spec() == "chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/" ||
132       // Media Router Stable
133       origin.spec() == "chrome-extension://pkedcjkdefgpdelpbcmbmeomcjbeemfm/";
134 }
135 
AddObserver(Observer * observer)136 void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) {
137   DCHECK_CURRENTLY_ON(BrowserThread::UI);
138   if (!observers_.HasObserver(observer))
139     observers_.AddObserver(observer);
140 }
141 
RemoveObserver(Observer * observer)142 void MediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) {
143   DCHECK_CURRENTLY_ON(BrowserThread::UI);
144   observers_.RemoveObserver(observer);
145 }
146 
ProcessMediaAccessRequest(content::WebContents * web_contents,const content::MediaStreamRequest & request,content::MediaResponseCallback callback,const extensions::Extension * extension)147 void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest(
148     content::WebContents* web_contents,
149     const content::MediaStreamRequest& request,
150     content::MediaResponseCallback callback,
151     const extensions::Extension* extension) {
152   DCHECK_CURRENTLY_ON(BrowserThread::UI);
153 
154 #if defined(OS_ANDROID)
155   // Kill switch for getDisplayMedia() on browser side to prevent renderer from
156   // bypassing blink side checks.
157   if (request.video_type ==
158           blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE &&
159       !base::FeatureList::IsEnabled(features::kUserMediaScreenCapturing)) {
160     std::move(callback).Run(
161         blink::MediaStreamDevices(),
162         blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
163     return;
164   }
165 #endif
166 
167   // Kill switch for getCurrentBrowsingContextMedia() on browser side to prevent
168   // renderer from bypassing blink side checks.
169   if (request.video_type ==
170       blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB) {
171     if (!base::FeatureList::IsEnabled(
172             blink::features::kRTCGetCurrentBrowsingContextMedia)) {
173       std::move(callback).Run(
174           blink::MediaStreamDevices(),
175           blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
176       return;
177     }
178   }
179 
180   for (const auto& handler : media_access_handlers_) {
181     if (handler->SupportsStreamType(web_contents, request.video_type,
182                                     extension) ||
183         handler->SupportsStreamType(web_contents, request.audio_type,
184                                     extension)) {
185       handler->HandleRequest(web_contents, request, std::move(callback),
186                              extension);
187       return;
188     }
189   }
190   std::move(callback).Run(blink::MediaStreamDevices(),
191                           blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED,
192                           nullptr);
193 }
194 
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type)195 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
196     content::RenderFrameHost* render_frame_host,
197     const GURL& security_origin,
198     blink::mojom::MediaStreamType type) {
199   DCHECK_CURRENTLY_ON(BrowserThread::UI);
200   return CheckMediaAccessPermission(render_frame_host, security_origin, type,
201                                     nullptr);
202 }
203 
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type,const extensions::Extension * extension)204 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
205     content::RenderFrameHost* render_frame_host,
206     const GURL& security_origin,
207     blink::mojom::MediaStreamType type,
208     const extensions::Extension* extension) {
209   DCHECK_CURRENTLY_ON(BrowserThread::UI);
210   for (const auto& handler : media_access_handlers_) {
211     if (handler->SupportsStreamType(
212             content::WebContents::FromRenderFrameHost(render_frame_host), type,
213             extension)) {
214       return handler->CheckMediaAccessPermission(
215           render_frame_host, security_origin, type, extension);
216     }
217   }
218   return false;
219 }
220 
DisableDeviceEnumerationForTesting()221 void MediaCaptureDevicesDispatcher::DisableDeviceEnumerationForTesting() {
222   is_device_enumeration_disabled_ = true;
223 }
224 
GetDefaultDeviceIDForProfile(Profile * profile,blink::mojom::MediaStreamType type)225 std::string MediaCaptureDevicesDispatcher::GetDefaultDeviceIDForProfile(
226     Profile* profile,
227     blink::mojom::MediaStreamType type) {
228   DCHECK_CURRENTLY_ON(BrowserThread::UI);
229   PrefService* prefs = profile->GetPrefs();
230   if (type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE)
231     return prefs->GetString(prefs::kDefaultAudioCaptureDevice);
232   else if (type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE)
233     return prefs->GetString(prefs::kDefaultVideoCaptureDevice);
234   else
235     return std::string();
236 }
237 
238 const MediaStreamDevices&
GetAudioCaptureDevices() const239 MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() const {
240   DCHECK_CURRENTLY_ON(BrowserThread::UI);
241   if (is_device_enumeration_disabled_ || !test_audio_devices_.empty())
242     return test_audio_devices_;
243 
244   return MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
245 }
246 
247 const MediaStreamDevices&
GetVideoCaptureDevices() const248 MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() const {
249   DCHECK_CURRENTLY_ON(BrowserThread::UI);
250   if (is_device_enumeration_disabled_ || !test_video_devices_.empty())
251     return test_video_devices_;
252 
253   return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
254 }
255 
GetDefaultDevicesForBrowserContext(content::BrowserContext * context,bool audio,bool video,blink::MediaStreamDevices * devices)256 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForBrowserContext(
257     content::BrowserContext* context,
258     bool audio,
259     bool video,
260     blink::MediaStreamDevices* devices) {
261   DCHECK_CURRENTLY_ON(BrowserThread::UI);
262   DCHECK(audio || video);
263 
264   PrefService* prefs = Profile::FromBrowserContext(context)->GetPrefs();
265   std::string default_device;
266   if (audio) {
267     default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
268     const blink::MediaStreamDevice* device =
269         GetRequestedAudioDevice(default_device);
270     if (device) {
271       devices->push_back(*device);
272     } else {
273       const blink::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
274       if (!audio_devices.empty())
275         devices->push_back(audio_devices.front());
276     }
277   }
278 
279   if (video) {
280     default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
281     const blink::MediaStreamDevice* device =
282         GetRequestedVideoDevice(default_device);
283     if (device) {
284       devices->push_back(*device);
285     } else {
286       const blink::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
287       if (!video_devices.empty())
288         devices->push_back(video_devices.front());
289     }
290   }
291 }
292 
293 #if 0
294 const blink::MediaStreamDevice*
295 MediaCaptureDevicesDispatcher::GetRequestedAudioDevice(
296     const std::string& requested_audio_device_id) {
297   DCHECK_CURRENTLY_ON(BrowserThread::UI);
298   const blink::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
299   const blink::MediaStreamDevice* const device =
300       FindDeviceWithId(audio_devices, requested_audio_device_id);
301   return device;
302 }
303 
304 const blink::MediaStreamDevice*
305 MediaCaptureDevicesDispatcher::GetRequestedVideoDevice(
306     const std::string& requested_video_device_id) {
307   DCHECK_CURRENTLY_ON(BrowserThread::UI);
308   const blink::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
309   const blink::MediaStreamDevice* const device =
310       FindDeviceWithId(video_devices, requested_video_device_id);
311   return device;
312 }
313 #endif
314 
315 scoped_refptr<MediaStreamCaptureIndicator>
GetMediaStreamCaptureIndicator()316 MediaCaptureDevicesDispatcher::GetMediaStreamCaptureIndicator() {
317   return media_stream_capture_indicator_;
318 }
319 
OnAudioCaptureDevicesChanged()320 void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged() {
321   DCHECK_CURRENTLY_ON(BrowserThread::IO);
322   content::GetUIThreadTaskRunner({})->PostTask(
323       FROM_HERE,
324       base::BindOnce(
325           &MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread,
326           base::Unretained(this)));
327 }
328 
OnVideoCaptureDevicesChanged()329 void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged() {
330   DCHECK_CURRENTLY_ON(BrowserThread::IO);
331   content::GetUIThreadTaskRunner({})->PostTask(
332       FROM_HERE,
333       base::BindOnce(
334           &MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread,
335           base::Unretained(this)));
336 }
337 
OnMediaRequestStateChanged(int render_process_id,int render_frame_id,int page_request_id,const GURL & security_origin,blink::mojom::MediaStreamType stream_type,content::MediaRequestState state)338 void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
339     int render_process_id,
340     int render_frame_id,
341     int page_request_id,
342     const GURL& security_origin,
343     blink::mojom::MediaStreamType stream_type,
344     content::MediaRequestState state) {
345   DCHECK_CURRENTLY_ON(BrowserThread::IO);
346   content::GetUIThreadTaskRunner({})->PostTask(
347       FROM_HERE,
348       base::BindOnce(
349           &MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread,
350           base::Unretained(this), render_process_id, render_frame_id,
351           page_request_id, security_origin, stream_type, state));
352 }
353 
OnCreatingAudioStream(int render_process_id,int render_frame_id)354 void MediaCaptureDevicesDispatcher::OnCreatingAudioStream(int render_process_id,
355                                                           int render_frame_id) {
356   // TODO(https://crbug.com/837606): Figure out how to simplify threading here.
357   // Currently, this will either always be called on the UI thread, or always
358   // on the IO thread, depending on how far along the work to migrate to the
359   // audio service has progressed. The rest of the methods of the
360   // content::MediaObserver are always called on the IO thread.
361   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
362     OnCreatingAudioStreamOnUIThread(render_process_id, render_frame_id);
363     return;
364   }
365 
366   DCHECK_CURRENTLY_ON(BrowserThread::IO);
367   content::GetUIThreadTaskRunner({})->PostTask(
368       FROM_HERE,
369       base::BindOnce(
370           &MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread,
371           base::Unretained(this), render_process_id, render_frame_id));
372 }
373 
NotifyAudioDevicesChangedOnUIThread()374 void MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread() {
375   MediaStreamDevices devices = GetAudioCaptureDevices();
376   for (auto& observer : observers_)
377     observer.OnUpdateAudioDevices(devices);
378 }
379 
NotifyVideoDevicesChangedOnUIThread()380 void MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread() {
381   MediaStreamDevices devices = GetVideoCaptureDevices();
382   for (auto& observer : observers_)
383     observer.OnUpdateVideoDevices(devices);
384 }
385 
UpdateMediaRequestStateOnUIThread(int render_process_id,int render_frame_id,int page_request_id,const GURL & security_origin,blink::mojom::MediaStreamType stream_type,content::MediaRequestState state)386 void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread(
387     int render_process_id,
388     int render_frame_id,
389     int page_request_id,
390     const GURL& security_origin,
391     blink::mojom::MediaStreamType stream_type,
392     content::MediaRequestState state) {
393   DCHECK_CURRENTLY_ON(BrowserThread::UI);
394   for (const auto& handler : media_access_handlers_) {
395     if (handler->SupportsStreamType(
396             WebContentsFromIds(render_process_id, render_frame_id), stream_type,
397             nullptr)) {
398       handler->UpdateMediaRequestState(render_process_id, render_frame_id,
399                                        page_request_id, stream_type, state);
400       break;
401     }
402   }
403 
404 #if defined(OS_CHROMEOS)
405   if (IsOriginForCasting(security_origin) &&
406       blink::IsVideoInputMediaType(stream_type)) {
407     // Notify ash that casting state has changed.
408     if (state == content::MEDIA_REQUEST_STATE_DONE) {
409       ash::Shell::Get()->OnCastingSessionStartedOrStopped(true);
410     } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
411       ash::Shell::Get()->OnCastingSessionStartedOrStopped(false);
412     }
413   }
414 #endif
415 
416   for (auto& observer : observers_) {
417     observer.OnRequestUpdate(render_process_id, render_frame_id, stream_type,
418                              state);
419   }
420 }
421 
OnCreatingAudioStreamOnUIThread(int render_process_id,int render_frame_id)422 void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread(
423     int render_process_id,
424     int render_frame_id) {
425   DCHECK_CURRENTLY_ON(BrowserThread::UI);
426   for (auto& observer : observers_)
427     observer.OnCreatingAudioStream(render_process_id, render_frame_id);
428 }
429 
IsInsecureCapturingInProgress(int render_process_id,int render_frame_id)430 bool MediaCaptureDevicesDispatcher::IsInsecureCapturingInProgress(
431     int render_process_id,
432     int render_frame_id) {
433   DCHECK_CURRENTLY_ON(BrowserThread::UI);
434 
435   for (const auto& handler : media_access_handlers_) {
436     if (handler->IsInsecureCapturingInProgress(render_process_id,
437                                                render_frame_id))
438       return true;
439   }
440   return false;
441 }
442 
SetTestAudioCaptureDevices(const MediaStreamDevices & devices)443 void MediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices(
444     const MediaStreamDevices& devices) {
445   test_audio_devices_ = devices;
446 }
447 
SetTestVideoCaptureDevices(const MediaStreamDevices & devices)448 void MediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices(
449     const MediaStreamDevices& devices) {
450   test_video_devices_ = devices;
451 }
452 
OnSetCapturingLinkSecured(int render_process_id,int render_frame_id,int page_request_id,blink::mojom::MediaStreamType stream_type,bool is_secure)453 void MediaCaptureDevicesDispatcher::OnSetCapturingLinkSecured(
454     int render_process_id,
455     int render_frame_id,
456     int page_request_id,
457     blink::mojom::MediaStreamType stream_type,
458     bool is_secure) {
459   DCHECK_CURRENTLY_ON(BrowserThread::IO);
460 
461   if (!blink::IsVideoScreenCaptureMediaType(stream_type))
462     return;
463 
464   content::GetUIThreadTaskRunner({})->PostTask(
465       FROM_HERE,
466       base::BindOnce(
467           &MediaCaptureDevicesDispatcher::UpdateVideoScreenCaptureStatus,
468           base::Unretained(this), render_process_id, render_frame_id,
469           page_request_id, stream_type, is_secure));
470 }
471 
UpdateVideoScreenCaptureStatus(int render_process_id,int render_frame_id,int page_request_id,blink::mojom::MediaStreamType stream_type,bool is_secure)472 void MediaCaptureDevicesDispatcher::UpdateVideoScreenCaptureStatus(
473     int render_process_id,
474     int render_frame_id,
475     int page_request_id,
476     blink::mojom::MediaStreamType stream_type,
477     bool is_secure) {
478   DCHECK_CURRENTLY_ON(BrowserThread::UI);
479   DCHECK(blink::IsVideoScreenCaptureMediaType(stream_type));
480 
481   for (const auto& handler : media_access_handlers_) {
482     if (handler->SupportsStreamType(
483             WebContentsFromIds(render_process_id, render_frame_id), stream_type,
484             nullptr)) {
485       handler->UpdateVideoScreenCaptureStatus(
486           render_process_id, render_frame_id, page_request_id, is_secure);
487       break;
488     }
489   }
490 }
491