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 81f4162377f7b5e4d58fd0c2560c96bd51221654..b51e9bfe703beb9235ff9f320db960a56b1ac5b2 100644 |
| --- a/content/browser/renderer_host/media/media_stream_manager.cc |
| +++ b/content/browser/renderer_host/media/media_stream_manager.cc |
| @@ -6,12 +6,10 @@ |
| #include <stddef.h> |
| #include <stdint.h> |
| -#include <string.h> |
| + |
| #include <algorithm> |
| #include <cctype> |
| #include <list> |
| -#include <utility> |
| -#include <vector> |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| @@ -21,7 +19,6 @@ |
| #include "base/power_monitor/power_monitor.h" |
| #include "base/profiler/scoped_tracker.h" |
| #include "base/rand_util.h" |
| -#include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| @@ -29,11 +26,11 @@ |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_local.h" |
| #include "build/build_config.h" |
| -#include "content/browser/browser_main_loop.h" |
| #include "content/browser/child_process_security_policy_impl.h" |
| #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| #include "content/browser/renderer_host/media/audio_output_device_enumerator.h" |
| #include "content/browser/renderer_host/media/media_capture_devices_impl.h" |
| +#include "content/browser/renderer_host/media/media_devices_manager.h" |
| #include "content/browser/renderer_host/media/media_stream_requester.h" |
| #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
| #include "content/browser/renderer_host/media/video_capture_manager.h" |
| @@ -42,7 +39,6 @@ |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/browser/desktop_media_id.h" |
| #include "content/public/browser/media_observer.h" |
| -#include "content/public/browser/media_request_state.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents_media_capture_id.h" |
| #include "content/public/common/content_client.h" |
| @@ -66,10 +62,6 @@ |
| #include "chromeos/audio/cras_audio_handler.h" |
| #endif |
| -#if defined(OS_MACOSX) |
| -#include "media/device_monitors/device_monitor_mac.h" |
| -#endif |
| - |
| namespace content { |
| base::LazyInstance<base::ThreadLocalPointer<MediaStreamManager>>::Leaky |
| @@ -164,19 +156,6 @@ void EnableHotwordEffect(const StreamControls& controls, int* effects) { |
| } |
| } |
| -// Private helper method to generate a string for the log message that lists the |
| -// human readable names of |devices|. |
| -std::string GetLogMessageString(MediaStreamType stream_type, |
| - const StreamDeviceInfoArray& device_infos) { |
| - std::string output_string = |
| - base::StringPrintf("Getting devices for stream type %d:\n", stream_type); |
| - if (device_infos.empty()) |
| - return output_string + "No devices found."; |
| - for (const content::StreamDeviceInfo& device_info : device_infos) |
| - output_string += " " + device_info.device.name + "\n"; |
| - return output_string; |
| -} |
| - |
| // Clears the MediaStreamDevice.name from all devices in |devices|. |
| void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) { |
| for (content::StreamDeviceInfo& device_info : *devices) |
| @@ -194,6 +173,62 @@ GURL ConvertToGURL(const url::Origin& origin) { |
| return origin.unique() ? GURL() : GURL(origin.Serialize()); |
| } |
| +bool GetDeviceIDFromHMAC(const std::string& salt, |
| + const url::Origin& security_origin, |
| + const std::string& hmac_device_id, |
| + const MediaDeviceInfoArray& devices, |
| + std::string* device_id) { |
| + // The source_id can be empty if the constraint is set but empty. |
| + if (hmac_device_id.empty()) |
| + return false; |
| + |
| + for (const auto& device_info : devices) { |
| + if (MediaStreamManager::DoesMediaDeviceIDMatchHMAC( |
| + salt, security_origin, hmac_device_id, device_info.device_id)) { |
| + *device_id = device_info.device_id; |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +MediaStreamType ConvertToMediaStreamType(MediaDeviceType type) { |
| + switch (type) { |
| + case MEDIA_DEVICE_TYPE_AUDIO_INPUT: |
| + return MEDIA_DEVICE_AUDIO_CAPTURE; |
| + case MEDIA_DEVICE_TYPE_VIDEO_INPUT: |
| + return MEDIA_DEVICE_VIDEO_CAPTURE; |
| + case MEDIA_DEVICE_TYPE_AUDIO_OUTPUT: |
| + return MEDIA_DEVICE_AUDIO_OUTPUT; |
| + default: |
| + NOTREACHED(); |
| + } |
| + |
| + return MEDIA_NO_SERVICE; |
| +} |
| + |
| +StreamDeviceInfoArray ConvertToStreamDeviceInfoArray( |
| + MediaStreamType stream_type, |
| + const MediaDeviceInfoArray& device_infos) { |
| + StreamDeviceInfoArray stream_devices; |
| + for (const auto& info : device_infos) |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
{}
Guido Urdaneta
2016/09/20 13:59:26
Done.
|
| + stream_devices.emplace_back(stream_type, info.label, info.device_id, |
| + info.group_id); |
| + |
| + return stream_devices; |
| +} |
| + |
| +MediaStreamDevices ConvertToMediaStreamDevices( |
| + MediaStreamType stream_type, |
| + const MediaDeviceInfoArray& device_infos) { |
| + MediaStreamDevices devices; |
| + for (const auto& info : device_infos) |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
{}
Guido Urdaneta
2016/09/20 13:59:26
Done.
|
| + devices.emplace_back(stream_type, info.device_id, info.label, |
| + info.group_id); |
| + |
| + return devices; |
| +} |
| + |
| } // namespace |
| @@ -363,13 +398,6 @@ class MediaStreamManager::DeviceRequest { |
| int target_frame_id_; |
| }; |
| -MediaStreamManager::EnumerationCache::EnumerationCache() |
| - : valid(false) { |
| -} |
| - |
| -MediaStreamManager::EnumerationCache::~EnumerationCache() { |
| -} |
| - |
| // static |
| void MediaStreamManager::SendMessageToNativeLog(const std::string& message) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| @@ -392,12 +420,9 @@ MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) |
| #if defined(OS_WIN) |
| video_capture_thread_("VideoCaptureThread"), |
| #endif |
| - monitoring_started_(false), |
| use_fake_ui_(base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kUseFakeUIForMediaStream)) { |
| DCHECK(audio_manager_); |
| - memset(active_enumeration_ref_count_, 0, |
| - sizeof(active_enumeration_ref_count_)); |
| // Some unit tests create the MSM in the IO thread and assumes the |
| // initialization is done synchronously. |
| @@ -450,6 +475,12 @@ MediaStreamManager::audio_output_device_enumerator() { |
| return audio_output_device_enumerator_.get(); |
| } |
| +MediaDevicesManager* MediaStreamManager::media_devices_manager() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(media_devices_manager_.get()); |
| + return media_devices_manager_.get(); |
| +} |
| + |
| std::string MediaStreamManager::MakeMediaAccessRequest( |
| int render_process_id, |
| int render_frame_id, |
| @@ -721,75 +752,37 @@ void MediaStreamManager::DoEnumerateDevices(const std::string& label) { |
| if (request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) { |
| DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); |
| - DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0); |
| request->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, MEDIA_REQUEST_STATE_REQUESTED); |
| - if (active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT] == 0) { |
| - ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT]; |
| - DCHECK(audio_output_device_enumerator_); |
| - audio_output_device_enumerator_->Enumerate( |
| - base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated, |
| - base::Unretained(this))); |
| - } |
| + DCHECK(audio_output_device_enumerator_); |
| + media_devices_manager_->EnumerateDevices( |
| + {{false, false, true /* audio output only*/}}, |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
nit: since you've documented one param, what about
Guido Urdaneta
2016/09/20 13:59:26
Done. Since this is a bit confusing, do you think
tommi (sloooow) - chröme
2016/09/20 14:51:08
This is OK with me as is since the comments explai
|
| + base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated, |
| + base::Unretained(this), label)); |
| return; |
| } |
| - MediaStreamType type; |
| - EnumerationCache* cache; |
| - if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) { |
| - DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); |
| - type = MEDIA_DEVICE_AUDIO_CAPTURE; |
| - cache = &audio_enumeration_cache_; |
| - } else { |
| - DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type()); |
| - DCHECK_EQ(MEDIA_NO_SERVICE, request->audio_type()); |
| - type = MEDIA_DEVICE_VIDEO_CAPTURE; |
| - cache = &video_enumeration_cache_; |
| - } |
| - |
| - if (!EnumerationRequired(cache, type)) { |
| - // Cached device list of this type exists. Just send it out. |
| - request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED); |
| - request->devices = cache->devices; |
| - FinalizeEnumerateDevices(label, request); |
| - } else { |
| - StartEnumeration(request); |
| - } |
| + StartEnumeration(request, label); |
| DVLOG(1) << "Enumerate Devices ({label = " << label << "})"; |
| } |
| void MediaStreamManager::AudioOutputDevicesEnumerated( |
| - const AudioOutputDeviceEnumeration& device_enumeration) { |
| + const std::string& label, |
| + const MediaDeviceEnumeration& enumeration) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - DVLOG(1) << "AudioOutputDevicesEnumerated()"; |
| - StreamDeviceInfoArray device_infos; |
| - if (device_enumeration.has_actual_devices) { |
| - for (const auto& entry : device_enumeration.devices) { |
| - device_infos.emplace_back(MEDIA_DEVICE_AUDIO_OUTPUT, entry.device_name, |
| - entry.unique_id, entry.group_id); |
| - } |
| - } |
| - |
| - const std::string log_message = |
| - "New device enumeration result:\n" + |
| - GetLogMessageString(MEDIA_DEVICE_AUDIO_OUTPUT, device_infos); |
| - SendMessageToNativeLog(log_message); |
| - |
| - // Publish the result for all requests waiting for device list(s). |
| - for (const LabeledDeviceRequest& request : requests_) { |
| - if (request.second->state(MEDIA_DEVICE_AUDIO_OUTPUT) == |
| - MEDIA_REQUEST_STATE_REQUESTED && |
| - request.second->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) { |
| - DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request.second->request_type); |
| - request.second->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, |
| - MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| - request.second->devices = device_infos; |
| - FinalizeEnumerateDevices(request.first, request.second); |
| - } |
| - } |
| + DeviceRequest* request = FindRequest(label); |
| + if (!request) |
| + return; |
| - --active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT]; |
| - DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0); |
| + DCHECK_EQ(MEDIA_DEVICE_AUDIO_OUTPUT, request->audio_type()); |
| + DCHECK_EQ(MEDIA_REQUEST_STATE_REQUESTED, |
| + request->state(MEDIA_DEVICE_AUDIO_OUTPUT)); |
| + DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request->request_type); |
| + DCHECK(!request->ui_proxy.get()); |
| + StreamDeviceInfoArray device_infos = ConvertToStreamDeviceInfoArray( |
| + MEDIA_DEVICE_AUDIO_OUTPUT, enumeration[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]); |
| + request->devices = device_infos; |
| + FinalizeEnumerateDevices(label, request); |
| } |
| void MediaStreamManager::OpenDevice(MediaStreamRequester* requester, |
| @@ -844,61 +837,36 @@ bool MediaStreamManager::TranslateSourceIdToDeviceId( |
| if (source_id.empty()) |
| return false; |
| - const EnumerationCache* cache = |
| - stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? |
| - &audio_enumeration_cache_ : &video_enumeration_cache_; |
| + MediaDeviceType device_type = MEDIA_DEVICE_AUDIO_CAPTURE |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
I'm not fully groking what's supposed to be checke
Guido Urdaneta
2016/09/20 13:59:26
It's actually a type conversion from MediaStreamTy
|
| + ? MEDIA_DEVICE_TYPE_AUDIO_INPUT |
| + : MEDIA_DEVICE_TYPE_VIDEO_INPUT; |
| - // If device monitoring hasn't started, the |device_guid| is not valid. |
| - if (!cache->valid) |
| - return false; |
| - |
| - for (const StreamDeviceInfo& device_info : cache->devices) { |
| - if (DoesMediaDeviceIDMatchHMAC(salt, security_origin, source_id, |
| - device_info.device.id)) { |
| - *device_id = device_info.device.id; |
| - return true; |
| - } |
| - } |
| - return false; |
| + // If device monitoring hasn't started, the |source_id| is not valid. |
| + MediaDeviceInfoArray cached_devices = |
| + media_devices_manager_->GetCachedDeviceInfo(device_type); |
| + return GetDeviceIDFromHMAC(salt, security_origin, source_id, cached_devices, |
| + device_id); |
| } |
| void MediaStreamManager::EnsureDeviceMonitorStarted() { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - StartMonitoring(); |
| -} |
| - |
| -void MediaStreamManager::StopRemovedDevices( |
| - const StreamDeviceInfoArray& old_devices, |
| - const StreamDeviceInfoArray& new_devices) { |
| - DVLOG(1) << "StopRemovedDevices(" |
| - << "{#old_devices = " << old_devices.size() << "} " |
| - << "{#new_devices = " << new_devices.size() << "})"; |
| - for (const StreamDeviceInfo& old_device_info : old_devices) { |
| - bool device_found = false; |
| - for (const StreamDeviceInfo& new_device_info : new_devices) { |
| - if (old_device_info.device.id == new_device_info.device.id) { |
| - device_found = true; |
| - break; |
| - } |
| - } |
| - |
| - if (!device_found) { |
| - // A device has been removed. We need to check if it is used by a |
| - // MediaStream and in that case cleanup and notify the render process. |
| - StopRemovedDevice(old_device_info.device); |
| - } |
| - } |
| + DCHECK(media_devices_manager_); |
| + media_devices_manager_->StartMonitoring(); |
| } |
| -void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) { |
| +void MediaStreamManager::StopRemovedDevice(MediaDeviceType type, |
| + const MediaDeviceInfo& device) { |
| + DCHECK(type == MEDIA_DEVICE_TYPE_AUDIO_INPUT || |
| + type == MEDIA_DEVICE_TYPE_VIDEO_INPUT); |
| + MediaStreamType stream_type = ConvertToMediaStreamType(type); |
| std::vector<int> session_ids; |
| for (const LabeledDeviceRequest& labeled_request : requests_) { |
| const DeviceRequest* request = labeled_request.second; |
| for (const StreamDeviceInfo& device_info : request->devices) { |
| const std::string source_id = GetHMACForMediaDeviceID( |
| - request->salt, request->security_origin, device.id); |
| + request->salt, request->security_origin, device.device_id); |
| if (device_info.device.id == source_id && |
| - device_info.device.type == device.type) { |
| + device_info.device.type == stream_type) { |
| session_ids.push_back(device_info.session_id); |
| if (labeled_request.second->requester) { |
| labeled_request.second->requester->DeviceStopped( |
| @@ -909,86 +877,20 @@ void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) { |
| } |
| } |
| for (const int session_id : session_ids) |
| - StopDevice(device.type, session_id); |
| + StopDevice(stream_type, session_id); |
| AddLogMessageOnIOThread( |
| base::StringPrintf( |
| "Media input device removed: type = %s, id = %s, name = %s ", |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
nit: the whitespace around '=' isn't needed
Guido Urdaneta
2016/09/20 13:59:26
Done.
|
| - (device.type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video"), |
| - device.id.c_str(), device.name.c_str()).c_str()); |
| -} |
| - |
| -void MediaStreamManager::StartMonitoring() { |
| - DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - if (monitoring_started_) |
| - return; |
| - |
| - if (!base::SystemMonitor::Get()) |
| - return; |
| - |
| - monitoring_started_ = true; |
| - base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
| - |
| - // Enumerate both the audio and video input devices to cache the device lists |
| - // and send them to media observer. |
| - ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE]; |
| - audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE); |
| - ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE]; |
| - video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); |
| - |
| -#if defined(OS_MACOSX) |
| - BrowserThread::PostTask( |
| - BrowserThread::UI, FROM_HERE, |
| - base::Bind(&MediaStreamManager::StartMonitoringOnUIThread, |
| - base::Unretained(this))); |
| -#endif |
| + (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video"), |
| + device.device_id.c_str(), device.label.c_str()) |
| + .c_str()); |
| } |
| -void MediaStreamManager::StopMonitoring() { |
| - DCHECK(CalledOnIOThread()); |
| - if (!monitoring_started_) |
| - return; |
| - base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
| - monitoring_started_ = false; |
| - ClearEnumerationCache(&audio_enumeration_cache_); |
| - ClearEnumerationCache(&video_enumeration_cache_); |
| - audio_output_device_enumerator_->SetCachePolicy( |
| - AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); |
| -} |
| - |
| -#if defined(OS_MACOSX) |
| -void MediaStreamManager::StartMonitoringOnUIThread() { |
| - DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is fixed. |
| - tracked_objects::ScopedTracker tracking_profile1( |
| - FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| - "458404 MediaStreamManager::GetBrowserMainLoop")); |
| - BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance(); |
| - if (!browser_main_loop) |
| - return; |
| - |
| - // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is |
| - // fixed. |
| - tracked_objects::ScopedTracker tracking_profile2( |
| - FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| - "458404 MediaStreamManager::GetTaskRunner")); |
| - const scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| - audio_manager_->GetTaskRunner(); |
| - // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is |
| - // fixed. |
| - tracked_objects::ScopedTracker tracking_profile3( |
| - FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| - "458404 MediaStreamManager::DeviceMonitorMac::StartMonitoring")); |
| - browser_main_loop->device_monitor_mac()->StartMonitoring(task_runner); |
| -} |
| -#endif |
| - |
| -// Pick the first valid (translatable) device ID from lists of required |
| -// and optional IDs. |
| -bool MediaStreamManager::PickDeviceId(MediaStreamType type, |
| - const std::string& salt, |
| +bool MediaStreamManager::PickDeviceId(const std::string& salt, |
| const url::Origin& security_origin, |
| const TrackControls& controls, |
| + const MediaDeviceInfoArray& devices, |
| std::string* device_id) const { |
| if (!controls.device_ids.empty()) { |
| if (controls.device_ids.size() > 1) { |
| @@ -996,8 +898,8 @@ bool MediaStreamManager::PickDeviceId(MediaStreamType type, |
| return false; |
| } |
| const std::string& candidate_id = controls.device_ids[0]; |
| - if (!TranslateSourceIdToDeviceId(type, salt, security_origin, candidate_id, |
| - device_id)) { |
| + if (!GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices, |
| + device_id)) { |
| LOG(WARNING) << "Invalid mandatory capture ID = " << candidate_id; |
| return false; |
| } |
| @@ -1005,8 +907,8 @@ bool MediaStreamManager::PickDeviceId(MediaStreamType type, |
| } |
| // We don't have a required ID. Look at the alternates. |
| for (const std::string& candidate_id : controls.alternate_device_ids) { |
| - if (TranslateSourceIdToDeviceId(type, salt, security_origin, candidate_id, |
| - device_id)) { |
| + if (GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices, |
| + device_id)) { |
| return true; |
| } else { |
| LOG(WARNING) << "Invalid optional capture ID = " << candidate_id; |
| @@ -1018,13 +920,14 @@ bool MediaStreamManager::PickDeviceId(MediaStreamType type, |
| bool MediaStreamManager::GetRequestedDeviceCaptureId( |
| const DeviceRequest* request, |
| MediaStreamType type, |
| + const MediaDeviceInfoArray& devices, |
| std::string* device_id) const { |
| if (type == MEDIA_DEVICE_AUDIO_CAPTURE) { |
| - return PickDeviceId(type, request->salt, request->security_origin, |
| - request->controls.audio, device_id); |
| + return PickDeviceId(request->salt, request->security_origin, |
| + request->controls.audio, devices, device_id); |
| } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) { |
| - return PickDeviceId(type, request->salt, request->security_origin, |
| - request->controls.video, device_id); |
| + return PickDeviceId(request->salt, request->security_origin, |
| + request->controls.video, devices, device_id); |
| } else { |
| NOTREACHED(); |
| } |
| @@ -1045,55 +948,29 @@ void MediaStreamManager::TranslateDeviceIdToSourceId( |
| } |
| } |
| -void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { |
| - DCHECK(CalledOnIOThread()); |
| - cache->valid = false; |
| -} |
| - |
| -bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache, |
| - MediaStreamType stream_type) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - if (stream_type == MEDIA_NO_SERVICE) |
| - return false; |
| - |
| - DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| - stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| - |
| -#if defined(OS_ANDROID) |
| - // There's no SystemMonitor on Android that notifies us when devices are |
| - // added or removed, so we need to populate the cache on every request. |
| - // Fortunately, there is an already up-to-date cache in the browser side |
| - // audio manager that we can rely on, so the performance impact of |
| - // invalidating the cache like this, is minimal. |
| - if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) { |
| - // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices |
| - // will be called at the end of the enumeration. |
| - ClearEnumerationCache(cache); |
| - } |
| -#endif |
| - // If the cache isn't valid, we need to start a full enumeration. |
| - return !cache->valid; |
| -} |
| - |
| -void MediaStreamManager::StartEnumeration(DeviceRequest* request) { |
| +void MediaStreamManager::StartEnumeration(DeviceRequest* request, |
| + const std::string& label) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| // Start monitoring the devices when doing the first enumeration. |
| - StartMonitoring(); |
| + media_devices_manager_->StartMonitoring(); |
| // Start enumeration for devices of all requested device types. |
| - const MediaStreamType stream_types[] = {request->audio_type(), |
| - request->video_type()}; |
| - for (const MediaStreamType stream_type : stream_types) { |
| - if (stream_type == MEDIA_NO_SERVICE) |
| - continue; |
| - request->SetState(stream_type, MEDIA_REQUEST_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(stream_type); |
| - } |
| - } |
| + bool request_audio_input = request->audio_type() != MEDIA_NO_SERVICE; |
| + if (request_audio_input) |
| + request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_REQUESTED); |
| + |
| + bool request_video_input = request->video_type() != MEDIA_NO_SERVICE; |
| + if (request_video_input) |
| + request->SetState(request->video_type(), MEDIA_REQUEST_STATE_REQUESTED); |
| + |
| + // base::Unretained is safe here because MediaStreamManager is deleted on the |
| + // UI thread, after the IO thread has been stopped. |
| + DCHECK(request_audio_input || request_video_input); |
| + media_devices_manager_->EnumerateDevices( |
| + {{request_audio_input, request_video_input, false /* no audio output */}}, |
| + base::Bind(&MediaStreamManager::DevicesEnumerated, base::Unretained(this), |
| + request_audio_input, request_video_input, label)); |
| } |
| std::string MediaStreamManager::AddRequest(DeviceRequest* request) { |
| @@ -1134,7 +1011,8 @@ void MediaStreamManager::DeleteRequest(const std::string& label) { |
| void MediaStreamManager::ReadOutputParamsAndPostRequestToUI( |
| const std::string& label, |
| - DeviceRequest* request) { |
| + DeviceRequest* request, |
| + const MediaDeviceEnumeration& enumeration) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| // Actual audio parameters are required only for MEDIA_TAB_AUDIO_CAPTURE. |
| @@ -1150,15 +1028,16 @@ void MediaStreamManager::ReadOutputParamsAndPostRequestToUI( |
| base::Bind(&media::AudioManager::GetDefaultOutputStreamParameters, |
| base::Unretained(audio_manager_)), |
| base::Bind(&MediaStreamManager::PostRequestToUI, base::Unretained(this), |
| - label, request)); |
| + label, request, enumeration)); |
| } else { |
| - PostRequestToUI(label, request, media::AudioParameters()); |
| + PostRequestToUI(label, request, enumeration, media::AudioParameters()); |
| } |
| } |
| void MediaStreamManager::PostRequestToUI( |
| const std::string& label, |
| DeviceRequest* request, |
| + const MediaDeviceEnumeration& enumeration, |
| const media::AudioParameters& output_parameters) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| DCHECK(request->HasUIRequest()); |
| @@ -1181,18 +1060,12 @@ void MediaStreamManager::PostRequestToUI( |
| fake_ui_.reset(new FakeMediaStreamUIProxy()); |
| MediaStreamDevices devices; |
| - if (audio_enumeration_cache_.valid) { |
| - for (const StreamDeviceInfo& device_info : |
| - audio_enumeration_cache_.devices) { |
| - devices.push_back(device_info.device); |
| - } |
| - } |
| - if (video_enumeration_cache_.valid) { |
| - for (const StreamDeviceInfo& device_info : |
| - video_enumeration_cache_.devices) { |
| - devices.push_back(device_info.device); |
| - } |
| - } |
| + for (const auto& info : enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT]) |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
{}
Guido Urdaneta
2016/09/20 13:59:26
Done.
|
| + devices.emplace_back(audio_type, info.device_id, info.label, |
| + info.group_id); |
| + for (const auto& info : enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT]) |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
{}
Guido Urdaneta
2016/09/20 13:59:26
Done.
|
| + devices.emplace_back(video_type, info.device_id, info.label, |
| + info.group_id); |
| fake_ui_->SetAvailableDevices(devices); |
| @@ -1239,36 +1112,24 @@ void MediaStreamManager::SetupRequest(const std::string& label) { |
| } |
| if (!is_web_contents_capture && !is_screen_capture) { |
| - if (EnumerationRequired(&audio_enumeration_cache_, audio_type) || |
| - EnumerationRequired(&video_enumeration_cache_, video_type)) { |
| - // Enumerate the devices if there is no valid device lists to be used. |
| - StartEnumeration(request); |
| + if (audio_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| + video_type == MEDIA_DEVICE_VIDEO_CAPTURE) { |
| + StartEnumeration(request, label); |
| return; |
| - } else { |
| - // Cache is valid, so log the cached devices for MediaStream requests. |
| - if (request->request_type == MEDIA_GENERATE_STREAM) { |
| - std::string log_message("Using cached devices for request.\n"); |
| - if (audio_type != MEDIA_NO_SERVICE) { |
| - log_message += |
| - GetLogMessageString(audio_type, audio_enumeration_cache_.devices); |
| - } |
| - if (video_type != MEDIA_NO_SERVICE) { |
| - log_message += |
| - GetLogMessageString(video_type, video_enumeration_cache_.devices); |
| - } |
| - SendMessageToNativeLog(log_message); |
| - } |
| } |
| - |
| - if (!SetupDeviceCaptureRequest(request)) { |
| + // If no actual device capture is requested, set up the request with an |
| + // empty device list. |
| + if (!SetupDeviceCaptureRequest(request, MediaDeviceEnumeration())) { |
| FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); |
| return; |
| } |
| } |
| - ReadOutputParamsAndPostRequestToUI(label, request); |
| + ReadOutputParamsAndPostRequestToUI(label, request, MediaDeviceEnumeration()); |
| } |
| -bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) { |
| +bool MediaStreamManager::SetupDeviceCaptureRequest( |
| + DeviceRequest* request, |
| + const MediaDeviceEnumeration& enumeration) { |
| DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || |
| request->audio_type() == MEDIA_NO_SERVICE) && |
| (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE || |
| @@ -1276,6 +1137,7 @@ bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) { |
| std::string audio_device_id; |
| if (request->controls.audio.requested && |
| !GetRequestedDeviceCaptureId(request, request->audio_type(), |
| + enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT], |
| &audio_device_id)) { |
| return false; |
| } |
| @@ -1283,6 +1145,7 @@ bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) { |
| std::string video_device_id; |
| if (request->controls.video.requested && |
| !GetRequestedDeviceCaptureId(request, request->video_type(), |
| + enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT], |
| &video_device_id)) { |
| return false; |
| } |
| @@ -1472,6 +1335,7 @@ void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label, |
| fake_ui_.reset(new FakeMediaStreamUIProxy()); |
| request->ui_proxy = std::move(fake_ui_); |
| } else { |
| + DCHECK(!request->ui_proxy); |
| request->ui_proxy = MediaStreamUIProxy::Create(); |
| } |
| @@ -1513,7 +1377,7 @@ void MediaStreamManager::HandleCheckMediaAccessResponse( |
| label, |
| request->devices); |
| - // TODO(tommi): |
| + // TODO(guidou): |
|
tommi (sloooow) - chröme
2016/09/20 08:47:15
w00t!
|
| // Ideally enumeration requests should be deleted once they have been served |
| // (as any request). However, this implementation mixes requests and |
| // notifications together so enumeration requests are kept open by some |
| @@ -1589,11 +1453,6 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() { |
| // and the device managers. |
| base::MessageLoop::current()->AddDestructionObserver(this); |
| - if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| - switches::kUseFakeDeviceForMediaStream)) { |
| - audio_input_device_manager()->UseFakeDevice(); |
| - } |
| - |
| // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is |
| // fixed. |
| tracked_objects::ScopedTracker tracking_profile4( |
| @@ -1614,6 +1473,9 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() { |
| audio_output_device_enumerator_.reset(new AudioOutputDeviceEnumerator( |
| audio_manager_, AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING)); |
| + |
| + media_devices_manager_.reset( |
| + new MediaDevicesManager(audio_manager_, video_capture_manager_, this)); |
| } |
| void MediaStreamManager::Opened(MediaStreamType stream_type, |
| @@ -1702,91 +1564,45 @@ void MediaStreamManager::Closed(MediaStreamType stream_type, |
| } |
| void MediaStreamManager::DevicesEnumerated( |
| - MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { |
| + bool requested_audio_input, |
| + bool requested_video_input, |
| + const std::string& label, |
| + const MediaDeviceEnumeration& enumeration) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - DVLOG(1) << "DevicesEnumerated(" |
| - << "{stream_type = " << stream_type << "})"; |
| - |
| - std::string log_message = "New device enumeration result:\n" + |
| - GetLogMessageString(stream_type, devices); |
| - SendMessageToNativeLog(log_message); |
| - |
| - // Only cache the device list when the device list has been changed. |
| - bool need_update_clients = false; |
| - bool need_update_device_change_subscribers = false; |
| - EnumerationCache* cache = stream_type == MEDIA_DEVICE_AUDIO_CAPTURE |
| - ? &audio_enumeration_cache_ |
| - : &video_enumeration_cache_; |
| - if (!cache->valid || devices.size() != cache->devices.size() || |
| - !std::equal(devices.begin(), devices.end(), cache->devices.begin(), |
| - StreamDeviceInfo::IsEqual)) { |
| - StopRemovedDevices(cache->devices, devices); |
| - need_update_clients = true; |
| - // Device-change subscribers should not be notified the first time the cache |
| - // is loaded , as this is not a change in the set of devices. The same |
| - // applies to enumerations listing no devices when the cache is empty. |
| - need_update_device_change_subscribers = |
| - cache->valid && (devices.size() != 0 || cache->devices.size() != 0); |
| - cache->devices = devices; |
| - |
| - // The device might not be able to be enumerated when it is not warmed up, |
| - // for example, when the machine just wakes up from sleep. We set the cache |
| - // to be invalid so that the next media request will trigger the |
| - // enumeration again. See issue/317673. |
| - cache->valid = !devices.empty(); |
| - } |
| - |
| - if (need_update_clients && monitoring_started_) |
| - NotifyDevicesChanged(stream_type, devices); |
| - |
| - if (need_update_device_change_subscribers) |
| - NotifyDeviceChangeSubscribers(stream_type); |
| - |
| - // 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 |
| - // back from device_settings that will need to iterate through devices. |
| - std::list<std::string> label_list; |
| - for (const LabeledDeviceRequest& labeled_request : requests_) { |
| - DeviceRequest* const request = labeled_request.second; |
| - if (request->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && |
| - (request->audio_type() == stream_type || |
| - request->video_type() == stream_type)) { |
| - if (request->request_type != MEDIA_ENUMERATE_DEVICES) |
| - request->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| - label_list.push_back(labeled_request.first); |
| - } |
| - } |
| - for (const std::string& label : label_list) { |
| - DeviceRequest* const request = FindRequest(label); |
| - switch (request->request_type) { |
| - case MEDIA_ENUMERATE_DEVICES: |
| - if (need_update_clients && request->requester) { |
| - request->devices = devices; |
| - FinalizeEnumerateDevices(label, request); |
| - } |
| - break; |
| - default: |
| - if (request->state(request->audio_type()) == |
| - MEDIA_REQUEST_STATE_REQUESTED || |
| - request->state(request->video_type()) == |
| - MEDIA_REQUEST_STATE_REQUESTED) { |
| - // We are doing enumeration for other type of media, wait until it is |
| - // all done before posting the request to UI because UI needs |
| - // the device lists to handle the request. |
| - break; |
| - } |
| - if (!SetupDeviceCaptureRequest(request)) |
| - FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); |
| - else |
| - ReadOutputParamsAndPostRequestToUI(label, request); |
| - break; |
| + DeviceRequest* request = FindRequest(label); |
| + if (!request) |
| + return; |
| + |
| + bool requested[] = {requested_audio_input, requested_video_input}; |
| + MediaStreamType stream_types[] = {MEDIA_DEVICE_AUDIO_CAPTURE, |
| + MEDIA_DEVICE_VIDEO_CAPTURE}; |
| + MediaDeviceType device_types[] = {MEDIA_DEVICE_TYPE_AUDIO_INPUT, |
| + MEDIA_DEVICE_TYPE_VIDEO_INPUT}; |
| + |
| + for (size_t i = 0; i < arraysize(requested); ++i) { |
| + if (!requested[i]) |
| + continue; |
| + |
| + DCHECK(request->audio_type() == stream_types[i] || |
| + request->video_type() == stream_types[i]); |
| + if (request->state(stream_types[i]) == MEDIA_REQUEST_STATE_REQUESTED) { |
| + if (request->request_type == MEDIA_ENUMERATE_DEVICES) { |
| + // MEDIA_ENUMERATE_DEVICES requests are always for a single type, so it |
| + // is OK to ignore any remaining iteration in this loop. |
| + ProcessEnumerationRequest(label, request, stream_types[i], |
| + enumeration[device_types[i]]); |
| + return; |
| + } |
| + // Not a MEDIA_ENUMERATE_DEVICES request. |
| + request->SetState(stream_types[i], MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| } |
| } |
| - label_list.clear(); |
| - --active_enumeration_ref_count_[stream_type]; |
| - DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); |
| + |
| + if (!SetupDeviceCaptureRequest(request, enumeration)) |
| + FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); |
| + else |
| + ReadOutputParamsAndPostRequestToUI(label, request, enumeration); |
| } |
| void MediaStreamManager::Aborted(MediaStreamType stream_type, |
| @@ -1957,7 +1773,7 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() { |
| DCHECK(CalledOnIOThread()); |
| DCHECK(requests_.empty()); |
| if (device_task_runner_.get()) { |
| - StopMonitoring(); |
| + media_devices_manager_->StopMonitoring(); |
| video_capture_manager_->Unregister(); |
| audio_input_device_manager_->Unregister(); |
| @@ -1967,20 +1783,20 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() { |
| audio_input_device_manager_ = NULL; |
| video_capture_manager_ = NULL; |
| audio_output_device_enumerator_ = NULL; |
| + media_devices_manager_ = NULL; |
| g_media_stream_manager_tls_ptr.Pointer()->Set(NULL); |
| } |
| void MediaStreamManager::NotifyDevicesChanged( |
| - MediaStreamType stream_type, |
| - const StreamDeviceInfoArray& devices) { |
| + MediaDeviceType device_type, |
| + const MediaDeviceInfoArray& devices) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| MediaObserver* media_observer = |
| GetContentClient()->browser()->GetMediaObserver(); |
| - // Map the devices to MediaStreamDevices. |
| - MediaStreamDevices new_devices; |
| - for (const StreamDeviceInfo& device_info : devices) |
| - new_devices.push_back(device_info.device); |
| + MediaStreamType stream_type = ConvertToMediaStreamType(device_type); |
| + MediaStreamDevices new_devices = |
| + ConvertToMediaStreamDevices(stream_type, devices); |
| if (IsAudioInputMediaType(stream_type)) { |
| MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged( |
| @@ -1995,6 +1811,8 @@ void MediaStreamManager::NotifyDevicesChanged( |
| } else { |
| NOTREACHED(); |
| } |
| + |
| + ProcessOpenEnumerationRequests(stream_type, devices); |
| } |
| bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { |
| @@ -2030,28 +1848,6 @@ MediaStreamProvider* MediaStreamManager::GetDeviceManager( |
| return NULL; |
| } |
| -void MediaStreamManager::OnDevicesChanged( |
| - base::SystemMonitor::DeviceType device_type) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - |
| - // NOTE: This method is only called in response to physical audio/video device |
| - // changes (from the operating system). |
| - |
| - MediaStreamType stream_type; |
| - if (device_type == base::SystemMonitor::DEVTYPE_AUDIO) { |
| - stream_type = MEDIA_DEVICE_AUDIO_CAPTURE; |
| - } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) { |
| - stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; |
| - } else { |
| - return; // Uninteresting device change. |
| - } |
| - |
| - // Always do enumeration even though some enumeration is in progress, because |
| - // those enumeration commands could be sent before these devices change. |
| - ++active_enumeration_ref_count_[stream_type]; |
| - GetDeviceManager(stream_type)->EnumerateDevices(stream_type); |
| -} |
| - |
| void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type, |
| StreamDeviceInfoArray devices, |
| gfx::NativeViewId window_id) { |
| @@ -2173,7 +1969,6 @@ void MediaStreamManager::SetCapturingLinkSecured(int render_process_id, |
| content::MediaStreamType type, |
| bool is_secure) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - |
| for (LabeledDeviceRequest& labeled_request : requests_) { |
| DeviceRequest* request = labeled_request.second; |
| if (request->requesting_process_id != render_process_id) |
| @@ -2189,4 +1984,47 @@ void MediaStreamManager::SetCapturingLinkSecured(int render_process_id, |
| } |
| } |
| +void MediaStreamManager::ProcessEnumerationRequest( |
| + const std::string& label, |
| + DeviceRequest* request, |
| + MediaStreamType stream_type, |
| + const MediaDeviceInfoArray& device_infos) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK_EQ(MEDIA_REQUEST_STATE_REQUESTED, request->state(stream_type)); |
| + DCHECK(request->audio_type() == stream_type || |
| + request->video_type() == stream_type); |
| + DCHECK(request->audio_type() == MEDIA_NO_SERVICE || |
| + request->video_type() == MEDIA_NO_SERVICE); |
| + DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request->request_type); |
| + |
| + if (request->requester && !request->ui_proxy) { |
| + request->devices = |
| + ConvertToStreamDeviceInfoArray(stream_type, device_infos); |
| + FinalizeEnumerateDevices(label, request); |
| + } |
| +} |
| + |
| +// This function is intended to support subscription-style device enumerations. |
| +// It is only supported for media capture devices and will be removed once |
| +// handling of enumeration requests and device-change notifications is migrated |
| +// out of MediaStreamManager. |
| +void MediaStreamManager::ProcessOpenEnumerationRequests( |
| + MediaStreamType stream_type, |
| + const MediaDeviceInfoArray& device_infos) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| + stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| + |
| + for (const LabeledDeviceRequest& labeled_request : requests_) { |
| + DeviceRequest* request = labeled_request.second; |
| + if (request->request_type == MEDIA_ENUMERATE_DEVICES && |
| + request->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && |
| + (request->audio_type() == stream_type || |
| + request->video_type() == stream_type)) { |
| + ProcessEnumerationRequest(labeled_request.first, request, stream_type, |
| + device_infos); |
| + } |
| + } |
| +} |
| + |
| } // namespace content |