Home | History | Annotate | Download | only in media
      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
    356