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.
5 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
7 #include "base/command_line.h"
8 #include "content/browser/frame_host/frame_tree_node.h"
9 #include "content/browser/frame_host/render_frame_host_delegate.h"
10 #include "content/browser/frame_host/render_frame_host_impl.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/common/content_switches.h"
13 #include "media/capture/video/fake_video_capture_device.h"
17 void SetAndCheckAncestorFlag(MediaStreamRequest
* request
) {
18 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
19 RenderFrameHostImpl
* rfh
=
20 RenderFrameHostImpl::FromID(request
->render_process_id
,
21 request
->render_frame_id
);
24 // RenderFrame destroyed before the request is handled?
27 FrameTreeNode
* node
= rfh
->frame_tree_node();
29 while (node
->parent() != NULL
) {
30 if (!node
->HasSameOrigin(*node
->parent())) {
31 request
->all_ancestors_have_same_origin
= false;
34 node
= node
->parent();
36 request
->all_ancestors_have_same_origin
= true;
39 class MediaStreamUIProxy::Core
{
41 explicit Core(const base::WeakPtr
<MediaStreamUIProxy
>& proxy
,
42 RenderFrameHostDelegate
* test_render_delegate
);
45 void RequestAccess(scoped_ptr
<MediaStreamRequest
> request
);
46 bool CheckAccess(const GURL
& security_origin
,
50 void OnStarted(gfx::NativeViewId
* window_id
);
53 void ProcessAccessRequestResponse(const MediaStreamDevices
& devices
,
54 content::MediaStreamRequestResult result
,
55 scoped_ptr
<MediaStreamUI
> stream_ui
);
56 void ProcessStopRequestFromUI();
57 RenderFrameHostDelegate
* GetRenderFrameHostDelegate(int render_process_id
,
60 base::WeakPtr
<MediaStreamUIProxy
> proxy_
;
61 scoped_ptr
<MediaStreamUI
> ui_
;
63 RenderFrameHostDelegate
* const test_render_delegate_
;
65 // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
66 // cancel media requests.
67 base::WeakPtrFactory
<Core
> weak_factory_
;
69 DISALLOW_COPY_AND_ASSIGN(Core
);
72 MediaStreamUIProxy::Core::Core(const base::WeakPtr
<MediaStreamUIProxy
>& proxy
,
73 RenderFrameHostDelegate
* test_render_delegate
)
75 test_render_delegate_(test_render_delegate
),
79 MediaStreamUIProxy::Core::~Core() {
80 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
83 void MediaStreamUIProxy::Core::RequestAccess(
84 scoped_ptr
<MediaStreamRequest
> request
) {
85 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
87 RenderFrameHostDelegate
* render_delegate
= GetRenderFrameHostDelegate(
88 request
->render_process_id
, request
->render_frame_id
);
90 // Tab may have gone away, or has no delegate from which to request access.
91 if (!render_delegate
) {
92 ProcessAccessRequestResponse(MediaStreamDevices(),
93 MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN
,
94 scoped_ptr
<MediaStreamUI
>());
97 SetAndCheckAncestorFlag(request
.get());
99 render_delegate
->RequestMediaAccessPermission(
100 *request
, base::Bind(&Core::ProcessAccessRequestResponse
,
101 weak_factory_
.GetWeakPtr()));
104 bool MediaStreamUIProxy::Core::CheckAccess(const GURL
& security_origin
,
105 MediaStreamType type
,
106 int render_process_id
,
107 int render_frame_id
) {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
110 RenderFrameHostDelegate
* render_delegate
=
111 GetRenderFrameHostDelegate(render_process_id
, render_frame_id
);
112 if (!render_delegate
)
115 return render_delegate
->CheckMediaAccessPermission(security_origin
, type
);
118 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId
* window_id
) {
119 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
121 *window_id
= ui_
->OnStarted(
122 base::Bind(&Core::ProcessStopRequestFromUI
, base::Unretained(this)));
126 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
127 const MediaStreamDevices
& devices
,
128 content::MediaStreamRequestResult result
,
129 scoped_ptr
<MediaStreamUI
> stream_ui
) {
130 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
132 ui_
= stream_ui
.Pass();
133 BrowserThread::PostTask(
134 BrowserThread::IO
, FROM_HERE
,
135 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
136 proxy_
, devices
, result
));
139 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
140 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
142 BrowserThread::PostTask(
143 BrowserThread::IO
, FROM_HERE
,
144 base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI
, proxy_
));
147 RenderFrameHostDelegate
* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate(
148 int render_process_id
,
149 int render_frame_id
) {
150 if (test_render_delegate_
)
151 return test_render_delegate_
;
152 RenderFrameHostImpl
* host
=
153 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
154 return host
? host
->delegate() : NULL
;
158 scoped_ptr
<MediaStreamUIProxy
> MediaStreamUIProxy::Create() {
159 return scoped_ptr
<MediaStreamUIProxy
>(new MediaStreamUIProxy(NULL
));
163 scoped_ptr
<MediaStreamUIProxy
> MediaStreamUIProxy::CreateForTests(
164 RenderFrameHostDelegate
* render_delegate
) {
165 return scoped_ptr
<MediaStreamUIProxy
>(
166 new MediaStreamUIProxy(render_delegate
));
169 MediaStreamUIProxy::MediaStreamUIProxy(
170 RenderFrameHostDelegate
* test_render_delegate
)
171 : weak_factory_(this) {
172 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
173 core_
.reset(new Core(weak_factory_
.GetWeakPtr(), test_render_delegate
));
176 MediaStreamUIProxy::~MediaStreamUIProxy() {
177 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
180 void MediaStreamUIProxy::RequestAccess(
181 scoped_ptr
<MediaStreamRequest
> request
,
182 const ResponseCallback
& response_callback
) {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
185 response_callback_
= response_callback
;
186 BrowserThread::PostTask(
187 BrowserThread::UI
, FROM_HERE
,
188 base::Bind(&Core::RequestAccess
, base::Unretained(core_
.get()),
189 base::Passed(&request
)));
192 void MediaStreamUIProxy::CheckAccess(
193 const GURL
& security_origin
,
194 MediaStreamType type
,
195 int render_process_id
,
197 const base::Callback
<void(bool)>& callback
) {
198 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
200 BrowserThread::PostTaskAndReplyWithResult(
203 base::Bind(&Core::CheckAccess
,
204 base::Unretained(core_
.get()),
209 base::Bind(&MediaStreamUIProxy::OnCheckedAccess
,
210 weak_factory_
.GetWeakPtr(),
214 void MediaStreamUIProxy::OnStarted(const base::Closure
& stop_callback
,
215 const WindowIdCallback
& window_id_callback
) {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
218 stop_callback_
= stop_callback
;
220 // Owned by the PostTaskAndReply callback.
221 gfx::NativeViewId
* window_id
= new gfx::NativeViewId(0);
223 BrowserThread::PostTaskAndReply(
226 base::Bind(&Core::OnStarted
, base::Unretained(core_
.get()), window_id
),
227 base::Bind(&MediaStreamUIProxy::OnWindowId
,
228 weak_factory_
.GetWeakPtr(),
230 base::Owned(window_id
)));
233 void MediaStreamUIProxy::ProcessAccessRequestResponse(
234 const MediaStreamDevices
& devices
,
235 content::MediaStreamRequestResult result
) {
236 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
237 DCHECK(!response_callback_
.is_null());
239 ResponseCallback cb
= response_callback_
;
240 response_callback_
.Reset();
241 cb
.Run(devices
, result
);
244 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
245 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
246 DCHECK(!stop_callback_
.is_null());
248 base::Closure cb
= stop_callback_
;
249 stop_callback_
.Reset();
253 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback
& window_id_callback
,
254 gfx::NativeViewId
* window_id
) {
255 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
256 if (!window_id_callback
.is_null())
257 window_id_callback
.Run(*window_id
);
260 void MediaStreamUIProxy::OnCheckedAccess(
261 const base::Callback
<void(bool)>& callback
,
263 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
264 if (!callback
.is_null())
265 callback
.Run(have_access
);
268 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
269 : MediaStreamUIProxy(NULL
),
271 camera_access_(true) {
274 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
276 void FakeMediaStreamUIProxy::SetAvailableDevices(
277 const MediaStreamDevices
& devices
) {
281 void FakeMediaStreamUIProxy::SetMicAccess(bool access
) {
282 mic_access_
= access
;
285 void FakeMediaStreamUIProxy::SetCameraAccess(bool access
) {
286 camera_access_
= access
;
289 void FakeMediaStreamUIProxy::RequestAccess(
290 scoped_ptr
<MediaStreamRequest
> request
,
291 const ResponseCallback
& response_callback
) {
292 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
294 response_callback_
= response_callback
;
296 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
297 switches::kUseFakeUIForMediaStream
) == "deny") {
298 // Immediately deny the request.
299 BrowserThread::PostTask(
300 BrowserThread::IO
, FROM_HERE
,
301 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
302 weak_factory_
.GetWeakPtr(),
303 MediaStreamDevices(),
304 MEDIA_DEVICE_PERMISSION_DENIED
));
308 MediaStreamDevices devices_to_use
;
309 bool accepted_audio
= false;
310 bool accepted_video
= false;
312 // Use the first capture device of the same media type in the list for the
314 for (MediaStreamDevices::const_iterator it
= devices_
.begin();
315 it
!= devices_
.end(); ++it
) {
316 if (!accepted_audio
&&
317 IsAudioInputMediaType(request
->audio_type
) &&
318 IsAudioInputMediaType(it
->type
) &&
319 (request
->requested_audio_device_id
.empty() ||
320 request
->requested_audio_device_id
== it
->id
)) {
321 devices_to_use
.push_back(*it
);
322 accepted_audio
= true;
323 } else if (!accepted_video
&&
324 IsVideoMediaType(request
->video_type
) &&
325 IsVideoMediaType(it
->type
) &&
326 (request
->requested_video_device_id
.empty() ||
327 request
->requested_video_device_id
== it
->id
)) {
328 devices_to_use
.push_back(*it
);
329 accepted_video
= true;
333 // Fail the request if a device doesn't exist for the requested type.
334 if ((request
->audio_type
!= MEDIA_NO_SERVICE
&& !accepted_audio
) ||
335 (request
->video_type
!= MEDIA_NO_SERVICE
&& !accepted_video
)) {
336 devices_to_use
.clear();
339 BrowserThread::PostTask(
340 BrowserThread::IO
, FROM_HERE
,
341 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
342 weak_factory_
.GetWeakPtr(),
344 devices_to_use
.empty() ?
345 MEDIA_DEVICE_NO_HARDWARE
:
349 void FakeMediaStreamUIProxy::CheckAccess(
350 const GURL
& security_origin
,
351 MediaStreamType type
,
352 int render_process_id
,
354 const base::Callback
<void(bool)>& callback
) {
355 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
356 DCHECK(type
== MEDIA_DEVICE_AUDIO_CAPTURE
||
357 type
== MEDIA_DEVICE_VIDEO_CAPTURE
);
359 bool have_access
= false;
360 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
361 switches::kUseFakeUIForMediaStream
) != "deny") {
363 type
== MEDIA_DEVICE_AUDIO_CAPTURE
? mic_access_
: camera_access_
;
366 BrowserThread::PostTask(
369 base::Bind(&MediaStreamUIProxy::OnCheckedAccess
,
370 weak_factory_
.GetWeakPtr(),
376 void FakeMediaStreamUIProxy::OnStarted(
377 const base::Closure
& stop_callback
,
378 const WindowIdCallback
& window_id_callback
) {}
380 } // namespace content