Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / desktop_capture / desktop_capture_base.cc
blob22302a1434cfca5002a992174da5175257cf79e0
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/extension_tab_util.h"
9 #include "chrome/browser/media/desktop_media_list_ash.h"
10 #include "chrome/browser/media/desktop_streams_registry.h"
11 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
12 #include "chrome/browser/media/native_desktop_media_list.h"
13 #include "chrome/browser/ui/ash/ash_util.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/web_contents.h"
17 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
18 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
19 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
21 namespace extensions {
23 namespace {
25 const char kInvalidSourceNameError[] = "Invalid source type specified.";
26 const char kEmptySourcesListError[] =
27 "At least one source type must be specified.";
28 const char kTabCaptureNotSupportedError[] = "Tab capture is not supported yet.";
30 DesktopCaptureChooseDesktopMediaFunctionBase::PickerFactory* g_picker_factory =
31 NULL;
33 } // namespace
35 // static
36 void DesktopCaptureChooseDesktopMediaFunctionBase::SetPickerFactoryForTests(
37 PickerFactory* factory) {
38 g_picker_factory = factory;
41 DesktopCaptureChooseDesktopMediaFunctionBase::
42 DesktopCaptureChooseDesktopMediaFunctionBase() {
45 DesktopCaptureChooseDesktopMediaFunctionBase::
46 ~DesktopCaptureChooseDesktopMediaFunctionBase() {
47 // RenderViewHost may be already destroyed.
48 if (render_frame_host()) {
49 DesktopCaptureRequestsRegistry::GetInstance()->RemoveRequest(
50 render_frame_host()->GetProcess()->GetID(), request_id_);
54 void DesktopCaptureChooseDesktopMediaFunctionBase::Cancel() {
55 // Keep reference to |this| to ensure the object doesn't get destroyed before
56 // we return.
57 scoped_refptr<DesktopCaptureChooseDesktopMediaFunctionBase> self(this);
58 if (picker_) {
59 picker_.reset();
60 SetResult(new base::StringValue(std::string()));
61 SendResponse(true);
65 bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute(
66 const std::vector<api::desktop_capture::DesktopCaptureSourceType>& sources,
67 content::WebContents* web_contents,
68 const GURL& origin,
69 const base::string16 target_name) {
70 // Register to be notified when the tab is closed.
71 Observe(web_contents);
73 bool show_screens = false;
74 bool show_windows = false;
76 for (auto source_type : sources) {
77 switch (source_type) {
78 case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_NONE:
79 error_ = kInvalidSourceNameError;
80 return false;
82 case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_SCREEN:
83 show_screens = true;
84 break;
86 case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_WINDOW:
87 show_windows = true;
88 break;
90 case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_TAB:
91 error_ = kTabCaptureNotSupportedError;
92 return false;
96 if (!show_screens && !show_windows) {
97 error_ = kEmptySourcesListError;
98 return false;
101 const gfx::NativeWindow parent_window =
102 web_contents->GetTopLevelNativeWindow();
103 scoped_ptr<DesktopMediaList> media_list;
104 if (g_picker_factory) {
105 media_list = g_picker_factory->CreateModel(
106 show_screens, show_windows);
107 picker_ = g_picker_factory->CreatePicker();
108 } else {
109 #if defined(USE_ASH)
110 if (chrome::IsNativeWindowInAsh(parent_window)) {
111 media_list.reset(new DesktopMediaListAsh(
112 (show_screens ? DesktopMediaListAsh::SCREENS : 0) |
113 (show_windows ? DesktopMediaListAsh::WINDOWS : 0)));
115 #endif
116 if (!media_list) {
117 webrtc::DesktopCaptureOptions options =
118 webrtc::DesktopCaptureOptions::CreateDefault();
119 options.set_disable_effects(false);
120 scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
121 show_screens ? webrtc::ScreenCapturer::Create(options) : NULL);
122 scoped_ptr<webrtc::WindowCapturer> window_capturer(
123 show_windows ? webrtc::WindowCapturer::Create(options) : NULL);
125 media_list.reset(new NativeDesktopMediaList(
126 screen_capturer.Pass(), window_capturer.Pass()));
129 // DesktopMediaPicker is implemented only for Windows, OSX and
130 // Aura Linux builds.
131 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
132 picker_ = DesktopMediaPicker::Create();
133 #else
134 error_ = "Desktop Capture API is not yet implemented for this platform.";
135 return false;
136 #endif
138 DesktopMediaPicker::DoneCallback callback = base::Bind(
139 &DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults,
140 this);
142 picker_->Show(web_contents,
143 parent_window,
144 parent_window,
145 base::UTF8ToUTF16(extension()->name()),
146 target_name,
147 media_list.Pass(),
148 callback);
149 origin_ = origin;
150 return true;
153 void DesktopCaptureChooseDesktopMediaFunctionBase::WebContentsDestroyed() {
154 Cancel();
157 void DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults(
158 content::DesktopMediaID source) {
159 std::string result;
160 if (source.type != content::DesktopMediaID::TYPE_NONE &&
161 web_contents()) {
162 DesktopStreamsRegistry* registry =
163 MediaCaptureDevicesDispatcher::GetInstance()->
164 GetDesktopStreamsRegistry();
165 // TODO(miu): Once render_frame_host() is being set, we should register the
166 // exact RenderFrame requesting the stream, not the main RenderFrame. With
167 // that change, also update
168 // MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest().
169 // http://crbug.com/304341
170 content::RenderFrameHost* const main_frame = web_contents()->GetMainFrame();
171 result = registry->RegisterStream(main_frame->GetProcess()->GetID(),
172 main_frame->GetRoutingID(),
173 origin_,
174 source,
175 extension()->name());
178 SetResult(new base::StringValue(result));
179 SendResponse(true);
182 DesktopCaptureRequestsRegistry::RequestId::RequestId(int process_id,
183 int request_id)
184 : process_id(process_id),
185 request_id(request_id) {
188 bool DesktopCaptureRequestsRegistry::RequestId::operator<(
189 const RequestId& other) const {
190 if (process_id != other.process_id) {
191 return process_id < other.process_id;
192 } else {
193 return request_id < other.request_id;
197 DesktopCaptureCancelChooseDesktopMediaFunctionBase::
198 DesktopCaptureCancelChooseDesktopMediaFunctionBase() {}
200 DesktopCaptureCancelChooseDesktopMediaFunctionBase::
201 ~DesktopCaptureCancelChooseDesktopMediaFunctionBase() {}
203 bool DesktopCaptureCancelChooseDesktopMediaFunctionBase::RunSync() {
204 int request_id;
205 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id));
207 DesktopCaptureRequestsRegistry::GetInstance()->CancelRequest(
208 render_frame_host()->GetProcess()->GetID(), request_id);
209 return true;
212 DesktopCaptureRequestsRegistry::DesktopCaptureRequestsRegistry() {}
213 DesktopCaptureRequestsRegistry::~DesktopCaptureRequestsRegistry() {}
215 // static
216 DesktopCaptureRequestsRegistry* DesktopCaptureRequestsRegistry::GetInstance() {
217 return base::Singleton<DesktopCaptureRequestsRegistry>::get();
220 void DesktopCaptureRequestsRegistry::AddRequest(
221 int process_id,
222 int request_id,
223 DesktopCaptureChooseDesktopMediaFunctionBase* handler) {
224 requests_.insert(
225 RequestsMap::value_type(RequestId(process_id, request_id), handler));
228 void DesktopCaptureRequestsRegistry::RemoveRequest(int process_id,
229 int request_id) {
230 requests_.erase(RequestId(process_id, request_id));
233 void DesktopCaptureRequestsRegistry::CancelRequest(int process_id,
234 int request_id) {
235 RequestsMap::iterator it = requests_.find(RequestId(process_id, request_id));
236 if (it != requests_.end())
237 it->second->Cancel();
241 } // namespace extensions