- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / desktop_capture / desktop_capture_api.cc
1 // Copyright 2013 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/extensions/api/desktop_capture/desktop_capture_api.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_tab_util.h"
10 #include "chrome/browser/media/desktop_streams_registry.h"
11 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
12 #include "chrome/common/extensions/api/tabs.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
19 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
20
21 namespace extensions {
22
23 namespace {
24
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.";
29 const char kNoTabIdError[] = "targetTab doesn't have id field set.";
30 const char kNoUrlError[] = "targetTab doesn't have URL field set.";
31 const char kInvalidTabIdError[] = "Invalid tab specified.";
32 const char kTabUrlChangedError[] = "URL for the specified tab has changed.";
33
34 DesktopCaptureChooseDesktopMediaFunction::PickerFactory* g_picker_factory =
35     NULL;
36
37 }  // namespace
38
39 // static
40 void DesktopCaptureChooseDesktopMediaFunction::SetPickerFactoryForTests(
41     PickerFactory* factory) {
42   g_picker_factory = factory;
43 }
44
45 DesktopCaptureChooseDesktopMediaFunction::
46     DesktopCaptureChooseDesktopMediaFunction()
47     : render_process_id_(0),
48       render_view_id_(0) {
49 }
50
51 DesktopCaptureChooseDesktopMediaFunction::
52     ~DesktopCaptureChooseDesktopMediaFunction() {
53   // RenderViewHost may be already destroyed.
54   if (render_view_host()) {
55     DesktopCaptureRequestsRegistry::GetInstance()->RemoveRequest(
56         render_view_host()->GetProcess()->GetID(), request_id_);
57   }
58 }
59
60 void DesktopCaptureChooseDesktopMediaFunction::Cancel() {
61   // Keep reference to |this| to ensure the object doesn't get destroyed before
62   // we return.
63   scoped_refptr<DesktopCaptureChooseDesktopMediaFunction> self(this);
64   if (picker_) {
65     picker_.reset();
66     SetResult(new base::StringValue(std::string()));
67     SendResponse(true);
68   }
69 }
70
71 bool DesktopCaptureChooseDesktopMediaFunction::RunImpl() {
72   EXTENSION_FUNCTION_VALIDATE(args_->GetSize() > 0);
73
74   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id_));
75   args_->Remove(0, NULL);
76
77   scoped_ptr<api::desktop_capture::ChooseDesktopMedia::Params> params =
78       api::desktop_capture::ChooseDesktopMedia::Params::Create(*args_);
79   EXTENSION_FUNCTION_VALIDATE(params.get());
80
81   DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(
82       render_view_host()->GetProcess()->GetID(), request_id_, this);
83
84   gfx::NativeWindow parent_window;
85   content::RenderViewHost* render_view;
86   if (params->target_tab) {
87     if (!params->target_tab->url) {
88       error_ = kNoUrlError;
89       return false;
90     }
91     origin_ = GURL(*(params->target_tab->url)).GetOrigin();
92
93     if (!params->target_tab->id) {
94       error_ = kNoTabIdError;
95       return false;
96     }
97
98     content::WebContents* web_contents = NULL;
99     if (!ExtensionTabUtil::GetTabById(*(params->target_tab->id),
100                                       GetProfile(),
101                                       false,
102                                       NULL,
103                                       NULL,
104                                       &web_contents,
105                                       NULL)) {
106       error_ = kInvalidTabIdError;
107       return false;
108     }
109
110     GURL current_origin_ =
111         web_contents->GetLastCommittedURL().GetOrigin();
112     if (current_origin_ != origin_) {
113       error_ = kTabUrlChangedError;
114       return false;
115     }
116
117     render_view = web_contents->GetRenderViewHost();
118     parent_window = web_contents->GetView()->GetTopLevelNativeWindow();
119   } else {
120     origin_ = GetExtension()->url();
121     render_view = render_view_host();
122     parent_window =
123         GetAssociatedWebContents()->GetView()->GetTopLevelNativeWindow();
124   }
125   render_process_id_ = render_view->GetProcess()->GetID();
126   render_view_id_ = render_view->GetRoutingID();
127
128   scoped_ptr<webrtc::ScreenCapturer> screen_capturer;
129   scoped_ptr<webrtc::WindowCapturer> window_capturer;
130
131   for (std::vector<api::desktop_capture::DesktopCaptureSourceType>::iterator
132        it = params->sources.begin(); it != params->sources.end(); ++it) {
133     switch (*it) {
134       case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_NONE:
135         error_ = kInvalidSourceNameError;
136         return false;
137
138       case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_SCREEN:
139 #if defined(OS_WIN)
140         // ScreenCapturerWin disables Aero by default.
141         screen_capturer.reset(
142             webrtc::ScreenCapturer::CreateWithDisableAero(false));
143 #else
144         screen_capturer.reset(webrtc::ScreenCapturer::Create());
145 #endif
146         break;
147
148       case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_WINDOW:
149         window_capturer.reset(webrtc::WindowCapturer::Create());
150         break;
151
152       case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_TAB:
153         error_ = kTabCaptureNotSupportedError;
154         return false;
155     }
156   }
157
158   if (!screen_capturer && !window_capturer) {
159     error_ = kEmptySourcesListError;
160     return false;
161   }
162
163   scoped_ptr<DesktopMediaPickerModel> model;
164   if (g_picker_factory) {
165     model = g_picker_factory->CreateModel(
166         screen_capturer.Pass(), window_capturer.Pass());
167     picker_ = g_picker_factory->CreatePicker();
168   } else {
169     // DesktopMediaPicker is implemented only for Windows, OSX and
170     // Aura Linux builds.
171 #if (defined(TOOLKIT_VIEWS) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
172     model.reset(new DesktopMediaPickerModelImpl(
173         screen_capturer.Pass(), window_capturer.Pass()));
174     picker_ = DesktopMediaPicker::Create();
175 #else
176     const char kNotImplementedError[] =
177         "Desktop Capture API is not yet implemented for this platform.";
178     error_ = kNotImplementedError;
179     return false;
180 #endif
181   }
182   DesktopMediaPicker::DoneCallback callback = base::Bind(
183       &DesktopCaptureChooseDesktopMediaFunction::OnPickerDialogResults, this);
184
185   picker_->Show(parent_window, parent_window,
186                 UTF8ToUTF16(GetExtension()->name()),
187                 model.Pass(), callback);
188   return true;
189 }
190
191 void DesktopCaptureChooseDesktopMediaFunction::OnPickerDialogResults(
192     content::DesktopMediaID source) {
193   std::string result;
194   if (source.type != content::DesktopMediaID::TYPE_NONE) {
195     DesktopStreamsRegistry* registry =
196         MediaCaptureDevicesDispatcher::GetInstance()->
197         GetDesktopStreamsRegistry();
198     result = registry->RegisterStream(
199         render_process_id_, render_view_id_, origin_, source);
200   }
201
202   SetResult(new base::StringValue(result));
203   SendResponse(true);
204 }
205
206 DesktopCaptureRequestsRegistry::RequestId::RequestId(int process_id,
207                                                      int request_id)
208     : process_id(process_id),
209       request_id(request_id) {
210 }
211
212 bool DesktopCaptureRequestsRegistry::RequestId::operator<(
213     const RequestId& other) const {
214   if (process_id != other.process_id) {
215     return process_id < other.process_id;
216   } else {
217     return request_id < other.request_id;
218   }
219 }
220
221 DesktopCaptureCancelChooseDesktopMediaFunction::
222     DesktopCaptureCancelChooseDesktopMediaFunction() {}
223
224 DesktopCaptureCancelChooseDesktopMediaFunction::
225     ~DesktopCaptureCancelChooseDesktopMediaFunction() {}
226
227 bool DesktopCaptureCancelChooseDesktopMediaFunction::RunImpl() {
228   int request_id;
229   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id));
230
231   DesktopCaptureRequestsRegistry::GetInstance()->CancelRequest(
232       render_view_host()->GetProcess()->GetID(), request_id);
233   return true;
234 }
235
236 DesktopCaptureRequestsRegistry::DesktopCaptureRequestsRegistry() {}
237 DesktopCaptureRequestsRegistry::~DesktopCaptureRequestsRegistry() {}
238
239 // static
240 DesktopCaptureRequestsRegistry* DesktopCaptureRequestsRegistry::GetInstance() {
241   return Singleton<DesktopCaptureRequestsRegistry>::get();
242 }
243
244 void DesktopCaptureRequestsRegistry::AddRequest(
245     int process_id,
246     int request_id,
247     DesktopCaptureChooseDesktopMediaFunction* handler) {
248   requests_.insert(
249       RequestsMap::value_type(RequestId(process_id, request_id), handler));
250 }
251
252 void DesktopCaptureRequestsRegistry::RemoveRequest(int process_id,
253                                                    int request_id) {
254   requests_.erase(RequestId(process_id, request_id));
255 }
256
257 void DesktopCaptureRequestsRegistry::CancelRequest(int process_id,
258                                                    int request_id) {
259   RequestsMap::iterator it = requests_.find(RequestId(process_id, request_id));
260   if (it != requests_.end())
261     it->second->Cancel();
262 }
263
264
265 }  // namespace extensions