Index: content/browser/renderer_host/media/media_stream_manager.cc |
=================================================================== |
--- content/browser/renderer_host/media/media_stream_manager.cc (revision 148913) |
+++ content/browser/renderer_host/media/media_stream_manager.cc (working copy) |
@@ -11,6 +11,8 @@ |
#include "base/logging.h" |
#include "base/rand_util.h" |
#include "base/win/scoped_com_initializer.h" |
+#include "content/browser/browser_main_loop.h" |
+#include "content/browser/devices_monitor/devices_monitor.h" |
#include "content/browser/renderer_host/media/audio_input_device_manager.h" |
#include "content/browser/renderer_host/media/media_stream_device_settings.h" |
#include "content/browser/renderer_host/media/media_stream_requester.h" |
@@ -131,6 +133,10 @@ |
StreamDeviceInfoArray video_devices; |
}; |
+MediaStreamManager::EnumerationCache::EnumerationCache() |
+ : valid(false) { |
+} |
+ |
MediaStreamManager::MediaStreamManager( |
AudioInputDeviceManager* audio_input_device_manager, |
VideoCaptureManager* video_capture_manager) |
@@ -138,6 +144,7 @@ |
device_settings_(new MediaStreamDeviceSettings(this))), |
audio_input_device_manager_(audio_input_device_manager), |
video_capture_manager_(video_capture_manager), |
+ monitoring_started_(false), |
enumeration_in_progress_(content::NUM_MEDIA_STREAM_DEVICE_TYPES, false), |
tommi (sloooow) - chröme
2012/07/30 12:10:21
This array seems to be used in conjunction with th
wjia(left Chromium)
2012/08/01 01:28:59
This |enumeration_in_progress_| also include other
|
io_loop_(NULL) { |
} |
@@ -176,6 +183,17 @@ |
render_view_id, |
security_origin); |
StartEnumeration(&new_request, label); |
+ |
+ // Get user confirmation to use capture devices. |
+ // Need to make an asynchronous call to make sure the |requester| gets the |
+ // |label| before it would receive any event. |
+ BrowserThread::PostTask(BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&MediaStreamDeviceSettings::RequestCaptureDeviceUsage, |
+ base::Unretained(device_settings_.get()), |
+ *label, render_process_id, |
+ render_view_id, options, |
+ security_origin)); |
} |
void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) { |
@@ -246,6 +264,10 @@ |
// Find the request and close all open devices for the request. |
DeviceRequests::iterator it = requests_.find(label); |
if (it != requests_.end()) { |
+ if (it->second.type == DeviceRequest::kEnumerateDevices) { |
tommi (sloooow) - chröme
2012/07/30 12:10:21
kEnumerateDevices -> ENUMERATE_DEVICES
wjia(left Chromium)
2012/08/01 01:28:59
Done.
|
+ StopEnumerateDevices(label); |
+ return; |
+ } |
for (StreamDeviceInfoArray::iterator audio_it = |
it->second.audio_devices.begin(); |
audio_it != it->second.audio_devices.end(); ++audio_it) { |
@@ -260,7 +282,6 @@ |
NotifyObserverDevicesClosed(&(it->second)); |
} |
requests_.erase(it); |
- return; |
} |
} |
@@ -272,13 +293,19 @@ |
const GURL& security_origin, |
std::string* label) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ DCHECK(type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE || |
+ type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE); |
// Create a new request. |
StreamOptions options; |
- if (type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) |
+ EnumerationCache* cache = NULL; |
+ if (type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
options.audio = true; |
- else |
+ cache = &audio_enumeration_cache_; |
+ } else { |
options.video = true; |
+ cache = &video_enumeration_cache_; |
+ } |
DeviceRequest new_request(requester, options, |
render_process_id, |
@@ -286,9 +313,35 @@ |
security_origin); |
new_request.type = DeviceRequest::kEnumerateDevices; |
- StartEnumeration(&new_request, label); |
+ if (cache->valid) { |
+ // Cached device list of this type exists. Just send it out. |
+ new_request.state[type] = DeviceRequest::kRequested; |
tommi (sloooow) - chröme
2012/07/30 12:10:21
kRequested -> REQUESTED
wjia(left Chromium)
2012/08/01 01:28:59
Done.
|
+ AddRequest(&new_request, label); |
+ // Need to post a task since the requester won't have label till |
+ // this function returns. |
+ BrowserThread::PostTask(BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&MediaStreamManager::SendCachedDeviceList, |
+ base::Unretained(this), cache, *label)); |
+ } else { |
+ StartEnumeration(&new_request, label); |
+ StartMonitoring(); |
+ } |
} |
+void MediaStreamManager::StopEnumerateDevices(const std::string& label) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ DeviceRequests::iterator it = requests_.find(label); |
+ if (it != requests_.end()) { |
+ DCHECK_EQ(it->second.type, DeviceRequest::kEnumerateDevices); |
+ requests_.erase(it); |
+ if (!HasEnumerationRequest()) { |
+ StopMonitoring(); |
+ } |
+ } |
+} |
+ |
void MediaStreamManager::OpenDevice( |
MediaStreamRequester* requester, |
int render_process_id, |
@@ -316,6 +369,42 @@ |
StartEnumeration(&new_request, label); |
} |
+void MediaStreamManager::SendCachedDeviceList( |
+ EnumerationCache* cache, |
+ const std::string& label) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ if (cache->valid && requests_.find(label) != requests_.end()) { |
+ requests_[label].requester->DevicesEnumerated(label, cache->devices); |
tommi (sloooow) - chröme
2012/07/30 12:10:21
nit: you've already looked up the label so you cou
wjia(left Chromium)
2012/08/01 01:28:59
Done.
|
+ } |
+} |
+ |
+void MediaStreamManager::StartMonitoring() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ if (!monitoring_started_) { |
+ monitoring_started_ = true; |
+ content::BrowserMainLoop::GetDevicesMonitor()->Start(this); |
+ base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
tommi (sloooow) - chröme
2012/07/30 12:10:21
What do you think about this:
* Remove:
- Start
wjia(left Chromium)
2012/08/01 01:28:59
The start/stop of DeviceMonitor has been removed b
tommi (sloooow) - chröme
2012/08/01 10:21:37
Great. Thanks.
|
+ } |
+} |
+ |
+void MediaStreamManager::StopMonitoring() { |
+ DCHECK_EQ(MessageLoop::current(), io_loop_); |
+ if (monitoring_started_ && !HasEnumerationRequest()) { |
+ content::BrowserMainLoop::GetDevicesMonitor()->Stop(this); |
+ base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
+ monitoring_started_ = false; |
+ ClearEnumerationCache(&audio_enumeration_cache_); |
+ ClearEnumerationCache(&video_enumeration_cache_); |
+ } |
+} |
+ |
+void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { |
tommi (sloooow) - chröme
2012/07/30 12:10:21
could an empty cache mean valid == false?
if so, w
wjia(left Chromium)
2012/08/01 01:28:59
Unfortunately, empty cache doesn't mean valid or i
tommi (sloooow) - chröme
2012/08/01 10:21:37
sgtm.
|
+ DCHECK_EQ(MessageLoop::current(), io_loop_); |
+ if (cache->valid) { |
tommi (sloooow) - chröme
2012/07/30 12:10:21
no need to check it first. just set valid to fals
wjia(left Chromium)
2012/08/01 01:28:59
Done.
|
+ cache->valid = false; |
+ } |
+} |
+ |
void MediaStreamManager::StartEnumeration( |
DeviceRequest* new_request, |
std::string* label) { |
@@ -338,6 +427,14 @@ |
} |
} |
+ AddRequest(new_request, label); |
+} |
+ |
+void MediaStreamManager::AddRequest( |
+ DeviceRequest* new_request, |
+ std::string* label) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
// Create a label for this request and verify it is unique. |
std::string request_label; |
do { |
@@ -346,19 +443,6 @@ |
requests_.insert(std::make_pair(request_label, *new_request)); |
- // Get user confirmation to use capture devices. |
- // Need to make an asynchronous call to make sure the |requester| gets the |
- // |label| before it would receive any event. |
- if (new_request->type == DeviceRequest::kGenerateStream) { |
- BrowserThread::PostTask(BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&MediaStreamDeviceSettings::RequestCaptureDeviceUsage, |
- base::Unretained(device_settings_.get()), |
- request_label, new_request->render_process_id, |
- new_request->render_view_id, new_request->options, |
- new_request->security_origin)); |
- } |
- |
(*label) = request_label; |
} |
@@ -455,6 +539,19 @@ |
MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ // Only cache device list when there is EnumerateDevices request, since |
+ // other requests don't turn on device monitoring. |
+ bool need_update_clients = false; |
+ EnumerationCache* cache = |
+ (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE ? |
+ &audio_enumeration_cache_ : &video_enumeration_cache_); |
+ if (HasEnumerationRequest(stream_type)) { |
+ if (!cache->valid || cache->devices != devices) { |
tommi (sloooow) - chröme
2012/07/30 12:10:21
I think this is a case for not needing the |valid|
wjia(left Chromium)
2012/08/01 01:28:59
Without |valid| flag, we have to keep cache always
tommi (sloooow) - chröme
2012/08/01 10:21:37
sgtm
|
+ cache->devices = devices; |
+ need_update_clients = true; |
+ } |
+ } |
+ |
// Publish the result for all requests waiting for device list(s). |
// Find the requests waiting for this device list, store their labels and |
// release the iterator before calling device settings. We might get a call |
@@ -464,7 +561,8 @@ |
++it) { |
if (it->second.state[stream_type] == DeviceRequest::kRequested && |
Requested(it->second.options, stream_type)) { |
- it->second.state[stream_type] = DeviceRequest::kPendingApproval; |
+ if (it->second.type != DeviceRequest::kEnumerateDevices) |
+ it->second.state[stream_type] = DeviceRequest::kPendingApproval; |
label_list.push_back(it->first); |
} |
} |
@@ -473,8 +571,8 @@ |
DeviceRequest& request = requests_[*it]; |
switch (request.type) { |
case DeviceRequest::kEnumerateDevices: |
- request.requester->DevicesEnumerated(*it, devices); |
- requests_.erase(*it); |
+ if (need_update_clients) |
+ request.requester->DevicesEnumerated(*it, devices); |
break; |
case DeviceRequest::kOpenDevice: |
for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); |
@@ -628,7 +726,10 @@ |
void MediaStreamManager::WillDestroyCurrentMessageLoop() { |
DCHECK_EQ(MessageLoop::current(), io_loop_); |
+ DCHECK(requests_.empty()); |
if (device_thread_.get()) { |
+ StopMonitoring(); |
+ |
video_capture_manager_->Unregister(); |
audio_input_device_manager_->Unregister(); |
device_thread_.reset(); |
@@ -721,4 +822,55 @@ |
return NULL; |
} |
+void MediaStreamManager::OnDevicesChanged( |
+ base::SystemMonitor::DeviceType device_type) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ MediaStreamType stream_type; |
+ EnumerationCache* cache; |
+ if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) { |
+ stream_type = content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE; |
+ cache = &audio_enumeration_cache_; |
+ } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) { |
+ stream_type = content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE; |
+ cache = &video_enumeration_cache_; |
+ } else { |
+ return; // Uninterested device change. |
tommi (sloooow) - chröme
2012/07/30 12:10:21
s/Uninterested/Uninteresting.
wjia(left Chromium)
2012/08/01 01:28:59
Done.
|
+ } |
+ |
+ if (!HasEnumerationRequest(stream_type)) { |
+ // There is no request for that type, No need to enumerate devices. |
+ // Therefore, invalidate the cache of that type. |
+ ClearEnumerationCache(cache); |
+ } else if (!enumeration_in_progress_[stream_type]) { |
+ enumeration_in_progress_[stream_type] = true; |
+ GetDeviceManager(stream_type)->EnumerateDevices(); |
+ } |
+} |
+ |
+bool MediaStreamManager::HasEnumerationRequest() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ for (DeviceRequests::iterator it = requests_.begin(); |
+ it != requests_.end(); ++it) { |
+ DeviceRequest& request = it->second; |
+ if (request.type == DeviceRequest::kEnumerateDevices) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool MediaStreamManager::HasEnumerationRequest( |
+ MediaStreamType stream_type) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ for (DeviceRequests::iterator it = requests_.begin(); |
+ it != requests_.end(); ++it) { |
+ DeviceRequest& request = it->second; |
+ if (request.type == DeviceRequest::kEnumerateDevices && |
+ Requested(request.options, stream_type)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
} // namespace media_stream |