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/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"
16 class MediaStreamUIProxy::Core
{
18 explicit Core(const base::WeakPtr
<MediaStreamUIProxy
>& proxy
,
19 RenderFrameHostDelegate
* test_render_delegate
);
22 void RequestAccess(const MediaStreamRequest
& request
);
23 void OnStarted(gfx::NativeViewId
* window_id
);
26 void ProcessAccessRequestResponse(const MediaStreamDevices
& devices
,
27 content::MediaStreamRequestResult result
,
28 scoped_ptr
<MediaStreamUI
> stream_ui
);
29 void ProcessStopRequestFromUI();
31 base::WeakPtr
<MediaStreamUIProxy
> proxy_
;
32 scoped_ptr
<MediaStreamUI
> ui_
;
34 RenderFrameHostDelegate
* const test_render_delegate_
;
36 // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
37 // cancel media requests.
38 base::WeakPtrFactory
<Core
> weak_factory_
;
40 DISALLOW_COPY_AND_ASSIGN(Core
);
43 MediaStreamUIProxy::Core::Core(const base::WeakPtr
<MediaStreamUIProxy
>& proxy
,
44 RenderFrameHostDelegate
* test_render_delegate
)
46 test_render_delegate_(test_render_delegate
),
50 MediaStreamUIProxy::Core::~Core() {
51 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
54 void MediaStreamUIProxy::Core::RequestAccess(
55 const MediaStreamRequest
& request
) {
56 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
58 RenderFrameHostDelegate
* render_delegate
;
59 if (test_render_delegate_
) {
60 render_delegate
= test_render_delegate_
;
62 RenderFrameHostImpl
* const host
= RenderFrameHostImpl::FromID(
63 request
.render_process_id
, request
.render_frame_id
);
64 render_delegate
= host
? host
->delegate() : NULL
;
67 // Tab may have gone away, or has no delegate from which to request access.
68 if (!render_delegate
) {
69 ProcessAccessRequestResponse(
71 MEDIA_DEVICE_INVALID_STATE
,
72 scoped_ptr
<MediaStreamUI
>());
76 render_delegate
->RequestMediaAccessPermission(
77 request
, base::Bind(&Core::ProcessAccessRequestResponse
,
78 weak_factory_
.GetWeakPtr()));
81 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId
* window_id
) {
82 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
84 *window_id
= ui_
->OnStarted(
85 base::Bind(&Core::ProcessStopRequestFromUI
, base::Unretained(this)));
89 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
90 const MediaStreamDevices
& devices
,
91 content::MediaStreamRequestResult result
,
92 scoped_ptr
<MediaStreamUI
> stream_ui
) {
93 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
95 ui_
= stream_ui
.Pass();
96 BrowserThread::PostTask(
97 BrowserThread::IO
, FROM_HERE
,
98 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
99 proxy_
, devices
, result
));
102 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
103 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
105 BrowserThread::PostTask(
106 BrowserThread::IO
, FROM_HERE
,
107 base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI
, proxy_
));
111 scoped_ptr
<MediaStreamUIProxy
> MediaStreamUIProxy::Create() {
112 return scoped_ptr
<MediaStreamUIProxy
>(new MediaStreamUIProxy(NULL
));
116 scoped_ptr
<MediaStreamUIProxy
> MediaStreamUIProxy::CreateForTests(
117 RenderFrameHostDelegate
* render_delegate
) {
118 return scoped_ptr
<MediaStreamUIProxy
>(
119 new MediaStreamUIProxy(render_delegate
));
122 MediaStreamUIProxy::MediaStreamUIProxy(
123 RenderFrameHostDelegate
* test_render_delegate
)
124 : weak_factory_(this) {
125 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
126 core_
.reset(new Core(weak_factory_
.GetWeakPtr(), test_render_delegate
));
129 MediaStreamUIProxy::~MediaStreamUIProxy() {
130 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
133 void MediaStreamUIProxy::RequestAccess(
134 const MediaStreamRequest
& request
,
135 const ResponseCallback
& response_callback
) {
136 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
138 response_callback_
= response_callback
;
139 BrowserThread::PostTask(
140 BrowserThread::UI
, FROM_HERE
,
141 base::Bind(&Core::RequestAccess
, base::Unretained(core_
.get()), request
));
144 void MediaStreamUIProxy::OnStarted(const base::Closure
& stop_callback
,
145 const WindowIdCallback
& window_id_callback
) {
146 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
148 stop_callback_
= stop_callback
;
150 // Owned by the PostTaskAndReply callback.
151 gfx::NativeViewId
* window_id
= new gfx::NativeViewId(0);
153 BrowserThread::PostTaskAndReply(
156 base::Bind(&Core::OnStarted
, base::Unretained(core_
.get()), window_id
),
157 base::Bind(&MediaStreamUIProxy::OnWindowId
,
158 weak_factory_
.GetWeakPtr(),
160 base::Owned(window_id
)));
163 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback
& window_id_callback
,
164 gfx::NativeViewId
* window_id
) {
165 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
166 if (!window_id_callback
.is_null())
167 window_id_callback
.Run(*window_id
);
170 void MediaStreamUIProxy::ProcessAccessRequestResponse(
171 const MediaStreamDevices
& devices
,
172 content::MediaStreamRequestResult result
) {
173 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
174 DCHECK(!response_callback_
.is_null());
176 ResponseCallback cb
= response_callback_
;
177 response_callback_
.Reset();
178 cb
.Run(devices
, result
);
181 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
182 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
183 DCHECK(!stop_callback_
.is_null());
185 base::Closure cb
= stop_callback_
;
186 stop_callback_
.Reset();
190 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
191 : MediaStreamUIProxy(NULL
) {
194 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
196 void FakeMediaStreamUIProxy::SetAvailableDevices(
197 const MediaStreamDevices
& devices
) {
201 void FakeMediaStreamUIProxy::RequestAccess(
202 const MediaStreamRequest
& request
,
203 const ResponseCallback
& response_callback
) {
204 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
206 response_callback_
= response_callback
;
208 if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
209 switches::kUseFakeUIForMediaStream
) == "deny") {
210 // Immediately deny the request.
211 BrowserThread::PostTask(
212 BrowserThread::IO
, FROM_HERE
,
213 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
214 weak_factory_
.GetWeakPtr(),
215 MediaStreamDevices(),
216 MEDIA_DEVICE_PERMISSION_DENIED
));
220 MediaStreamDevices devices_to_use
;
221 bool accepted_audio
= false;
222 bool accepted_video
= false;
224 // Use the first capture device of the same media type in the list for the
226 for (MediaStreamDevices::const_iterator it
= devices_
.begin();
227 it
!= devices_
.end(); ++it
) {
228 if (!accepted_audio
&&
229 IsAudioInputMediaType(request
.audio_type
) &&
230 IsAudioInputMediaType(it
->type
) &&
231 (request
.requested_audio_device_id
.empty() ||
232 request
.requested_audio_device_id
== it
->id
)) {
233 devices_to_use
.push_back(*it
);
234 accepted_audio
= true;
235 } else if (!accepted_video
&&
236 IsVideoMediaType(request
.video_type
) &&
237 IsVideoMediaType(it
->type
) &&
238 (request
.requested_video_device_id
.empty() ||
239 request
.requested_video_device_id
== it
->id
)) {
240 devices_to_use
.push_back(*it
);
241 accepted_video
= true;
245 // Fail the request if a device exist for the requested type.
246 if ((request
.audio_type
!= MEDIA_NO_SERVICE
&& !accepted_audio
) ||
247 (request
.video_type
!= MEDIA_NO_SERVICE
&& !accepted_video
)) {
248 devices_to_use
.clear();
251 BrowserThread::PostTask(
252 BrowserThread::IO
, FROM_HERE
,
253 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse
,
254 weak_factory_
.GetWeakPtr(),
256 devices_to_use
.empty() ?
257 MEDIA_DEVICE_NO_HARDWARE
:
261 void FakeMediaStreamUIProxy::OnStarted(
262 const base::Closure
& stop_callback
,
263 const WindowIdCallback
& window_id_callback
) {}
265 } // namespace content