1 // Copyright 2019 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_media_picker_controller.h"
6 
7 #include <memory>
8 #include <tuple>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/media/webrtc/desktop_media_list_ash.h"
16 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
17 #include "chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h"
18 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
19 #include "chrome/browser/media/webrtc/native_desktop_media_list.h"
20 #include "chrome/browser/media/webrtc/tab_desktop_media_list.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/browser_window.h"
24 #include "chrome/grit/chromium_strings.h"
25 #include "content/public/browser/desktop_capture.h"
26 #include "content/public/browser/desktop_streams_registry.h"
27 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "desktop_media_picker.h"
31 #include "extensions/common/manifest.h"
32 #include "extensions/common/switches.h"
33 #include "ui/base/l10n/l10n_util.h"
34 
DesktopMediaPickerController(DesktopMediaPickerFactory * picker_factory)35 DesktopMediaPickerController::DesktopMediaPickerController(
36     DesktopMediaPickerFactory* picker_factory)
37     : picker_factory_(picker_factory
38                           ? picker_factory
39                           : DesktopMediaPickerFactoryImpl::GetInstance()) {}
40 
41 DesktopMediaPickerController::~DesktopMediaPickerController() = default;
42 
Show(const Params & params,const std::vector<content::DesktopMediaID::Type> & sources,DoneCallback done_callback)43 void DesktopMediaPickerController::Show(
44     const Params& params,
45     const std::vector<content::DesktopMediaID::Type>& sources,
46     DoneCallback done_callback) {
47   DCHECK(!base::Contains(sources, content::DesktopMediaID::TYPE_NONE));
48   DCHECK(!done_callback_);
49 
50   done_callback_ = std::move(done_callback);
51   params_ = params;
52 
53   Observe(params.web_contents);
54 
55   // Keep same order as the input |sources| and avoid duplicates.
56   source_lists_ = picker_factory_->CreateMediaList(sources);
57   if (source_lists_.empty()) {
58     OnPickerDialogResults("At least one source type must be specified.", {});
59     return;
60   }
61 
62   if (params.select_only_screen && sources.size() == 1 &&
63       sources[0] == content::DesktopMediaID::TYPE_SCREEN) {
64     // Try to bypass the picker dialog if possible.
65     DCHECK(source_lists_.size() == 1);
66     auto* source_list = source_lists_[0].get();
67     source_list->Update(
68         base::BindOnce(&DesktopMediaPickerController::OnInitialMediaListFound,
69                        base::Unretained(this)));
70   } else {
71     ShowPickerDialog();
72   }
73 }
74 
WebContentsDestroyed()75 void DesktopMediaPickerController::WebContentsDestroyed() {
76   OnPickerDialogResults(std::string(), content::DesktopMediaID());
77 }
78 
OnInitialMediaListFound()79 void DesktopMediaPickerController::OnInitialMediaListFound() {
80   DCHECK(params_.select_only_screen);
81   DCHECK(source_lists_.size() == 1);
82   auto* source_list = source_lists_[0].get();
83   if (source_list->GetSourceCount() == 1) {
84     // With only one possible source, the picker dialog is being bypassed. Apply
85     // the default value of the "audio checkbox" here for desktop screen share.
86     // Only two platform configurations support desktop audio capture (i.e.,
87     // system-wide audio loopback) at this time.
88     content::DesktopMediaID media_id = source_list->GetSource(0).id;
89     DCHECK_EQ(media_id.type, content::DesktopMediaID::TYPE_SCREEN);
90 #if defined(USE_CRAS) || defined(OS_WIN)
91     media_id.audio_share =
92         params_.request_audio && params_.approve_audio_by_default;
93 #else
94     media_id.audio_share = false;
95 #endif
96     OnPickerDialogResults({}, media_id);
97     return;
98   }
99 
100   ShowPickerDialog();
101 }
102 
ShowPickerDialog()103 void DesktopMediaPickerController::ShowPickerDialog() {
104   picker_ = picker_factory_->CreatePicker();
105   if (!picker_) {
106     OnPickerDialogResults(
107         "Desktop Capture API is not yet implemented for this platform.", {});
108     return;
109   }
110 
111   picker_->Show(
112       params_, std::move(source_lists_),
113       base::BindOnce(&DesktopMediaPickerController::OnPickerDialogResults,
114                      // A weak pointer is used here, because although
115                      // |picker_| can't outlive this object, it can
116                      // schedule this callback to be invoked
117                      // asynchronously after it has potentially been
118                      // destroyed.
119                      weak_factory_.GetWeakPtr(), std::string()));
120 }
121 
OnPickerDialogResults(const std::string & err,content::DesktopMediaID source)122 void DesktopMediaPickerController::OnPickerDialogResults(
123     const std::string& err,
124     content::DesktopMediaID source) {
125   if (done_callback_)
126     std::move(done_callback_).Run(err, source);
127 }
128