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