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