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