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 bool CheckAccess(const GURL& security_origin,
27 void OnStarted(gfx::NativeViewId* window_id);
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,
37 base::WeakPtr<MediaStreamUIProxy> proxy_;
38 scoped_ptr<MediaStreamUI> ui_;
40 RenderFrameHostDelegate* const test_render_delegate_;
42 // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
43 // cancel media requests.
44 base::WeakPtrFactory<Core> weak_factory_;
46 DISALLOW_COPY_AND_ASSIGN(Core);
49 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
50 RenderFrameHostDelegate* test_render_delegate)
52 test_render_delegate_(test_render_delegate),
56 MediaStreamUIProxy::Core::~Core() {
57 DCHECK_CURRENTLY_ON(BrowserThread::UI);
60 void MediaStreamUIProxy::Core::RequestAccess(
61 const MediaStreamRequest& request) {
62 DCHECK_CURRENTLY_ON(BrowserThread::UI);
64 RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate(
65 request.render_process_id, request.render_frame_id);
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>());
75 render_delegate->RequestMediaAccessPermission(
76 request, base::Bind(&Core::ProcessAccessRequestResponse,
77 weak_factory_.GetWeakPtr()));
80 bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin,
82 int render_process_id,
83 int render_frame_id) {
84 DCHECK_CURRENTLY_ON(BrowserThread::UI);
86 RenderFrameHostDelegate* render_delegate =
87 GetRenderFrameHostDelegate(render_process_id, render_frame_id);
91 return render_delegate->CheckMediaAccessPermission(security_origin, type);
94 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
95 DCHECK_CURRENTLY_ON(BrowserThread::UI);
97 *window_id = ui_->OnStarted(
98 base::Bind(&Core::ProcessStopRequestFromUI, base::Unretained(this)));
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);
108 ui_ = stream_ui.Pass();
109 BrowserThread::PostTask(
110 BrowserThread::IO, FROM_HERE,
111 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
112 proxy_, devices, result));
115 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
116 DCHECK_CURRENTLY_ON(BrowserThread::UI);
118 BrowserThread::PostTask(
119 BrowserThread::IO, FROM_HERE,
120 base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
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;
134 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
135 return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
139 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
140 RenderFrameHostDelegate* render_delegate) {
141 return scoped_ptr<MediaStreamUIProxy>(
142 new MediaStreamUIProxy(render_delegate));
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));
152 MediaStreamUIProxy::~MediaStreamUIProxy() {
153 DCHECK_CURRENTLY_ON(BrowserThread::IO);
156 void MediaStreamUIProxy::RequestAccess(
157 const MediaStreamRequest& request,
158 const ResponseCallback& response_callback) {
159 DCHECK_CURRENTLY_ON(BrowserThread::IO);
161 response_callback_ = response_callback;
162 BrowserThread::PostTask(
163 BrowserThread::UI, FROM_HERE,
164 base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
167 void MediaStreamUIProxy::CheckAccess(
168 const GURL& security_origin,
169 MediaStreamType type,
170 int render_process_id,
172 const base::Callback<void(bool)>& callback) {
173 DCHECK_CURRENTLY_ON(BrowserThread::IO);
175 BrowserThread::PostTaskAndReplyWithResult(
178 base::Bind(&Core::CheckAccess,
179 base::Unretained(core_.get()),
184 base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
185 weak_factory_.GetWeakPtr(),
189 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback,
190 const WindowIdCallback& window_id_callback) {
191 DCHECK_CURRENTLY_ON(BrowserThread::IO);
193 stop_callback_ = stop_callback;
195 // Owned by the PostTaskAndReply callback.
196 gfx::NativeViewId* window_id = new gfx::NativeViewId(0);
198 BrowserThread::PostTaskAndReply(
201 base::Bind(&Core::OnStarted, base::Unretained(core_.get()), window_id),
202 base::Bind(&MediaStreamUIProxy::OnWindowId,
203 weak_factory_.GetWeakPtr(),
205 base::Owned(window_id)));
208 void MediaStreamUIProxy::ProcessAccessRequestResponse(
209 const MediaStreamDevices& devices,
210 content::MediaStreamRequestResult result) {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO);
212 DCHECK(!response_callback_.is_null());
214 ResponseCallback cb = response_callback_;
215 response_callback_.Reset();
216 cb.Run(devices, result);
219 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
220 DCHECK_CURRENTLY_ON(BrowserThread::IO);
221 DCHECK(!stop_callback_.is_null());
223 base::Closure cb = stop_callback_;
224 stop_callback_.Reset();
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);
235 void MediaStreamUIProxy::OnCheckedAccess(
236 const base::Callback<void(bool)>& callback,
238 DCHECK_CURRENTLY_ON(BrowserThread::IO);
239 if (!callback.is_null())
240 callback.Run(have_access);
243 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
244 : MediaStreamUIProxy(NULL),
246 camera_access_(true) {
249 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
251 void FakeMediaStreamUIProxy::SetAvailableDevices(
252 const MediaStreamDevices& devices) {
256 void FakeMediaStreamUIProxy::SetMicAccess(bool access) {
257 mic_access_ = access;
260 void FakeMediaStreamUIProxy::SetCameraAccess(bool access) {
261 camera_access_ = access;
264 void FakeMediaStreamUIProxy::RequestAccess(
265 const MediaStreamRequest& request,
266 const ResponseCallback& response_callback) {
267 DCHECK_CURRENTLY_ON(BrowserThread::IO);
269 response_callback_ = response_callback;
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));
283 MediaStreamDevices devices_to_use;
284 bool accepted_audio = false;
285 bool accepted_video = false;
287 // Use the first capture device of the same media type in the list for the
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;
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();
314 BrowserThread::PostTask(
315 BrowserThread::IO, FROM_HERE,
316 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
317 weak_factory_.GetWeakPtr(),
319 devices_to_use.empty() ?
320 MEDIA_DEVICE_NO_HARDWARE :
324 void FakeMediaStreamUIProxy::CheckAccess(
325 const GURL& security_origin,
326 MediaStreamType type,
327 int render_process_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);
334 bool have_access = false;
335 if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
336 switches::kUseFakeUIForMediaStream) != "deny") {
338 type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_;
341 BrowserThread::PostTask(
344 base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
345 weak_factory_.GetWeakPtr(),
351 void FakeMediaStreamUIProxy::OnStarted(
352 const base::Closure& stop_callback,
353 const WindowIdCallback& window_id_callback) {}
355 } // namespace content