Chromium Code Reviews| Index: content/browser/renderer_host/media/media_stream_manager.cc |
| diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc |
| index 8194fde724332595de1996e35f27e6c6f4aa7e41..26bb149cdda5d2fb58c575552a76a1415643008a 100644 |
| --- a/content/browser/renderer_host/media/media_stream_manager.cc |
| +++ b/content/browser/renderer_host/media/media_stream_manager.cc |
| @@ -11,6 +11,7 @@ |
| #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/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" |
| @@ -47,10 +48,8 @@ static std::string RandomLabel() { |
| // Helper to verify if a media stream type is part of options or not. |
| static bool Requested(const StreamOptions& options, |
| MediaStreamType stream_type) { |
| - return (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE && |
| - options.video) || |
| - (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE && |
| - options.audio); |
| + return (options.audio_type == stream_type || |
| + options.video_type == stream_type); |
| } |
| DeviceThread::DeviceThread(const char* name) |
| @@ -90,12 +89,10 @@ struct MediaStreamManager::DeviceRequest { |
| DeviceRequest() |
| : requester(NULL), |
| - state(content::NUM_MEDIA_STREAM_DEVICE_TYPES, STATE_NOT_REQUESTED), |
| + state(content::NUM_MEDIA_TYPES, STATE_NOT_REQUESTED), |
| type(GENERATE_STREAM), |
| render_process_id(-1), |
| render_view_id(-1) { |
| - options.audio = false; |
| - options.video = false; |
| } |
| DeviceRequest(MediaStreamRequester* requester, |
| @@ -105,7 +102,7 @@ struct MediaStreamManager::DeviceRequest { |
| const GURL& request_security_origin) |
| : requester(requester), |
| options(request_options), |
| - state(content::NUM_MEDIA_STREAM_DEVICE_TYPES, STATE_NOT_REQUESTED), |
| + state(content::NUM_MEDIA_TYPES, STATE_NOT_REQUESTED), |
| type(GENERATE_STREAM), |
| render_process_id(render_process_id), |
| render_view_id(render_view_id), |
| @@ -122,9 +119,7 @@ struct MediaStreamManager::DeviceRequest { |
| int render_process_id; |
| int render_view_id; |
| GURL security_origin; |
| - std::string requested_device_id; |
| - StreamDeviceInfoArray audio_devices; |
| - StreamDeviceInfoArray video_devices; |
| + StreamDeviceInfoArray devices; |
| }; |
| MediaStreamManager::EnumerationCache::EnumerationCache() |
| @@ -134,13 +129,10 @@ MediaStreamManager::EnumerationCache::EnumerationCache() |
| MediaStreamManager::EnumerationCache::~EnumerationCache() { |
| } |
| -MediaStreamManager::MediaStreamManager( |
| - AudioInputDeviceManager* audio_input_device_manager, |
| - VideoCaptureManager* video_capture_manager) |
| +MediaStreamManager::MediaStreamManager() |
| : ALLOW_THIS_IN_INITIALIZER_LIST( |
| device_settings_(new MediaStreamDeviceSettings(this))), |
| - audio_input_device_manager_(audio_input_device_manager), |
| - video_capture_manager_(video_capture_manager), |
| + audio_manager_(NULL), |
| monitoring_started_(false), |
| io_loop_(NULL) { |
| memset(active_enumeration_ref_count_, 0, |
| @@ -153,20 +145,6 @@ MediaStreamManager::~MediaStreamManager() { |
| DCHECK(!io_loop_); |
| } |
| -VideoCaptureManager* MediaStreamManager::video_capture_manager() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - DCHECK(video_capture_manager_); |
| - EnsureDeviceThreadAndListener(); |
| - return video_capture_manager_; |
| -} |
| - |
| -AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - DCHECK(audio_input_device_manager_); |
| - EnsureDeviceThreadAndListener(); |
| - return audio_input_device_manager_; |
| -} |
| - |
| void MediaStreamManager::GenerateStream(MediaStreamRequester* requester, |
| int render_process_id, |
| int render_view_id, |
| @@ -197,21 +175,19 @@ void MediaStreamManager::CancelGenerateStream(const std::string& label) { |
| if (it != requests_.end()) { |
| // The request isn't complete. |
| if (!RequestDone(it->second)) { |
| - DeviceRequest* request = &(it->second); |
| - if (request->state[content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE] == |
| - DeviceRequest::STATE_OPENING) { |
| - for (StreamDeviceInfoArray::iterator it = |
| - request->audio_devices.begin(); it != request->audio_devices.end(); |
| - ++it) { |
| - audio_input_device_manager()->Close(it->session_id); |
| + DeviceRequest& request = it->second; |
| + for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES; |
| + ++i) { |
| + const MediaStreamType stream_type = static_cast<MediaStreamType>(i); |
| + if (request.state[stream_type] != DeviceRequest::STATE_OPENING) { |
| + continue; |
| } |
| - } |
| - if (request->state[content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE] == |
| - DeviceRequest::STATE_OPENING) { |
| - for (StreamDeviceInfoArray::iterator it = |
| - request->video_devices.begin(); it != request->video_devices.end(); |
| - ++it) { |
| - video_capture_manager()->Close(it->session_id); |
| + for (StreamDeviceInfoArray::const_iterator device_it = |
| + request.devices.begin(); |
| + device_it != request.devices.end(); ++device_it) { |
| + if (device_it->stream_type == stream_type) { |
| + GetDeviceManager(stream_type)->Close(device_it->session_id); |
| + } |
| } |
| } |
| requests_.erase(it); |
| @@ -231,15 +207,10 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) { |
| StopEnumerateDevices(label); |
| return; |
| } |
| - for (StreamDeviceInfoArray::iterator audio_it = |
| - it->second.audio_devices.begin(); |
| - audio_it != it->second.audio_devices.end(); ++audio_it) { |
| - audio_input_device_manager()->Close(audio_it->session_id); |
| - } |
| - for (StreamDeviceInfoArray::iterator video_it = |
| - it->second.video_devices.begin(); |
| - video_it != it->second.video_devices.end(); ++video_it) { |
| - video_capture_manager()->Close(video_it->session_id); |
| + for (StreamDeviceInfoArray::const_iterator device_it = |
| + it->second.devices.begin(); |
| + device_it != it->second.devices.end(); ++device_it) { |
| + GetDeviceManager(device_it->stream_type)->Close(device_it->session_id); |
| } |
| if (it->second.type == DeviceRequest::GENERATE_STREAM && |
| RequestDone(it->second)) { |
| @@ -257,18 +228,25 @@ void MediaStreamManager::EnumerateDevices( |
| 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); |
| + DCHECK_LT(content::MEDIA_NO_SERVICE, type); |
| + DCHECK_GT(content::NUM_MEDIA_TYPES, type); |
| // Create a new request. |
| StreamOptions options; |
| - EnumerationCache* cache = NULL; |
| - if (type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - options.audio = true; |
| - cache = &audio_enumeration_cache_; |
| + EnumerationCache* cache; |
| + if (type == content::MEDIA_USER_AUDIO_CAPTURE) { |
| + options.audio_type = type; |
| + cache = &user_audio_enumeration_cache_; |
| + } else if (type == content::MEDIA_USER_VIDEO_CAPTURE) { |
| + options.video_type = type; |
| + cache = &user_video_enumeration_cache_; |
| } else { |
| - options.video = true; |
| - cache = &video_enumeration_cache_; |
| + if (content::IsAudioMediaType(type)) { |
| + options.audio_type = type; |
| + } else if (content::IsVideoMediaType(type)) { |
| + options.video_type = type; |
| + } |
| + cache = NULL; |
| } |
| DeviceRequest new_request(requester, options, |
| @@ -277,7 +255,7 @@ void MediaStreamManager::EnumerateDevices( |
| security_origin); |
| new_request.type = DeviceRequest::ENUMERATE_DEVICES; |
| - if (cache->valid) { |
| + if (cache && cache->valid) { |
| // Cached device list of this type exists. Just send it out. |
| new_request.state[type] = DeviceRequest::STATE_REQUESTED; |
| AddRequest(&new_request, label); |
| @@ -289,7 +267,9 @@ void MediaStreamManager::EnumerateDevices( |
| base::Unretained(this), cache, *label)); |
| } else { |
| StartEnumeration(&new_request, label); |
| - StartMonitoring(); |
| + if (cache) { |
| + StartMonitoring(); |
| + } |
| } |
| } |
| @@ -318,17 +298,21 @@ void MediaStreamManager::OpenDevice( |
| // Create a new request. |
| StreamOptions options; |
| - if (type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) |
| - options.audio = true; |
| - else |
| - options.video = true; |
| + if (content::IsAudioMediaType(type)) { |
| + options.audio_type = type; |
| + } else if (content::IsVideoMediaType(type)) { |
| + options.video_type = type; |
| + } else { |
| + LOG(FATAL) << "Cannot handle request for MediaStreamType " << type; |
| + return; |
| + } |
| + options.opt_device_id = device_id; |
|
wjia(left Chromium)
2012/09/03 15:54:17
device_id doesn't belong to here. It should be in
miu
2012/09/04 20:42:19
Actually, I didn't move it from here into StreamOp
|
| DeviceRequest new_request(requester, options, |
| render_process_id, |
| render_view_id, |
| security_origin); |
| new_request.type = DeviceRequest::OPEN_DEVICE; |
| - new_request.requested_device_id = device_id; |
| StartEnumeration(&new_request, label); |
| } |
| @@ -358,8 +342,8 @@ void MediaStreamManager::StopMonitoring() { |
| if (monitoring_started_ && !HasEnumerationRequest()) { |
| base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
| monitoring_started_ = false; |
| - ClearEnumerationCache(&audio_enumeration_cache_); |
| - ClearEnumerationCache(&video_enumeration_cache_); |
| + ClearEnumerationCache(&user_audio_enumeration_cache_); |
| + ClearEnumerationCache(&user_video_enumeration_cache_); |
| } |
| } |
| @@ -373,22 +357,16 @@ void MediaStreamManager::StartEnumeration( |
| std::string* label) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - MediaStreamType stream_type = content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE; |
| - if (Requested(new_request->options, stream_type)) { |
| - new_request->state[stream_type] = DeviceRequest::STATE_REQUESTED; |
| - DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); |
| - if (!active_enumeration_ref_count_[stream_type]) { |
| - ++active_enumeration_ref_count_[stream_type]; |
| - GetDeviceManager(stream_type)->EnumerateDevices(); |
| - } |
| - } |
| - stream_type = content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE; |
| - if (Requested(new_request->options, stream_type)) { |
| - new_request->state[stream_type] = DeviceRequest::STATE_REQUESTED; |
| - DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); |
| - if (!active_enumeration_ref_count_[stream_type]) { |
| - ++active_enumeration_ref_count_[stream_type]; |
| - GetDeviceManager(stream_type)->EnumerateDevices(); |
| + for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES; |
| + ++i) { |
| + const MediaStreamType stream_type = static_cast<MediaStreamType>(i); |
| + if (Requested(new_request->options, stream_type)) { |
| + new_request->state[stream_type] = DeviceRequest::STATE_REQUESTED; |
| + DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); |
| + if (active_enumeration_ref_count_[stream_type] == 0) { |
| + ++active_enumeration_ref_count_[stream_type]; |
| + GetDeviceManager(stream_type)->EnumerateDevices(); |
| + } |
| } |
| } |
| @@ -411,22 +389,46 @@ void MediaStreamManager::AddRequest( |
| (*label) = request_label; |
| } |
| -void MediaStreamManager::EnsureDeviceThreadAndListener() { |
| +void MediaStreamManager::EnsureDeviceManagerStarted( |
| + MediaStreamType stream_type) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (device_thread_.get()) |
| - return; |
| - device_thread_.reset(new DeviceThread("MediaStreamDeviceThread")); |
| - CHECK(device_thread_->Start()); |
| + if (!device_thread_.get()) { |
| + device_thread_.reset(new DeviceThread("MediaStreamDeviceThread")); |
| + CHECK(device_thread_->Start()); |
| + } |
| - audio_input_device_manager_->Register(this, |
| - device_thread_->message_loop_proxy()); |
| - video_capture_manager_->Register(this, device_thread_->message_loop_proxy()); |
| + if (!device_manager_[stream_type]) { |
| + switch (stream_type) { |
| + case content::MEDIA_USER_AUDIO_CAPTURE: |
| + case content::MEDIA_TAB_AUDIO_CAPTURE: |
| + if (!audio_manager_) { |
| + audio_manager_ = content::BrowserMainLoop::GetAudioManager(); |
| + } |
| + device_manager_[stream_type] = |
| + new media_stream::AudioInputDeviceManager(audio_manager_, |
| + stream_type); |
| + break; |
| + case content::MEDIA_USER_VIDEO_CAPTURE: |
| + case content::MEDIA_TAB_VIDEO_CAPTURE: |
| + device_manager_[stream_type] = |
| + new media_stream::VideoCaptureManager(stream_type); |
| + break; |
| + default: |
| + LOG(FATAL) << "Cannot create device manager for invalid or " |
| + << "unsupported MediaStreamType " << stream_type; |
| + return; |
| + } |
| + device_manager_[stream_type]->Register( |
| + this, device_thread_->message_loop_proxy()); |
| + } |
| // We want to be notified of IO message loop destruction to delete the thread |
| // and the device managers. |
| - io_loop_ = MessageLoop::current(); |
| - io_loop_->AddDestructionObserver(this); |
| + if (!io_loop_) { |
| + io_loop_ = MessageLoop::current(); |
| + io_loop_->AddDestructionObserver(this); |
| + } |
| } |
| void MediaStreamManager::Opened(MediaStreamType stream_type, |
| @@ -439,17 +441,11 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, |
| std::string label; |
| for (DeviceRequests::iterator request_it = requests_.begin(); |
| request_it != requests_.end() && request == NULL; ++request_it) { |
| - if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - devices = &(request_it->second.audio_devices); |
| - } else if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { |
| - devices = &(request_it->second.video_devices); |
| - } else { |
| - NOTREACHED(); |
| - } |
| - |
| + devices = &(request_it->second.devices); |
| for (StreamDeviceInfoArray::iterator device_it = devices->begin(); |
| device_it != devices->end(); ++device_it) { |
| - if (device_it->session_id == capture_session_id) { |
| + if (device_it->stream_type == stream_type && |
| + device_it->session_id == capture_session_id) { |
| // We've found the request. |
| device_it->in_use = true; |
| label = request_it->first; |
| @@ -469,6 +465,9 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, |
| // they are. |
| for (StreamDeviceInfoArray::iterator device_it = devices->begin(); |
| device_it != devices->end(); ++device_it) { |
| + if (device_it->stream_type != stream_type) { |
| + continue; |
| + } |
| if (device_it->in_use == false) { |
| // Wait for more devices to be opened before we're done. |
| return; |
| @@ -481,17 +480,36 @@ void MediaStreamManager::Opened(MediaStreamType stream_type, |
| return; |
| } |
| + // Partition the array of devices into audio vs video. |
| + StreamDeviceInfoArray audio_devices, video_devices; |
| + for (StreamDeviceInfoArray::const_iterator device_it = devices->begin(); |
| + device_it != devices->end(); ++device_it) { |
| + if (content::IsAudioMediaType(device_it->stream_type)) { |
| + audio_devices.push_back(*device_it); |
| + } else if (content::IsVideoMediaType(device_it->stream_type)) { |
| + video_devices.push_back(*device_it); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } |
| + |
| switch (request->type) { |
| case DeviceRequest::OPEN_DEVICE: |
| - request->requester->DeviceOpened(label, (*devices)[0]); |
| + if (content::IsAudioMediaType(stream_type)) { |
| + request->requester->DeviceOpened(label, audio_devices.front()); |
| + } else if (content::IsVideoMediaType(stream_type)) { |
| + request->requester->DeviceOpened(label, video_devices.front()); |
| + } else { |
| + NOTREACHED(); |
| + } |
| break; |
| case DeviceRequest::GENERATE_STREAM: |
| - request->requester->StreamGenerated(label, request->audio_devices, |
| - request->video_devices); |
| + request->requester->StreamGenerated(label, audio_devices, video_devices); |
| NotifyObserverDevicesOpened(request); |
| break; |
| default: |
| NOTREACHED(); |
| + break; |
| } |
| } |
| @@ -504,13 +522,20 @@ void MediaStreamManager::DevicesEnumerated( |
| MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - // Only cache device list when there is EnumerateDevices request, since |
| + // Only cache the device list when there is an EnumerateDevices request, since |
| // other requests don't turn on device monitoring. |
| + // NOTE: Caching only applies to the user audio/video capture devices. |
| + EnumerationCache* cache; |
| + if (stream_type == content::MEDIA_USER_AUDIO_CAPTURE) { |
| + cache = &user_audio_enumeration_cache_; |
| + } else if (stream_type == content::MEDIA_USER_VIDEO_CAPTURE) { |
| + cache = &user_video_enumeration_cache_; |
| + } else { |
| + cache = NULL; |
| + } |
| 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 && |
| + HasEnumerationRequest(stream_type) && |
| (!cache->valid || |
| devices.size() != cache->devices.size() || |
| !std::equal(devices.begin(), devices.end(), cache->devices.begin(), |
| @@ -518,6 +543,10 @@ void MediaStreamManager::DevicesEnumerated( |
| cache->valid = true; |
| cache->devices = devices; |
| need_update_clients = true; |
| + } else { |
| + // If stream_type is not a user type, there is no caching. In such cases, |
| + // we assume we always need to update the clients. |
| + need_update_clients = (cache == NULL); |
| } |
| // Publish the result for all requests waiting for device list(s). |
| @@ -537,31 +566,44 @@ void MediaStreamManager::DevicesEnumerated( |
| for (std::list<std::string>::iterator it = label_list.begin(); |
| it != label_list.end(); ++it) { |
| DeviceRequest& request = requests_[*it]; |
| + |
| + // If one specific device has been requested, prune all other devices out. |
| + StreamDeviceInfoArray tmp; |
| + const StreamDeviceInfoArray* pruned_devices; |
| + if (request.options.opt_device_id.empty()) { |
| + pruned_devices = &devices; |
| + } else { |
| + for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); |
| + device_it != devices.end(); ++device_it) { |
| + if (device_it->device_id == request.options.opt_device_id) { |
| + tmp.push_back(*device_it); |
| + } |
| + } |
| + pruned_devices = &tmp; |
| + } |
| + |
| switch (request.type) { |
| case DeviceRequest::ENUMERATE_DEVICES: |
| if (need_update_clients) |
| - request.requester->DevicesEnumerated(*it, devices); |
| + request.requester->DevicesEnumerated(*it, *pruned_devices); |
| break; |
| case DeviceRequest::OPEN_DEVICE: |
| - for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); |
| - device_it != devices.end(); device_it++) { |
| - if (request.requested_device_id == device_it->device_id) { |
| - StreamDeviceInfo device = *device_it; |
| - device.in_use = false; |
| - device.session_id = |
| - GetDeviceManager(device_it->stream_type)->Open(device); |
| - request.state[device_it->stream_type] = |
| - DeviceRequest::STATE_OPENING; |
| - if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) |
| - request.audio_devices.push_back(device); |
| - else |
| - request.video_devices.push_back(device); |
| - break; |
| - } |
| + if (!pruned_devices->empty()) { |
| + StreamDeviceInfo device = pruned_devices->front(); |
| + // For OPEN_DEVICE requests, it is mandatory for the opt_device_id |
| + // field to be provided. See MediaStreamManager::OpenDevice(). |
| + DCHECK(!request.options.opt_device_id.empty()); |
| + DCHECK_EQ(request.options.opt_device_id, device.device_id); |
| + device.in_use = false; |
| + device.session_id = |
| + GetDeviceManager(device.stream_type)->Open(device); |
| + request.state[device.stream_type] = DeviceRequest::STATE_OPENING; |
| + request.devices.push_back(device); |
| } |
| break; |
| default: |
| - device_settings_->AvailableDevices(*it, stream_type, devices); |
| + device_settings_->AvailableDevices(*it, stream_type, *pruned_devices); |
| + break; |
| } |
| } |
| label_list.clear(); |
| @@ -574,52 +616,58 @@ void MediaStreamManager::Error(MediaStreamType stream_type, |
| MediaStreamProviderError error) { |
| // Find the device for the error call. |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end(); |
| ++it) { |
| - StreamDeviceInfoArray* devices = NULL; |
| - if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - devices = &(it->second.audio_devices); |
| - } else if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { |
| - devices = &(it->second.video_devices); |
| - } else { |
| - NOTREACHED(); |
| - } |
| + StreamDeviceInfoArray& devices = it->second.devices; |
| - int device_idx = 0; |
| - for (StreamDeviceInfoArray::iterator device_it = devices->begin(); |
| - device_it != devices->end(); ++device_it, ++device_idx) { |
| - if (device_it->session_id == capture_session_id) { |
| - // We've found the failing device. Find the error case: |
| - if (it->second.state[stream_type] == DeviceRequest::STATE_DONE) { |
| - // 1. Already opened -> signal device failure and close device. |
| - // Use device_idx to signal which of the devices encountered an |
| - // error. |
| - if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - it->second.requester->AudioDeviceFailed(it->first, device_idx); |
| - } else if (stream_type == |
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { |
| - it->second.requester->VideoDeviceFailed(it->first, device_idx); |
| - } |
| - GetDeviceManager(stream_type)->Close(capture_session_id); |
| - // We don't erase the devices here so that we can update the UI |
| - // properly in StopGeneratedStream(). |
| - it->second.state[stream_type] = DeviceRequest::STATE_ERROR; |
| + int audio_device_idx = -1; |
| + int video_device_idx = -1; |
| + for (StreamDeviceInfoArray::iterator device_it = devices.begin(); |
| + device_it != devices.end(); ++device_it) { |
| + if (content::IsAudioMediaType(device_it->stream_type)) { |
| + ++audio_device_idx; |
| + } else if (content::IsVideoMediaType(device_it->stream_type)) { |
| + ++video_device_idx; |
| + } else { |
| + NOTREACHED(); |
| + continue; |
| + } |
| + if (device_it->stream_type != stream_type || |
| + device_it->session_id != capture_session_id) { |
| + continue; |
| + } |
| + // We've found the failing device. Find the error case: |
| + if (it->second.state[stream_type] == DeviceRequest::STATE_DONE) { |
| + // 1. Already opened -> signal device failure and close device. |
| + // Use device_idx to signal which of the devices encountered an |
| + // error. |
| + if (content::IsAudioMediaType(stream_type)) { |
| + it->second.requester->AudioDeviceFailed(it->first, audio_device_idx); |
| + } else if (content::IsVideoMediaType(stream_type)) { |
| + it->second.requester->VideoDeviceFailed(it->first, video_device_idx); |
| } else { |
| - // Request is not done, devices are not opened in this case. |
| - if ((it->second.audio_devices.size() + |
| - it->second.video_devices.size()) <= 1) { |
| - // 2. Device not opened and no other devices for this request -> |
| - // signal stream error and remove the request. |
| - it->second.requester->StreamGenerationFailed(it->first); |
| - requests_.erase(it); |
| - } else { |
| - // 3. Not opened but other devices exists for this request -> remove |
| - // device from list, but don't signal an error. |
| - devices->erase(device_it); |
| - } |
| + NOTREACHED(); |
| + return; |
| + } |
| + GetDeviceManager(stream_type)->Close(capture_session_id); |
| + // We don't erase the devices here so that we can update the UI |
| + // properly in StopGeneratedStream(). |
| + it->second.state[stream_type] = DeviceRequest::STATE_ERROR; |
| + } else { |
| + // Request is not done, devices are not opened in this case. |
| + if (devices.size() <= 1) { |
| + // 2. Device not opened and no other devices for this request -> |
| + // signal stream error and remove the request. |
| + it->second.requester->StreamGenerationFailed(it->first); |
| + requests_.erase(it); |
| + } else { |
| + // 3. Not opened but other devices exists for this request -> remove |
| + // device from list, but don't signal an error. |
| + devices.erase(device_it); // NOTE: This invalidates device_it! |
| } |
| - return; |
| } |
| + return; |
| } |
| } |
| } |
| @@ -628,53 +676,56 @@ void MediaStreamManager::DevicesAccepted(const std::string& label, |
| const StreamDeviceInfoArray& devices) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| DeviceRequests::iterator request_it = requests_.find(label); |
| - if (request_it != requests_.end()) { |
| - if (devices.empty()) { |
| - // No available devices or user didn't accept device usage. |
| - request_it->second.requester->StreamGenerationFailed(request_it->first); |
| - requests_.erase(request_it); |
| - return; |
| - } |
| + if (request_it == requests_.end()) { |
| + return; |
| + } |
| - // Loop through all device types for this request. |
| - for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); |
| - device_it != devices.end(); ++device_it) { |
| - StreamDeviceInfo device_info = *device_it; |
| - |
| - // Set in_use to false to be able to track if this device has been |
| - // opened. in_use might be true if the device type can be used in more |
| - // than one session. |
| - DCHECK_EQ(request_it->second.state[device_it->stream_type], |
| - DeviceRequest::STATE_PENDING_APPROVAL); |
| - device_info.in_use = false; |
| - device_info.session_id = |
| - GetDeviceManager(device_info.stream_type)->Open(device_info); |
| - request_it->second.state[device_it->stream_type] = |
| - DeviceRequest::STATE_OPENING; |
| - if (device_info.stream_type == |
| - content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - request_it->second.audio_devices.push_back(device_info); |
| - } else if (device_info.stream_type == |
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { |
| - request_it->second.video_devices.push_back(device_info); |
| - } else { |
| - NOTREACHED(); |
| - } |
| - } |
| - // Check if we received all stream types requested. |
| - MediaStreamType stream_type = |
| - content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE; |
| - if (Requested(request_it->second.options, stream_type) && |
| - request_it->second.audio_devices.size() == 0) { |
| - request_it->second.state[stream_type] = DeviceRequest::STATE_ERROR; |
| - } |
| - stream_type = content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE; |
| - if (Requested(request_it->second.options, stream_type) && |
| - request_it->second.video_devices.size() == 0) { |
| - request_it->second.state[stream_type] = DeviceRequest::STATE_ERROR; |
| - } |
| + DeviceRequest& request = request_it->second; |
| + |
| + if (devices.empty()) { |
| + // No available devices or user didn't accept device usage. |
| + request.requester->StreamGenerationFailed(request_it->first); |
| + requests_.erase(request_it); |
| return; |
| } |
| + |
| + // Process all newly-accepted devices for this request. |
| + for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); |
| + device_it != devices.end(); ++device_it) { |
| + StreamDeviceInfo device_info = *device_it; // make a copy |
| + |
| + // Set in_use to false to be able to track if this device has been |
| + // opened. in_use might be true if the device type can be used in more |
| + // than one session. |
| + DCHECK_EQ(request.state[device_it->stream_type], |
| + DeviceRequest::STATE_PENDING_APPROVAL); |
| + device_info.in_use = false; |
| + device_info.session_id = |
| + GetDeviceManager(device_info.stream_type)->Open(device_info); |
| + request.state[device_it->stream_type] = DeviceRequest::STATE_OPENING; |
| + request.devices.push_back(device_info); |
| + } |
| + |
| + // Check whether we've received all stream types requested. |
| + bool found_audio = false, found_video = false; |
| + for (StreamDeviceInfoArray::const_iterator i = request.devices.begin(); |
| + i != request.devices.end(); ++i) { |
| + if (i->stream_type == request.options.audio_type) { |
| + found_audio = true; |
| + } else if (i->stream_type == request.options.video_type) { |
| + found_video = true; |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } |
| + if (request.options.audio_type != content::MEDIA_NO_SERVICE && |
| + !found_audio) { |
| + request.state[request.options.audio_type] = DeviceRequest::STATE_ERROR; |
| + } |
| + if (request.options.video_type != content::MEDIA_NO_SERVICE && |
| + !found_video) { |
| + request.state[request.options.video_type] = DeviceRequest::STATE_ERROR; |
| + } |
| } |
| void MediaStreamManager::SettingsError(const std::string& label) { |
| @@ -689,9 +740,21 @@ void MediaStreamManager::SettingsError(const std::string& label) { |
| } |
| } |
| +void MediaStreamManager::SetAudioManager(media::AudioManager* audio_manager) { |
| + LOG_IF(FATAL, (audio_manager_ != NULL) && (audio_manager_ != audio_manager)) |
| + << "Cannot override AudioManager after it has been set."; |
| + audio_manager_ = audio_manager; |
| +} |
| + |
| void MediaStreamManager::UseFakeDevice() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - video_capture_manager()->UseFakeDevice(); |
| + for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES; |
| + ++i) { |
| + const MediaStreamType stream_type = static_cast<MediaStreamType>(i); |
| + if (content::IsVideoMediaType(stream_type)) { |
| + GetVideoCaptureManager(stream_type)->UseFakeDevice(); |
| + } |
| + } |
| device_settings_->UseFakeUI(); |
| } |
| @@ -701,13 +764,20 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() { |
| if (device_thread_.get()) { |
| StopMonitoring(); |
| - video_capture_manager_->Unregister(); |
| - audio_input_device_manager_->Unregister(); |
| + for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES; |
| + ++i) { |
| + if (device_manager_[i]) { |
| + device_manager_[i]->Unregister(); |
| + } |
| + } |
| + |
| device_thread_.reset(); |
| } |
| - audio_input_device_manager_ = NULL; |
| - video_capture_manager_ = NULL; |
| + for (int i = content::MEDIA_NO_SERVICE + 1; i < content::NUM_MEDIA_TYPES; |
| + ++i) { |
| + device_manager_[i] = NULL; |
| + } |
| io_loop_ = NULL; |
| device_settings_.reset(); |
| } |
| @@ -737,85 +807,86 @@ void MediaStreamManager::NotifyObserverDevicesClosed(DeviceRequest* request) { |
| void MediaStreamManager::DevicesFromRequest( |
| DeviceRequest* request, content::MediaStreamDevices* devices) { |
| - StreamDeviceInfoArray::const_iterator it = request->audio_devices.begin(); |
| - for (; it != request->audio_devices.end(); ++it) { |
| - devices->push_back( |
| - content::MediaStreamDevice( |
| - content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE, |
| - it->device_id, |
| - it->name)); |
| - } |
| - for (it = request->video_devices.begin(); it != request->video_devices.end(); |
| - ++it) { |
| - devices->push_back( |
| - content::MediaStreamDevice( |
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE, |
| - it->device_id, |
| - it->name)); |
| + for (StreamDeviceInfoArray::const_iterator it = request->devices.begin(); |
| + it != request->devices.end(); ++it) { |
| + devices->push_back(content::MediaStreamDevice( |
| + it->stream_type, it->device_id, it->name)); |
| } |
| } |
| bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - // Check if all devices are opened. |
| - MediaStreamType stream_type = content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE; |
| - if (Requested(request.options, stream_type)) { |
| - if (request.state[stream_type] != DeviceRequest::STATE_DONE && |
| - request.state[stream_type] != DeviceRequest::STATE_ERROR) { |
| - return false; |
| - } |
| - for (StreamDeviceInfoArray::const_iterator it = |
| - request.audio_devices.begin(); it != request.audio_devices.end(); |
| - ++it) { |
| - if (it->in_use == false) { |
| - return false; |
| - } |
| - } |
| + const bool requested_audio = |
| + content::IsAudioMediaType(request.options.audio_type); |
| + const bool requested_video = |
| + content::IsVideoMediaType(request.options.video_type); |
| + |
| + const bool audio_done = |
| + !requested_audio || |
| + request.state[request.options.audio_type] == DeviceRequest::STATE_DONE || |
| + request.state[request.options.audio_type] == DeviceRequest::STATE_ERROR; |
| + if (!audio_done) { |
| + return false; |
| } |
| - stream_type = content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE; |
| - if (Requested(request.options, stream_type)) { |
| - if (request.state[stream_type] != DeviceRequest::STATE_DONE && |
| - request.state[stream_type] != DeviceRequest::STATE_ERROR) { |
| - return false; |
| - } |
| + const bool video_done = |
| + !requested_video || |
| + request.state[request.options.video_type] == DeviceRequest::STATE_DONE || |
| + request.state[request.options.video_type] == DeviceRequest::STATE_ERROR; |
| + if (!video_done) { |
| + return false; |
| + } |
| - for (StreamDeviceInfoArray::const_iterator it = |
| - request.video_devices.begin(); it != request.video_devices.end(); |
| - ++it) { |
| - if (it->in_use == false) { |
| - return false; |
| - } |
| + for (StreamDeviceInfoArray::const_iterator it = request.devices.begin(); |
| + it != request.devices.end(); ++it) { |
| + if ((!requested_audio && content::IsAudioMediaType(it->stream_type)) || |
| + (!requested_video && content::IsVideoMediaType(it->stream_type))) { |
| + continue; |
| + } |
| + if (it->in_use == false) { |
| + return false; |
| } |
| } |
| return true; |
| } |
| -// Called to get media capture device manager of specified type. |
| MediaStreamProvider* MediaStreamManager::GetDeviceManager( |
| MediaStreamType stream_type) { |
| - if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { |
| - return video_capture_manager(); |
| - } else if (stream_type == content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) { |
| - return audio_input_device_manager(); |
| - } |
| - NOTREACHED(); |
| - return NULL; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + EnsureDeviceManagerStarted(stream_type); |
| + return device_manager_[stream_type]; |
| +} |
| + |
| +VideoCaptureManager* MediaStreamManager::GetVideoCaptureManager( |
| + MediaStreamType stream_type) { |
| + DCHECK(content::IsVideoMediaType(stream_type)); |
| + return reinterpret_cast<VideoCaptureManager*>(GetDeviceManager(stream_type)); |
| +} |
| + |
| +AudioInputDeviceManager* MediaStreamManager::GetAudioInputDeviceManager( |
| + MediaStreamType stream_type) { |
| + DCHECK(content::IsAudioMediaType(stream_type)); |
| + return reinterpret_cast<AudioInputDeviceManager*>( |
| + GetDeviceManager(stream_type)); |
| } |
| void MediaStreamManager::OnDevicesChanged( |
| base::SystemMonitor::DeviceType device_type) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + // NOTE: This method is only called in response to user audio/video device |
| + // changes (from the operating system). |
| + |
| 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_; |
| + stream_type = content::MEDIA_USER_AUDIO_CAPTURE; |
| + cache = &user_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_; |
| + stream_type = content::MEDIA_USER_VIDEO_CAPTURE; |
| + cache = &user_video_enumeration_cache_; |
| } else { |
| return; // Uninteresting device change. |
| } |