Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / media / media_stream_ui_proxy.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 "content/browser/renderer_host/media/media_stream_ui_proxy.h"
6
7 #include "base/command_line.h"
8 #include "content/browser/frame_host/render_frame_host_delegate.h"
9 #include "content/browser/frame_host/render_frame_host_impl.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/common/content_switches.h"
12 #include "media/video/capture/fake_video_capture_device.h"
13
14 namespace content {
15
16 class MediaStreamUIProxy::Core {
17  public:
18   explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
19                 RenderFrameHostDelegate* test_render_delegate);
20   ~Core();
21
22   void RequestAccess(const MediaStreamRequest& request);
23   bool CheckAccess(const GURL& security_origin,
24                    MediaStreamType type,
25                    int process_id,
26                    int frame_id);
27   void OnStarted(gfx::NativeViewId* window_id);
28
29  private:
30   void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
31                                     content::MediaStreamRequestResult result,
32                                     scoped_ptr<MediaStreamUI> stream_ui);
33   void ProcessStopRequestFromUI();
34   RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id,
35                                                       int render_frame_id);
36
37   base::WeakPtr<MediaStreamUIProxy> proxy_;
38   scoped_ptr<MediaStreamUI> ui_;
39
40   RenderFrameHostDelegate* const test_render_delegate_;
41
42   // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
43   // cancel media requests.
44   base::WeakPtrFactory<Core> weak_factory_;
45
46   DISALLOW_COPY_AND_ASSIGN(Core);
47 };
48
49 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
50                                RenderFrameHostDelegate* test_render_delegate)
51     : proxy_(proxy),
52       test_render_delegate_(test_render_delegate),
53       weak_factory_(this) {
54 }
55
56 MediaStreamUIProxy::Core::~Core() {
57   DCHECK_CURRENTLY_ON(BrowserThread::UI);
58 }
59
60 void MediaStreamUIProxy::Core::RequestAccess(
61     const MediaStreamRequest& request) {
62   DCHECK_CURRENTLY_ON(BrowserThread::UI);
63
64   RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate(
65       request.render_process_id, request.render_frame_id);
66
67   // Tab may have gone away, or has no delegate from which to request access.
68   if (!render_delegate) {
69     ProcessAccessRequestResponse(MediaStreamDevices(),
70                                  MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
71                                  scoped_ptr<MediaStreamUI>());
72     return;
73   }
74
75   render_delegate->RequestMediaAccessPermission(
76       request, base::Bind(&Core::ProcessAccessRequestResponse,
77                           weak_factory_.GetWeakPtr()));
78 }
79
80 bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin,
81                                            MediaStreamType type,
82                                            int render_process_id,
83                                            int render_frame_id) {
84   DCHECK_CURRENTLY_ON(BrowserThread::UI);
85
86   RenderFrameHostDelegate* render_delegate =
87       GetRenderFrameHostDelegate(render_process_id, render_frame_id);
88   if (!render_delegate)
89     return false;
90
91   return render_delegate->CheckMediaAccessPermission(security_origin, type);
92 }
93
94 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
95   DCHECK_CURRENTLY_ON(BrowserThread::UI);
96   if (ui_) {
97     *window_id = ui_->OnStarted(
98         base::Bind(&Core::ProcessStopRequestFromUI, base::Unretained(this)));
99   }
100 }
101
102 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
103     const MediaStreamDevices& devices,
104     content::MediaStreamRequestResult result,
105     scoped_ptr<MediaStreamUI> stream_ui) {
106   DCHECK_CURRENTLY_ON(BrowserThread::UI);
107
108   ui_ = stream_ui.Pass();
109   BrowserThread::PostTask(
110       BrowserThread::IO, FROM_HERE,
111       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
112                  proxy_, devices, result));
113 }
114
115 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
116   DCHECK_CURRENTLY_ON(BrowserThread::UI);
117
118   BrowserThread::PostTask(
119       BrowserThread::IO, FROM_HERE,
120       base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
121 }
122
123 RenderFrameHostDelegate* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate(
124     int render_process_id,
125     int render_frame_id) {
126   if (test_render_delegate_)
127     return test_render_delegate_;
128   RenderFrameHostImpl* host =
129       RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
130   return host ? host->delegate() : NULL;
131 }
132
133 // static
134 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
135   return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
136 }
137
138 // static
139 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
140     RenderFrameHostDelegate* render_delegate) {
141   return scoped_ptr<MediaStreamUIProxy>(
142       new MediaStreamUIProxy(render_delegate));
143 }
144
145 MediaStreamUIProxy::MediaStreamUIProxy(
146     RenderFrameHostDelegate* test_render_delegate)
147     : weak_factory_(this) {
148   DCHECK_CURRENTLY_ON(BrowserThread::IO);
149   core_.reset(new Core(weak_factory_.GetWeakPtr(), test_render_delegate));
150 }
151
152 MediaStreamUIProxy::~MediaStreamUIProxy() {
153   DCHECK_CURRENTLY_ON(BrowserThread::IO);
154 }
155
156 void MediaStreamUIProxy::RequestAccess(
157     const MediaStreamRequest& request,
158     const ResponseCallback& response_callback) {
159   DCHECK_CURRENTLY_ON(BrowserThread::IO);
160
161   response_callback_ = response_callback;
162   BrowserThread::PostTask(
163       BrowserThread::UI, FROM_HERE,
164       base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
165 }
166
167 void MediaStreamUIProxy::CheckAccess(
168     const GURL& security_origin,
169     MediaStreamType type,
170     int render_process_id,
171     int render_frame_id,
172     const base::Callback<void(bool)>& callback) {
173   DCHECK_CURRENTLY_ON(BrowserThread::IO);
174
175   BrowserThread::PostTaskAndReplyWithResult(
176       BrowserThread::UI,
177       FROM_HERE,
178       base::Bind(&Core::CheckAccess,
179                  base::Unretained(core_.get()),
180                  security_origin,
181                  type,
182                  render_process_id,
183                  render_frame_id),
184       base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
185                  weak_factory_.GetWeakPtr(),
186                  callback));
187 }
188
189 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback,
190                                    const WindowIdCallback& window_id_callback) {
191   DCHECK_CURRENTLY_ON(BrowserThread::IO);
192
193   stop_callback_ = stop_callback;
194
195   // Owned by the PostTaskAndReply callback.
196   gfx::NativeViewId* window_id = new gfx::NativeViewId(0);
197
198   BrowserThread::PostTaskAndReply(
199       BrowserThread::UI,
200       FROM_HERE,
201       base::Bind(&Core::OnStarted, base::Unretained(core_.get()), window_id),
202       base::Bind(&MediaStreamUIProxy::OnWindowId,
203                  weak_factory_.GetWeakPtr(),
204                  window_id_callback,
205                  base::Owned(window_id)));
206 }
207
208 void MediaStreamUIProxy::ProcessAccessRequestResponse(
209     const MediaStreamDevices& devices,
210     content::MediaStreamRequestResult result) {
211   DCHECK_CURRENTLY_ON(BrowserThread::IO);
212   DCHECK(!response_callback_.is_null());
213
214   ResponseCallback cb = response_callback_;
215   response_callback_.Reset();
216   cb.Run(devices, result);
217 }
218
219 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
220   DCHECK_CURRENTLY_ON(BrowserThread::IO);
221   DCHECK(!stop_callback_.is_null());
222
223   base::Closure cb = stop_callback_;
224   stop_callback_.Reset();
225   cb.Run();
226 }
227
228 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback,
229                                     gfx::NativeViewId* window_id) {
230   DCHECK_CURRENTLY_ON(BrowserThread::IO);
231   if (!window_id_callback.is_null())
232     window_id_callback.Run(*window_id);
233 }
234
235 void MediaStreamUIProxy::OnCheckedAccess(
236     const base::Callback<void(bool)>& callback,
237     bool have_access) {
238   DCHECK_CURRENTLY_ON(BrowserThread::IO);
239   if (!callback.is_null())
240     callback.Run(have_access);
241 }
242
243 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
244   : MediaStreamUIProxy(NULL),
245     mic_access_(true),
246     camera_access_(true) {
247 }
248
249 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
250
251 void FakeMediaStreamUIProxy::SetAvailableDevices(
252     const MediaStreamDevices& devices) {
253   devices_ = devices;
254 }
255
256 void FakeMediaStreamUIProxy::SetMicAccess(bool access) {
257   mic_access_ = access;
258 }
259
260 void FakeMediaStreamUIProxy::SetCameraAccess(bool access) {
261   camera_access_ = access;
262 }
263
264 void FakeMediaStreamUIProxy::RequestAccess(
265     const MediaStreamRequest& request,
266     const ResponseCallback& response_callback) {
267   DCHECK_CURRENTLY_ON(BrowserThread::IO);
268
269   response_callback_ = response_callback;
270
271   if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
272       switches::kUseFakeUIForMediaStream) == "deny") {
273     // Immediately deny the request.
274     BrowserThread::PostTask(
275           BrowserThread::IO, FROM_HERE,
276           base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
277                      weak_factory_.GetWeakPtr(),
278                      MediaStreamDevices(),
279                      MEDIA_DEVICE_PERMISSION_DENIED));
280     return;
281   }
282
283   MediaStreamDevices devices_to_use;
284   bool accepted_audio = false;
285   bool accepted_video = false;
286
287   // Use the first capture device of the same media type in the list for the
288   // fake UI.
289   for (MediaStreamDevices::const_iterator it = devices_.begin();
290        it != devices_.end(); ++it) {
291     if (!accepted_audio &&
292         IsAudioInputMediaType(request.audio_type) &&
293         IsAudioInputMediaType(it->type) &&
294         (request.requested_audio_device_id.empty() ||
295          request.requested_audio_device_id == it->id)) {
296       devices_to_use.push_back(*it);
297       accepted_audio = true;
298     } else if (!accepted_video &&
299                IsVideoMediaType(request.video_type) &&
300                IsVideoMediaType(it->type) &&
301                (request.requested_video_device_id.empty() ||
302                 request.requested_video_device_id == it->id)) {
303       devices_to_use.push_back(*it);
304       accepted_video = true;
305     }
306   }
307
308   // Fail the request if a device doesn't exist for the requested type.
309   if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) ||
310       (request.video_type != MEDIA_NO_SERVICE && !accepted_video)) {
311     devices_to_use.clear();
312   }
313
314   BrowserThread::PostTask(
315       BrowserThread::IO, FROM_HERE,
316       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
317                  weak_factory_.GetWeakPtr(),
318                  devices_to_use,
319                  devices_to_use.empty() ?
320                      MEDIA_DEVICE_NO_HARDWARE :
321                      MEDIA_DEVICE_OK));
322 }
323
324 void FakeMediaStreamUIProxy::CheckAccess(
325     const GURL& security_origin,
326     MediaStreamType type,
327     int render_process_id,
328     int render_frame_id,
329     const base::Callback<void(bool)>& callback) {
330   DCHECK_CURRENTLY_ON(BrowserThread::IO);
331   DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
332          type == MEDIA_DEVICE_VIDEO_CAPTURE);
333
334   bool have_access = false;
335   if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
336       switches::kUseFakeUIForMediaStream) != "deny") {
337     have_access =
338         type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_;
339   }
340
341   BrowserThread::PostTask(
342       BrowserThread::IO,
343       FROM_HERE,
344       base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
345                  weak_factory_.GetWeakPtr(),
346                  callback,
347                  have_access));
348   return;
349 }
350
351 void FakeMediaStreamUIProxy::OnStarted(
352     const base::Closure& stop_callback,
353     const WindowIdCallback& window_id_callback) {}
354
355 }  // namespace content