• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/renderer_host/render_view_host_delegate.h"
9 #include "content/browser/renderer_host/render_view_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                 RenderViewHostDelegate* test_render_delegate);
20   ~Core();
21 
22   void RequestAccess(const MediaStreamRequest& request);
23   void OnStarted(gfx::NativeViewId* window_id);
24 
25  private:
26   void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
27                                     content::MediaStreamRequestResult result,
28                                     scoped_ptr<MediaStreamUI> stream_ui);
29   void ProcessStopRequestFromUI();
30 
31   base::WeakPtr<MediaStreamUIProxy> proxy_;
32   scoped_ptr<MediaStreamUI> ui_;
33 
34   RenderViewHostDelegate* const test_render_delegate_;
35 
36   // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
37   // cancel media requests.
38   base::WeakPtrFactory<Core> weak_factory_;
39 
40   DISALLOW_COPY_AND_ASSIGN(Core);
41 };
42 
Core(const base::WeakPtr<MediaStreamUIProxy> & proxy,RenderViewHostDelegate * test_render_delegate)43 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
44                                RenderViewHostDelegate* test_render_delegate)
45     : proxy_(proxy),
46       test_render_delegate_(test_render_delegate),
47       weak_factory_(this) {
48 }
49 
~Core()50 MediaStreamUIProxy::Core::~Core() {
51   DCHECK_CURRENTLY_ON(BrowserThread::UI);
52 }
53 
RequestAccess(const MediaStreamRequest & request)54 void MediaStreamUIProxy::Core::RequestAccess(
55     const MediaStreamRequest& request) {
56   DCHECK_CURRENTLY_ON(BrowserThread::UI);
57 
58   RenderViewHostDelegate* render_delegate;
59 
60   if (test_render_delegate_) {
61     render_delegate = test_render_delegate_;
62   } else {
63     RenderViewHostImpl* host = RenderViewHostImpl::FromID(
64         request.render_process_id, request.render_view_id);
65 
66     // Tab may have gone away.
67     if (!host || !host->GetDelegate()) {
68       ProcessAccessRequestResponse(
69           MediaStreamDevices(),
70           MEDIA_DEVICE_INVALID_STATE,
71           scoped_ptr<MediaStreamUI>());
72       return;
73     }
74 
75     render_delegate = host->GetDelegate();
76   }
77 
78   render_delegate->RequestMediaAccessPermission(
79       request, base::Bind(&Core::ProcessAccessRequestResponse,
80                           weak_factory_.GetWeakPtr()));
81 }
82 
OnStarted(gfx::NativeViewId * window_id)83 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
84   DCHECK_CURRENTLY_ON(BrowserThread::UI);
85   if (ui_) {
86     *window_id = ui_->OnStarted(
87         base::Bind(&Core::ProcessStopRequestFromUI, base::Unretained(this)));
88   }
89 }
90 
ProcessAccessRequestResponse(const MediaStreamDevices & devices,content::MediaStreamRequestResult result,scoped_ptr<MediaStreamUI> stream_ui)91 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
92     const MediaStreamDevices& devices,
93     content::MediaStreamRequestResult result,
94     scoped_ptr<MediaStreamUI> stream_ui) {
95   DCHECK_CURRENTLY_ON(BrowserThread::UI);
96 
97   ui_ = stream_ui.Pass();
98   BrowserThread::PostTask(
99       BrowserThread::IO, FROM_HERE,
100       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
101                  proxy_, devices, result));
102 }
103 
ProcessStopRequestFromUI()104 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
105   DCHECK_CURRENTLY_ON(BrowserThread::UI);
106 
107   BrowserThread::PostTask(
108       BrowserThread::IO, FROM_HERE,
109       base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
110 }
111 
112 // static
Create()113 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
114   return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
115 }
116 
117 // static
CreateForTests(RenderViewHostDelegate * render_delegate)118 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
119     RenderViewHostDelegate* render_delegate) {
120   return scoped_ptr<MediaStreamUIProxy>(
121       new MediaStreamUIProxy(render_delegate));
122 }
123 
MediaStreamUIProxy(RenderViewHostDelegate * test_render_delegate)124 MediaStreamUIProxy::MediaStreamUIProxy(
125     RenderViewHostDelegate* test_render_delegate)
126     : weak_factory_(this) {
127   DCHECK_CURRENTLY_ON(BrowserThread::IO);
128   core_.reset(new Core(weak_factory_.GetWeakPtr(), test_render_delegate));
129 }
130 
~MediaStreamUIProxy()131 MediaStreamUIProxy::~MediaStreamUIProxy() {
132   DCHECK_CURRENTLY_ON(BrowserThread::IO);
133   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release());
134 }
135 
RequestAccess(const MediaStreamRequest & request,const ResponseCallback & response_callback)136 void MediaStreamUIProxy::RequestAccess(
137     const MediaStreamRequest& request,
138     const ResponseCallback& response_callback) {
139   DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 
141   response_callback_ = response_callback;
142   BrowserThread::PostTask(
143       BrowserThread::UI, FROM_HERE,
144       base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
145 }
146 
OnStarted(const base::Closure & stop_callback,const WindowIdCallback & window_id_callback)147 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback,
148                                    const WindowIdCallback& window_id_callback) {
149   DCHECK_CURRENTLY_ON(BrowserThread::IO);
150 
151   stop_callback_ = stop_callback;
152 
153   // Owned by the PostTaskAndReply callback.
154   gfx::NativeViewId* window_id = new gfx::NativeViewId(0);
155 
156   BrowserThread::PostTaskAndReply(
157       BrowserThread::UI,
158       FROM_HERE,
159       base::Bind(&Core::OnStarted, base::Unretained(core_.get()), window_id),
160       base::Bind(&MediaStreamUIProxy::OnWindowId,
161                  weak_factory_.GetWeakPtr(),
162                  window_id_callback,
163                  base::Owned(window_id)));
164 }
165 
OnWindowId(const WindowIdCallback & window_id_callback,gfx::NativeViewId * window_id)166 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback,
167                                     gfx::NativeViewId* window_id) {
168   DCHECK_CURRENTLY_ON(BrowserThread::IO);
169   if (!window_id_callback.is_null())
170     window_id_callback.Run(*window_id);
171 }
172 
ProcessAccessRequestResponse(const MediaStreamDevices & devices,content::MediaStreamRequestResult result)173 void MediaStreamUIProxy::ProcessAccessRequestResponse(
174     const MediaStreamDevices& devices,
175     content::MediaStreamRequestResult result) {
176   DCHECK_CURRENTLY_ON(BrowserThread::IO);
177   DCHECK(!response_callback_.is_null());
178 
179   ResponseCallback cb = response_callback_;
180   response_callback_.Reset();
181   cb.Run(devices, result);
182 }
183 
ProcessStopRequestFromUI()184 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
185   DCHECK_CURRENTLY_ON(BrowserThread::IO);
186   DCHECK(!stop_callback_.is_null());
187 
188   base::Closure cb = stop_callback_;
189   stop_callback_.Reset();
190   cb.Run();
191 }
192 
FakeMediaStreamUIProxy()193 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
194   : MediaStreamUIProxy(NULL) {
195 }
196 
~FakeMediaStreamUIProxy()197 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
198 
SetAvailableDevices(const MediaStreamDevices & devices)199 void FakeMediaStreamUIProxy::SetAvailableDevices(
200     const MediaStreamDevices& devices) {
201   devices_ = devices;
202 }
203 
RequestAccess(const MediaStreamRequest & request,const ResponseCallback & response_callback)204 void FakeMediaStreamUIProxy::RequestAccess(
205     const MediaStreamRequest& request,
206     const ResponseCallback& response_callback) {
207   DCHECK_CURRENTLY_ON(BrowserThread::IO);
208 
209   response_callback_ = response_callback;
210 
211   if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
212       switches::kUseFakeUIForMediaStream) == "deny") {
213     // Immediately deny the request.
214     BrowserThread::PostTask(
215           BrowserThread::IO, FROM_HERE,
216           base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
217                      weak_factory_.GetWeakPtr(),
218                      MediaStreamDevices(),
219                      MEDIA_DEVICE_PERMISSION_DENIED));
220     return;
221   }
222 
223   MediaStreamDevices devices_to_use;
224   bool accepted_audio = false;
225   bool accepted_video = false;
226 
227   // Use the first capture device of the same media type in the list for the
228   // fake UI.
229   for (MediaStreamDevices::const_iterator it = devices_.begin();
230        it != devices_.end(); ++it) {
231     if (!accepted_audio &&
232         IsAudioInputMediaType(request.audio_type) &&
233         IsAudioInputMediaType(it->type) &&
234         (request.requested_audio_device_id.empty() ||
235          request.requested_audio_device_id == it->id)) {
236       devices_to_use.push_back(*it);
237       accepted_audio = true;
238     } else if (!accepted_video &&
239                IsVideoMediaType(request.video_type) &&
240                IsVideoMediaType(it->type) &&
241                (request.requested_video_device_id.empty() ||
242                 request.requested_video_device_id == it->id)) {
243       devices_to_use.push_back(*it);
244       accepted_video = true;
245     }
246   }
247 
248   // Fail the request if a device exist for the requested type.
249   if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) ||
250       (request.video_type != MEDIA_NO_SERVICE && !accepted_video)) {
251     devices_to_use.clear();
252   }
253 
254   BrowserThread::PostTask(
255       BrowserThread::IO, FROM_HERE,
256       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
257                  weak_factory_.GetWeakPtr(),
258                  devices_to_use,
259                  devices_to_use.empty() ?
260                      MEDIA_DEVICE_NO_HARDWARE :
261                      MEDIA_DEVICE_OK));
262 }
263 
OnStarted(const base::Closure & stop_callback,const WindowIdCallback & window_id_callback)264 void FakeMediaStreamUIProxy::OnStarted(
265     const base::Closure& stop_callback,
266     const WindowIdCallback& window_id_callback) {}
267 
268 }  // namespace content
269