Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/media/media_stream_ui_controller.h" | 5 #include "content/browser/renderer_host/media/media_stream_ui_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 13 #include "content/browser/renderer_host/media/media_stream_settings_requester.h" | 13 #include "content/browser/renderer_host/media/media_stream_settings_requester.h" |
| 14 #include "content/browser/renderer_host/render_view_host_delegate.h" | 14 #include "content/browser/renderer_host/render_view_host_delegate.h" |
| 15 #include "content/browser/renderer_host/render_view_host_impl.h" | 15 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 16 #include "content/common/media/media_stream_options.h" | 16 #include "content/common/media/media_stream_options.h" |
| 17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
| 18 #include "content/public/browser/content_browser_client.h" | 18 #include "content/public/browser/content_browser_client.h" |
| 19 #include "content/public/browser/media_observer.h" | 19 #include "content/public/browser/media_observer.h" |
| 20 #include "content/public/common/media_stream_request.h" | 20 #include "content/public/common/media_stream_request.h" |
| 21 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
| 22 | 22 |
| 23 using content::BrowserThread; | 23 namespace content { |
| 24 using content::MediaStreamDevice; | |
| 25 using content::MediaStreamRequest; | |
| 26 | |
| 27 namespace { | 24 namespace { |
| 28 | 25 |
| 29 // Helper class to handle the callbacks to a MediaStreamUIController instance. | 26 // Helper class to handle the callbacks to a MediaStreamUIController instance. |
| 30 // This class will make sure that the call to PostResponse is executed on the IO | 27 // This class will make sure that the call to PostResponse is executed on the IO |
| 31 // thread (and that the instance of MediaStreamUIController still exists). | 28 // thread (and that the instance of MediaStreamUIController still exists). |
| 32 // This allows us to pass a simple base::Callback object to any class that needs | 29 // This allows us to pass a simple base::Callback object to any class that needs |
| 33 // to post a response to the MediaStreamUIController object. This logic cannot | 30 // to post a response to the MediaStreamUIController object. This logic cannot |
| 34 // be implemented inside MediaStreamUIController::PostResponse since that | 31 // be implemented inside MediaStreamUIController::PostResponse since that |
| 35 // would imply that the WeakPtr<MediaStreamUIController> pointer has been | 32 // would imply that the WeakPtr<MediaStreamUIController> pointer has been |
| 36 // dereferenced already (which would cause an error in the ThreadChecker before | 33 // dereferenced already (which would cause an error in the ThreadChecker before |
| 37 // we even get there). | 34 // we even get there). |
| 38 class ResponseCallbackHelper | 35 class ResponseCallbackHelper |
| 39 : public base::RefCountedThreadSafe<ResponseCallbackHelper> { | 36 : public base::RefCountedThreadSafe<ResponseCallbackHelper> { |
| 40 public: | 37 public: |
| 41 explicit ResponseCallbackHelper( | 38 explicit ResponseCallbackHelper( |
| 42 base::WeakPtr<content::MediaStreamUIController> controller) | 39 base::WeakPtr<MediaStreamUIController> controller) |
| 43 : controller_(controller) { | 40 : controller_(controller) { |
| 44 } | 41 } |
| 45 | 42 |
| 46 void PostResponse(const std::string& label, | 43 void PostResponse(const std::string& label, |
| 47 const content::MediaStreamDevices& devices) { | 44 const MediaStreamDevices& devices) { |
| 48 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 45 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 49 BrowserThread::PostTask( | 46 BrowserThread::PostTask( |
| 50 BrowserThread::IO, FROM_HERE, | 47 BrowserThread::IO, FROM_HERE, |
| 51 base::Bind(&content::MediaStreamUIController::PostResponse, | 48 base::Bind(&MediaStreamUIController::PostResponse, |
| 52 controller_, label, devices)); | 49 controller_, label, devices)); |
| 53 return; | 50 return; |
| 54 } else if (controller_) { | 51 } else if (controller_) { |
| 55 controller_->PostResponse(label, devices); | 52 controller_->PostResponse(label, devices); |
| 56 } | 53 } |
| 57 } | 54 } |
| 58 | 55 |
| 59 private: | 56 private: |
| 60 friend class base::RefCountedThreadSafe<ResponseCallbackHelper>; | 57 friend class base::RefCountedThreadSafe<ResponseCallbackHelper>; |
| 61 ~ResponseCallbackHelper() {} | 58 ~ResponseCallbackHelper() {} |
| 62 | 59 |
| 63 base::WeakPtr<content::MediaStreamUIController> controller_; | 60 base::WeakPtr<MediaStreamUIController> controller_; |
| 64 | 61 |
| 65 DISALLOW_COPY_AND_ASSIGN(ResponseCallbackHelper); | 62 DISALLOW_COPY_AND_ASSIGN(ResponseCallbackHelper); |
| 66 }; | 63 }; |
| 67 | 64 |
| 68 } // namespace | 65 } // namespace |
| 69 | 66 |
| 70 namespace content { | |
| 71 | |
| 72 // UI request contains all data needed to keep track of requests between the | 67 // UI request contains all data needed to keep track of requests between the |
| 73 // different calls. | 68 // different calls. |
| 74 class MediaStreamRequestForUI : public content::MediaStreamRequest { | 69 class MediaStreamRequestForUI : public MediaStreamRequest { |
| 75 public: | 70 public: |
| 76 MediaStreamRequestForUI( | 71 MediaStreamRequestForUI( |
| 77 int render_pid, | 72 int render_pid, |
|
tfarina
2012/10/29 17:41:34
nit: it does fits into the previous line now.
jam
2012/10/29 18:14:45
i'm not sure what you mean? the 4 won't fit in the
tfarina
2012/10/29 18:19:33
I mean this:
MediaStreamRequestForUI(int render_p
jam
2012/10/29 18:25:03
Done.
| |
| 78 int render_vid, | 73 int render_vid, |
| 79 const GURL& origin, | 74 const GURL& origin, |
| 80 const media_stream::StreamOptions& options) | 75 const StreamOptions& options) |
| 81 : MediaStreamRequest(render_pid, render_vid, origin), | 76 : MediaStreamRequest(render_pid, render_vid, origin), |
| 82 wait_for_audio(IsAudioMediaType(options.audio_type)), | 77 wait_for_audio(IsAudioMediaType(options.audio_type)), |
| 83 wait_for_video(IsVideoMediaType(options.video_type)), | 78 wait_for_video(IsVideoMediaType(options.video_type)), |
| 84 posted_task(false) { | 79 posted_task(false) { |
| 85 DCHECK(wait_for_audio || wait_for_video); | 80 DCHECK(wait_for_audio || wait_for_video); |
| 86 } | 81 } |
| 87 | 82 |
| 88 ~MediaStreamRequestForUI() {} | 83 ~MediaStreamRequestForUI() {} |
| 89 | 84 |
| 90 bool IsRequestReadyForView() const { | 85 bool IsRequestReadyForView() const { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 106 }; | 101 }; |
| 107 | 102 |
| 108 namespace { | 103 namespace { |
| 109 | 104 |
| 110 // Sends the request to the appropriate WebContents. | 105 // Sends the request to the appropriate WebContents. |
| 111 void ProceedMediaAccessPermission(const MediaStreamRequestForUI& request, | 106 void ProceedMediaAccessPermission(const MediaStreamRequestForUI& request, |
| 112 const MediaResponseCallback& callback) { | 107 const MediaResponseCallback& callback) { |
| 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 114 | 109 |
| 115 // Send the permission request to the web contents. | 110 // Send the permission request to the web contents. |
| 116 content::RenderViewHostImpl* host = | 111 RenderViewHostImpl* host = RenderViewHostImpl::FromID( |
| 117 content::RenderViewHostImpl::FromID(request.render_process_id, | 112 request.render_process_id, request.render_view_id); |
| 118 request.render_view_id); | |
| 119 | 113 |
| 120 // Tab may have gone away. | 114 // Tab may have gone away. |
| 121 if (!host || !host->GetDelegate()) { | 115 if (!host || !host->GetDelegate()) { |
| 122 callback.Run(content::MediaStreamDevices()); | 116 callback.Run(MediaStreamDevices()); |
| 123 return; | 117 return; |
| 124 } | 118 } |
| 125 | 119 |
| 126 host->GetDelegate()->RequestMediaAccessPermission(&request, callback); | 120 host->GetDelegate()->RequestMediaAccessPermission(&request, callback); |
| 127 } | 121 } |
| 128 | 122 |
| 129 } // namespace | 123 } // namespace |
| 130 | 124 |
| 131 MediaStreamUIController::MediaStreamUIController( | 125 MediaStreamUIController::MediaStreamUIController( |
| 132 media_stream::SettingsRequester* requester) | 126 SettingsRequester* requester) |
|
tfarina
2012/10/29 17:41:34
fits above.
jam
2012/10/29 18:14:45
Done.
| |
| 133 : requester_(requester), | 127 : requester_(requester), |
| 134 use_fake_ui_(false), | 128 use_fake_ui_(false), |
| 135 weak_ptr_factory_(this) { | 129 weak_ptr_factory_(this) { |
| 136 DCHECK(requester_); | 130 DCHECK(requester_); |
| 137 } | 131 } |
| 138 | 132 |
| 139 MediaStreamUIController::~MediaStreamUIController() { | 133 MediaStreamUIController::~MediaStreamUIController() { |
| 140 DCHECK(requests_.empty()); | 134 DCHECK(requests_.empty()); |
| 141 } | 135 } |
| 142 | 136 |
| 143 void MediaStreamUIController::MakeUIRequest( | 137 void MediaStreamUIController::MakeUIRequest( |
| 144 const std::string& label, int render_process_id, int render_view_id, | 138 const std::string& label, int render_process_id, int render_view_id, |
| 145 const media_stream::StreamOptions& request_options, | 139 const StreamOptions& request_options, |
| 146 const GURL& security_origin) { | 140 const GURL& security_origin) { |
| 147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 148 | 142 |
| 149 // Create a new request. | 143 // Create a new request. |
| 150 if (!requests_.insert( | 144 if (!requests_.insert( |
| 151 std::make_pair(label, new MediaStreamRequestForUI( | 145 std::make_pair(label, new MediaStreamRequestForUI( |
| 152 render_process_id, render_view_id, security_origin, | 146 render_process_id, render_view_id, security_origin, |
| 153 request_options))).second) { | 147 request_options))).second) { |
| 154 NOTREACHED(); | 148 NOTREACHED(); |
| 155 } | 149 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 176 | 170 |
| 177 // Process the next pending request to replace the old infobar on the same | 171 // Process the next pending request to replace the old infobar on the same |
| 178 // page. | 172 // page. |
| 179 ProcessNextRequestForView(render_process_id, render_view_id); | 173 ProcessNextRequestForView(render_process_id, render_view_id); |
| 180 } | 174 } |
| 181 } | 175 } |
| 182 | 176 |
| 183 void MediaStreamUIController::AddAvailableDevicesToRequest( | 177 void MediaStreamUIController::AddAvailableDevicesToRequest( |
| 184 const std::string& label, | 178 const std::string& label, |
| 185 MediaStreamDeviceType stream_type, | 179 MediaStreamDeviceType stream_type, |
| 186 const media_stream::StreamDeviceInfoArray& devices) { | 180 const StreamDeviceInfoArray& devices) { |
| 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 188 | 182 |
| 189 UIRequests::const_iterator request_iter = requests_.find(label); | 183 UIRequests::const_iterator request_iter = requests_.find(label); |
| 190 if (request_iter == requests_.end()) { | 184 if (request_iter == requests_.end()) { |
| 191 NOTREACHED(); | 185 NOTREACHED(); |
| 192 return; | 186 return; |
| 193 } | 187 } |
| 194 | 188 |
| 195 // Add the available devices to the request. | 189 // Add the available devices to the request. |
| 196 MediaStreamRequestForUI* request = request_iter->second; | 190 MediaStreamRequestForUI* request = request_iter->second; |
| 197 | 191 |
| 198 // Create the simplified list of devices. | 192 // Create the simplified list of devices. |
| 199 content::MediaStreamDevices& requested_devices = | 193 MediaStreamDevices& requested_devices = request->devices[stream_type]; |
| 200 request->devices[stream_type]; | |
| 201 DCHECK(requested_devices.empty()); | 194 DCHECK(requested_devices.empty()); |
| 202 for (media_stream::StreamDeviceInfoArray::const_iterator it = devices.begin(); | 195 for (StreamDeviceInfoArray::const_iterator it = devices.begin(); |
| 203 it != devices.end(); | 196 it != devices.end(); |
| 204 ++it) { | 197 ++it) { |
| 205 requested_devices.push_back(MediaStreamDevice(stream_type, | 198 requested_devices.push_back(MediaStreamDevice(stream_type, |
| 206 it->device_id, | 199 it->device_id, |
| 207 it->name)); | 200 it->name)); |
| 208 } | 201 } |
| 209 | 202 |
| 210 if (IsAudioMediaType(stream_type)) { | 203 if (IsAudioMediaType(stream_type)) { |
| 211 DCHECK(request->wait_for_audio); | 204 DCHECK(request->wait_for_audio); |
| 212 request->wait_for_audio = false; | 205 request->wait_for_audio = false; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 227 // request to the view if the UI is handling any other request. | 220 // request to the view if the UI is handling any other request. |
| 228 if (IsUIBusy(request->render_process_id, request->render_view_id)) | 221 if (IsUIBusy(request->render_process_id, request->render_view_id)) |
| 229 return; | 222 return; |
| 230 | 223 |
| 231 PostRequestToUI(label); | 224 PostRequestToUI(label); |
| 232 } | 225 } |
| 233 } | 226 } |
| 234 | 227 |
| 235 void MediaStreamUIController::PostResponse( | 228 void MediaStreamUIController::PostResponse( |
| 236 const std::string& label, | 229 const std::string& label, |
| 237 const content::MediaStreamDevices& devices) { | 230 const MediaStreamDevices& devices) { |
| 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 239 UIRequests::iterator request_iter = requests_.find(label); | 232 UIRequests::iterator request_iter = requests_.find(label); |
| 240 // Return if the request has been removed. | 233 // Return if the request has been removed. |
| 241 if (request_iter == requests_.end()) | 234 if (request_iter == requests_.end()) |
| 242 return; | 235 return; |
| 243 | 236 |
| 244 DCHECK(requester_); | 237 DCHECK(requester_); |
| 245 scoped_ptr<MediaStreamRequestForUI> request(request_iter->second); | 238 scoped_ptr<MediaStreamRequestForUI> request(request_iter->second); |
| 246 requests_.erase(request_iter); | 239 requests_.erase(request_iter); |
| 247 | 240 |
| 248 // Look for queued requests for the same view. If there is a pending request, | 241 // Look for queued requests for the same view. If there is a pending request, |
| 249 // post it for user approval. | 242 // post it for user approval. |
| 250 ProcessNextRequestForView(request->render_process_id, | 243 ProcessNextRequestForView(request->render_process_id, |
| 251 request->render_view_id); | 244 request->render_view_id); |
| 252 | 245 |
| 253 if (devices.size() > 0) { | 246 if (devices.size() > 0) { |
| 254 // Build a list of "full" device objects for the accepted devices. | 247 // Build a list of "full" device objects for the accepted devices. |
| 255 media_stream::StreamDeviceInfoArray device_list; | 248 StreamDeviceInfoArray device_list; |
| 256 // TODO(xians): figure out if it is all right to hard code in_use to false, | 249 // TODO(xians): figure out if it is all right to hard code in_use to false, |
| 257 // though DevicesAccepted seems to do so. | 250 // though DevicesAccepted seems to do so. |
| 258 for (MediaStreamDevices::const_iterator dev = devices.begin(); | 251 for (MediaStreamDevices::const_iterator dev = devices.begin(); |
| 259 dev != devices.end(); ++dev) { | 252 dev != devices.end(); ++dev) { |
| 260 device_list.push_back(media_stream::StreamDeviceInfo( | 253 device_list.push_back(StreamDeviceInfo( |
| 261 dev->type, dev->name, dev->device_id, false)); | 254 dev->type, dev->name, dev->device_id, false)); |
| 262 } | 255 } |
| 263 | 256 |
| 264 requester_->DevicesAccepted(label, device_list); | 257 requester_->DevicesAccepted(label, device_list); |
| 265 } else { | 258 } else { |
| 266 requester_->SettingsError(label); | 259 requester_->SettingsError(label); |
| 267 } | 260 } |
| 268 } | 261 } |
| 269 | 262 |
| 270 void MediaStreamUIController::NotifyUIIndicatorDevicesOpened( | 263 void MediaStreamUIController::NotifyUIIndicatorDevicesOpened( |
| 271 int render_process_id, | 264 int render_process_id, |
| 272 int render_view_id, | 265 int render_view_id, |
| 273 const content::MediaStreamDevices& devices) { | 266 const MediaStreamDevices& devices) { |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 275 DCHECK(!devices.empty()); | 268 DCHECK(!devices.empty()); |
| 276 content::MediaObserver* media_observer = | 269 MediaObserver* media_observer = |
| 277 content::GetContentClient()->browser()->GetMediaObserver(); | 270 GetContentClient()->browser()->GetMediaObserver(); |
| 278 if (media_observer == NULL) | 271 if (media_observer == NULL) |
| 279 return; | 272 return; |
| 280 | 273 |
| 281 media_observer->OnCaptureDevicesOpened(render_process_id, | 274 media_observer->OnCaptureDevicesOpened(render_process_id, |
| 282 render_view_id, | 275 render_view_id, |
| 283 devices); | 276 devices); |
| 284 } | 277 } |
| 285 | 278 |
| 286 void MediaStreamUIController::NotifyUIIndicatorDevicesClosed( | 279 void MediaStreamUIController::NotifyUIIndicatorDevicesClosed( |
| 287 int render_process_id, | 280 int render_process_id, |
| 288 int render_view_id, | 281 int render_view_id, |
| 289 const content::MediaStreamDevices& devices) { | 282 const MediaStreamDevices& devices) { |
| 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 291 DCHECK(!devices.empty()); | 284 DCHECK(!devices.empty()); |
| 292 content::MediaObserver* media_observer = | 285 MediaObserver* media_observer = |
| 293 content::GetContentClient()->browser()->GetMediaObserver(); | 286 GetContentClient()->browser()->GetMediaObserver(); |
| 294 if (media_observer == NULL) | 287 if (media_observer == NULL) |
| 295 return; | 288 return; |
| 296 | 289 |
| 297 media_observer->OnCaptureDevicesClosed(render_process_id, | 290 media_observer->OnCaptureDevicesClosed(render_process_id, |
| 298 render_view_id, | 291 render_view_id, |
| 299 devices); | 292 devices); |
| 300 } | 293 } |
| 301 | 294 |
| 302 void MediaStreamUIController::UseFakeUI() { | 295 void MediaStreamUIController::UseFakeUI() { |
| 303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 NOTREACHED(); | 341 NOTREACHED(); |
| 349 return; | 342 return; |
| 350 } | 343 } |
| 351 MediaStreamRequestForUI* request = request_iter->second; | 344 MediaStreamRequestForUI* request = request_iter->second; |
| 352 DCHECK(request != NULL); | 345 DCHECK(request != NULL); |
| 353 | 346 |
| 354 request->posted_task = true; | 347 request->posted_task = true; |
| 355 | 348 |
| 356 scoped_refptr<ResponseCallbackHelper> helper = | 349 scoped_refptr<ResponseCallbackHelper> helper = |
| 357 new ResponseCallbackHelper(weak_ptr_factory_.GetWeakPtr()); | 350 new ResponseCallbackHelper(weak_ptr_factory_.GetWeakPtr()); |
| 358 content::MediaResponseCallback callback = | 351 MediaResponseCallback callback = |
| 359 base::Bind(&ResponseCallbackHelper::PostResponse, | 352 base::Bind(&ResponseCallbackHelper::PostResponse, |
| 360 helper.get(), label); | 353 helper.get(), label); |
| 361 | 354 |
| 362 BrowserThread::PostTask( | 355 BrowserThread::PostTask( |
| 363 BrowserThread::UI, FROM_HERE, | 356 BrowserThread::UI, FROM_HERE, |
| 364 base::Bind(&ProceedMediaAccessPermission, *request, callback)); | 357 base::Bind(&ProceedMediaAccessPermission, *request, callback)); |
| 365 } | 358 } |
| 366 | 359 |
| 367 void MediaStreamUIController::PostRequestToFakeUI(const std::string& label) { | 360 void MediaStreamUIController::PostRequestToFakeUI(const std::string& label) { |
| 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 379 devices_to_use.push_back(it->second.front()); | 372 devices_to_use.push_back(it->second.front()); |
| 380 } | 373 } |
| 381 } | 374 } |
| 382 | 375 |
| 383 BrowserThread::PostTask( | 376 BrowserThread::PostTask( |
| 384 BrowserThread::IO, FROM_HERE, | 377 BrowserThread::IO, FROM_HERE, |
| 385 base::Bind(&MediaStreamUIController::PostResponse, | 378 base::Bind(&MediaStreamUIController::PostResponse, |
| 386 weak_ptr_factory_.GetWeakPtr(), label, devices_to_use)); | 379 weak_ptr_factory_.GetWeakPtr(), label, devices_to_use)); |
| 387 } | 380 } |
| 388 | 381 |
| 389 } // namespace media_stream | 382 } // namespace content |
| OLD | NEW |