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 "content/browser/renderer_host/render_view_host_delegate.h"
      8 #include "content/browser/renderer_host/render_view_host_impl.h"
      9 #include "content/public/browser/browser_thread.h"
     10 #include "media/video/capture/fake_video_capture_device.h"
     11 
     12 namespace content {
     13 
     14 class MediaStreamUIProxy::Core {
     15  public:
     16   explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
     17                 RenderViewHostDelegate* test_render_delegate);
     18   ~Core();
     19 
     20   void RequestAccess(const MediaStreamRequest& request);
     21   void OnStarted();
     22 
     23  private:
     24   void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
     25                                     scoped_ptr<MediaStreamUI> stream_ui);
     26   void ProcessStopRequestFromUI();
     27 
     28   base::WeakPtr<MediaStreamUIProxy> proxy_;
     29   scoped_ptr<MediaStreamUI> ui_;
     30 
     31   RenderViewHostDelegate* const test_render_delegate_;
     32 
     33   // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
     34   // cancel media requests.
     35   base::WeakPtrFactory<Core> weak_factory_;
     36 
     37   DISALLOW_COPY_AND_ASSIGN(Core);
     38 };
     39 
     40 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
     41                                RenderViewHostDelegate* test_render_delegate)
     42     : proxy_(proxy),
     43       test_render_delegate_(test_render_delegate),
     44       weak_factory_(this) {
     45 }
     46 
     47 MediaStreamUIProxy::Core::~Core() {
     48   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     49 }
     50 
     51 void MediaStreamUIProxy::Core::RequestAccess(
     52     const MediaStreamRequest& request) {
     53   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     54 
     55   RenderViewHostDelegate* render_delegate;
     56 
     57   if (test_render_delegate_) {
     58     render_delegate = test_render_delegate_;
     59   } else {
     60     RenderViewHostImpl* host = RenderViewHostImpl::FromID(
     61         request.render_process_id, request.render_view_id);
     62 
     63     // Tab may have gone away.
     64     if (!host || !host->GetDelegate()) {
     65       ProcessAccessRequestResponse(
     66           MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
     67       return;
     68     }
     69 
     70     render_delegate = host->GetDelegate();
     71   }
     72 
     73   render_delegate->RequestMediaAccessPermission(
     74       request, base::Bind(&Core::ProcessAccessRequestResponse,
     75                           weak_factory_.GetWeakPtr()));
     76 }
     77 
     78 void MediaStreamUIProxy::Core::OnStarted() {
     79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     80   if (ui_) {
     81     ui_->OnStarted(base::Bind(&Core::ProcessStopRequestFromUI,
     82                               base::Unretained(this)));
     83   }
     84 }
     85 
     86 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
     87     const MediaStreamDevices& devices,
     88     scoped_ptr<MediaStreamUI> stream_ui) {
     89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     90 
     91   ui_ = stream_ui.Pass();
     92   BrowserThread::PostTask(
     93       BrowserThread::IO, FROM_HERE,
     94       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
     95                  proxy_, devices));
     96 }
     97 
     98 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    100 
    101   BrowserThread::PostTask(
    102       BrowserThread::IO, FROM_HERE,
    103       base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
    104 }
    105 
    106 // static
    107 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
    108   return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
    109 }
    110 
    111 // static
    112 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
    113     RenderViewHostDelegate* render_delegate) {
    114   return scoped_ptr<MediaStreamUIProxy>(
    115       new MediaStreamUIProxy(render_delegate));
    116 }
    117 
    118 MediaStreamUIProxy::MediaStreamUIProxy(
    119     RenderViewHostDelegate* test_render_delegate)
    120     : weak_factory_(this) {
    121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    122   core_.reset(new Core(weak_factory_.GetWeakPtr(), test_render_delegate));
    123 }
    124 
    125 MediaStreamUIProxy::~MediaStreamUIProxy() {
    126   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    127   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release());
    128 }
    129 
    130 void MediaStreamUIProxy::RequestAccess(
    131     const MediaStreamRequest& request,
    132     const ResponseCallback& response_callback) {
    133   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    134 
    135   response_callback_ = response_callback;
    136   BrowserThread::PostTask(
    137       BrowserThread::UI, FROM_HERE,
    138       base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
    139 }
    140 
    141 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback) {
    142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    143 
    144   stop_callback_ = stop_callback;
    145   BrowserThread::PostTask(
    146       BrowserThread::UI, FROM_HERE,
    147       base::Bind(&Core::OnStarted, base::Unretained(core_.get())));
    148 }
    149 
    150 void MediaStreamUIProxy::ProcessAccessRequestResponse(
    151     const MediaStreamDevices& devices) {
    152   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    153   DCHECK(!response_callback_.is_null());
    154 
    155   ResponseCallback cb = response_callback_;
    156   response_callback_.Reset();
    157   cb.Run(devices);
    158 }
    159 
    160 void MediaStreamUIProxy::ProcessStopRequestFromUI() {
    161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    162   DCHECK(!stop_callback_.is_null());
    163 
    164   base::Closure cb = stop_callback_;
    165   stop_callback_.Reset();
    166   cb.Run();
    167 }
    168 
    169 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
    170   : MediaStreamUIProxy(NULL) {
    171 }
    172 
    173 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
    174 
    175 void FakeMediaStreamUIProxy::SetAvailableDevices(
    176     const MediaStreamDevices& devices) {
    177   devices_ = devices;
    178 }
    179 
    180 void FakeMediaStreamUIProxy::RequestAccess(
    181     const MediaStreamRequest& request,
    182     const ResponseCallback& response_callback) {
    183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    184 
    185   response_callback_ = response_callback;
    186 
    187   MediaStreamDevices devices_to_use;
    188   bool accepted_audio = false;
    189   bool accepted_video = false;
    190   // Use the first capture device of the same media type in the list for the
    191   // fake UI.
    192   for (MediaStreamDevices::const_iterator it = devices_.begin();
    193        it != devices_.end(); ++it) {
    194     if (!accepted_audio &&
    195         IsAudioMediaType(request.audio_type) &&
    196         IsAudioMediaType(it->type) &&
    197         (request.requested_audio_device_id.empty() ||
    198          request.requested_audio_device_id == it->id)) {
    199       devices_to_use.push_back(*it);
    200       accepted_audio = true;
    201     } else if (!accepted_video &&
    202                IsVideoMediaType(request.video_type) &&
    203                IsVideoMediaType(it->type) &&
    204                (request.requested_video_device_id.empty() ||
    205                 request.requested_video_device_id == it->id)) {
    206       devices_to_use.push_back(*it);
    207       accepted_video = true;
    208     }
    209   }
    210 
    211   BrowserThread::PostTask(
    212       BrowserThread::IO, FROM_HERE,
    213       base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse,
    214                  weak_factory_.GetWeakPtr(), devices_to_use));
    215 }
    216 
    217 void FakeMediaStreamUIProxy::OnStarted(const base::Closure& stop_callback) {
    218 }
    219 
    220 }  // namespace content
    221