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/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 
     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 
     50 MediaStreamUIProxy::Core::~Core() {
     51   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     52 }
     53 
     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 
     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 
     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 
    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
    113 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
    114   return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
    115 }
    116 
    117 // static
    118 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
    119     RenderViewHostDelegate* render_delegate) {
    120   return scoped_ptr<MediaStreamUIProxy>(
    121       new MediaStreamUIProxy(render_delegate));
    122 }
    123 
    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 
    131 MediaStreamUIProxy::~MediaStreamUIProxy() {
    132   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    133   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release());
    134 }
    135 
    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 
    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 
    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 
    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 
    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 
    193 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
    194   : MediaStreamUIProxy(NULL) {
    195 }
    196 
    197 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
    198 
    199 void FakeMediaStreamUIProxy::SetAvailableDevices(
    200     const MediaStreamDevices& devices) {
    201   devices_ = devices;
    202 }
    203 
    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 
    264 void FakeMediaStreamUIProxy::OnStarted(
    265     const base::Closure& stop_callback,
    266     const WindowIdCallback& window_id_callback) {}
    267 
    268 }  // namespace content
    269