Chromium Code Reviews| Index: content/browser/device_monitor_mac.mm |
| diff --git a/content/browser/device_monitor_mac.mm b/content/browser/device_monitor_mac.mm |
| index 7b12e91cbdf4ed8b57fc020d3b75c0579240d0ef..0f4423b4e0c4425673a7990bdc32e1e9813844af 100644 |
| --- a/content/browser/device_monitor_mac.mm |
| +++ b/content/browser/device_monitor_mac.mm |
| @@ -7,39 +7,112 @@ |
| #import <QTKit/QTKit.h> |
| #include "base/logging.h" |
| +#include "media/video/capture/mac/avfoundation_glue.h" |
|
Robert Sesek
2013/10/15 20:44:46
#import because the file being included contains O
mcasas
2013/10/16 11:04:40
Done.
|
| -namespace content { |
| +namespace { |
| -class DeviceMonitorMac::QTMonitorImpl { |
| - public: |
| - explicit QTMonitorImpl(DeviceMonitorMac* monitor); |
| - virtual ~QTMonitorImpl() {} |
| +// This class is used to keep track of system devices names and their types. |
| +class DeviceInfo { |
|
Robert Sesek
2013/10/15 20:44:46
nit: remove
mcasas
2013/10/16 11:04:40
Done.
|
| - void Start(); |
| - void Stop(); |
| + public: |
| + enum DeviceType { |
| + kAudio, |
| + kVideo, |
| + kMuxed |
| + }; |
| + |
| + DeviceInfo(std::string unique_id, DeviceType type) |
| + : unique_id_(unique_id), type_(type) {} |
| + |
| + // Operator== is needed here to use this class in a std::vector. |
| + bool operator==(const DeviceInfo& device) const { |
| + return unique_id_ == device.unique_id_; |
| + } |
|
Robert Sesek
2013/10/15 20:44:46
nit: blank line after
mcasas
2013/10/16 11:04:40
Done.
|
| + std::string unique_id() const { return unique_id_; } |
|
Robert Sesek
2013/10/15 20:44:46
Return a const ref
mcasas
2013/10/16 11:04:40
Done.
|
| + DeviceType type() const { return type_; } |
| - private: |
| - void OnDeviceChanged(); |
| +private: |
|
Robert Sesek
2013/10/15 20:44:46
nit: 1 space indent
mcasas
2013/10/16 11:04:40
Done.
|
| + std::string unique_id_; |
| + DeviceType type_; |
| + // Allow generated copy constructor and assignment. |
| +}; |
| - DeviceMonitorMac* monitor_; |
| - int number_audio_devices_; |
| - int number_video_devices_; |
| +// Base class used by DeviceMonitorMac to interact with either a QTKit or an |
| +// AVFoundation implementation of events and notifications. This class should |
| +// never be instantiated on its own. |
| +class MacMonitor { |
| + public: |
| + MacMonitor() {} |
|
Robert Sesek
2013/10/15 20:44:46
Remove this ctor?
mcasas
2013/10/16 11:04:40
Done. Note that this forces adding a explicit call
|
| + explicit MacMonitor(content::DeviceMonitorMac* monitor) |
| + : monitor_(monitor), |
| + cached_devices_(), |
| + device_arrival_(nil), |
| + device_removal_(nil) { DCHECK(monitor); } |
| + virtual ~MacMonitor() {} |
|
Robert Sesek
2013/10/15 20:44:46
This dtor needn't be virtual — it does not inherit
mcasas
2013/10/16 11:04:40
Done.
|
| + |
| + virtual void OnDeviceChanged() = 0; |
| + void ConsolidateDevicesListAndNotify( |
|
Robert Sesek
2013/10/15 20:44:46
Comments needed.
mcasas
2013/10/16 11:04:40
Done.
|
| + std::vector<DeviceInfo> snapshot_devices); |
| + |
| + protected: |
| + content::DeviceMonitorMac* monitor_; |
| + std::vector<DeviceInfo> cached_devices_; |
| id device_arrival_; |
| id device_removal_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl); |
| + DISALLOW_COPY_AND_ASSIGN(MacMonitor); |
| }; |
| -DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor) |
| - : monitor_(monitor), |
| - number_audio_devices_(0), |
| - number_video_devices_(0), |
| - device_arrival_(nil), |
| - device_removal_(nil) { |
| - DCHECK(monitor); |
| +void MacMonitor::ConsolidateDevicesListAndNotify( |
| + std::vector<DeviceInfo> snapshot_devices) { |
| + int video_device_added = 0; |
| + int audio_device_added = 0; |
| + int video_device_removed = 0; |
| + int audio_device_removed = 0; |
| + |
| + // Compare the current system devices snapshot with the ones cached to detect |
| + // additions, present in the former but not in the latter. If we find a device |
| + // in snapshot_devices entry also present in cached_devices, we remove it from |
| + // the latter vector. |
| + std::vector<DeviceInfo>::iterator it; |
| + for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) { |
| + std::vector<DeviceInfo>::iterator cached_devices_iterator = |
| + std::find(cached_devices_.begin(), cached_devices_.end(), *it); |
| + if (cached_devices_iterator == cached_devices_.end()) { |
| + video_device_added += ((it->type() == DeviceInfo::kVideo) || |
| + (it->type() == DeviceInfo::kMuxed)); |
| + audio_device_added += ((it->type() == DeviceInfo::kAudio) || |
| + (it->type() == DeviceInfo::kMuxed)); |
| + DVLOG(1) << "Device has been added, id: " << it->unique_id(); |
| + } else { |
| + cached_devices_.erase(cached_devices_iterator); |
| + } |
| + } |
| + // All the remaining entries in cached_devices are removed devices. |
| + for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) { |
| + video_device_removed += ((it->type() == DeviceInfo::kVideo) || |
| + (it->type() == DeviceInfo::kMuxed)); |
| + audio_device_removed += ((it->type() == DeviceInfo::kAudio) || |
| + (it->type() == DeviceInfo::kMuxed)); |
| + DVLOG(1) << "Device has been removed, id: " << it->unique_id(); |
| + } |
| + // Update the cached devices with the current system snapshot. |
| + cached_devices_.swap(snapshot_devices); |
| + |
| + if (video_device_added || video_device_removed) |
| + monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
| + if (audio_device_added || video_device_removed) |
| + monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
| } |
| -void DeviceMonitorMac::QTMonitorImpl::Start() { |
| +class QTKitMonitorImpl : public MacMonitor { |
| + public: |
| + explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor); |
| + virtual ~QTKitMonitorImpl(); |
| + |
| + virtual void OnDeviceChanged() OVERRIDE; |
| +}; |
| + |
| +QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor) { |
| NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| device_arrival_ = |
| [nc addObserverForName:QTCaptureDeviceWasConnectedNotification |
| @@ -56,48 +129,113 @@ void DeviceMonitorMac::QTMonitorImpl::Start() { |
| OnDeviceChanged();}]; |
| } |
| -void DeviceMonitorMac::QTMonitorImpl::Stop() { |
| - if (!monitor_) |
| - return; |
| - |
| +QTKitMonitorImpl::~QTKitMonitorImpl() { |
| NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| [nc removeObserver:device_arrival_]; |
| [nc removeObserver:device_removal_]; |
| } |
| -void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() { |
| +void QTKitMonitorImpl::OnDeviceChanged() { |
| + std::vector<DeviceInfo> snapshot_devices; |
| + DeviceInfo::DeviceType device_info; |
| + |
| NSArray* devices = [QTCaptureDevice inputDevices]; |
| - int number_video_devices = 0; |
| - int number_audio_devices = 0; |
| for (QTCaptureDevice* device in devices) { |
| - if ([device hasMediaType:QTMediaTypeVideo] || |
| - [device hasMediaType:QTMediaTypeMuxed]) |
| - ++number_video_devices; |
| - |
| - if ([device hasMediaType:QTMediaTypeSound] || |
| - [device hasMediaType:QTMediaTypeMuxed]) |
| - ++number_audio_devices; |
| + if ([device hasMediaType:QTMediaTypeVideo]) |
| + device_info = DeviceInfo::kVideo; |
| + else if ([device hasMediaType:QTMediaTypeMuxed]) |
| + device_info = DeviceInfo::kMuxed; |
| + else if ([device hasMediaType:QTMediaTypeSound]) |
| + device_info = DeviceInfo::kAudio; |
| + |
| + snapshot_devices.push_back( |
| + DeviceInfo([[device uniqueID] UTF8String], device_info)); |
| } |
| - if (number_video_devices_ != number_video_devices) { |
| - number_video_devices_ = number_video_devices; |
| - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
| - } |
| + ConsolidateDevicesListAndNotify(snapshot_devices); |
| +} |
| - if (number_audio_devices_ != number_audio_devices) { |
| - number_audio_devices_ = number_audio_devices; |
| - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
| +class AVFoundationMonitorImpl : public MacMonitor { |
| + public: |
| + explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor); |
| + virtual ~AVFoundationMonitorImpl(); |
| + |
| + virtual void OnDeviceChanged() OVERRIDE; |
| +}; |
| + |
| +AVFoundationMonitorImpl::AVFoundationMonitorImpl( |
| + content::DeviceMonitorMac* monitor) { |
| + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| + NSOperationQueue* main_queue = [NSOperationQueue mainQueue]; |
| + |
| + device_arrival_ = |
| + [nc addObserverForName:AVFoundationGlue:: |
| + AvCaptureDeviceWasConnectedNotification() |
| + object:nil |
| + queue:main_queue |
| + usingBlock:^(NSNotification* notification) { |
| + OnDeviceChanged();}]; |
| + DCHECK(device_arrival_); |
| + device_removal_ = |
|
Robert Sesek
2013/10/15 20:44:46
nit: check indention after ths line
mcasas
2013/10/16 11:04:40
Done.
|
| + [nc addObserverForName:AVFoundationGlue:: |
| + AvCaptureDeviceWasDisconnectedNotification() |
| + object:nil |
| + queue:main_queue |
| + usingBlock:^(NSNotification* notification) { |
| + OnDeviceChanged();}]; |
| + DCHECK(device_removal_); |
| +} |
| + |
| +AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { |
| + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| + [nc removeObserver:device_arrival_]; |
| + [nc removeObserver:device_removal_]; |
| +} |
| + |
| +void AVFoundationMonitorImpl::OnDeviceChanged() { |
| + std::vector<DeviceInfo> snapshot_devices; |
| + DeviceInfo::DeviceType device_info; |
| + |
| + NSArray* devices = [AVCaptureDeviceGlue devices]; |
| + for (CrAVCaptureDevice* device in devices) { |
| + if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::AvMediaTypeVideo() |
| + forCaptureDevice:device]) { |
| + device_info = DeviceInfo::kVideo; |
| + } else if ([AVCaptureDeviceGlue |
| + hasMediaType:AVFoundationGlue::AvMediaTypeMuxed() |
| + forCaptureDevice:device]) { |
| + device_info = DeviceInfo::kMuxed; |
| + } else if ([AVCaptureDeviceGlue |
| + hasMediaType:AVFoundationGlue::AvMediaTypeAudio() |
| + forCaptureDevice:device]) { |
| + device_info = DeviceInfo::kAudio; |
| + } |
| + snapshot_devices.push_back(DeviceInfo( |
| + [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_info)); |
| } |
| + |
| + ConsolidateDevicesListAndNotify(snapshot_devices); |
| } |
| +} // namespace |
| + |
| +namespace content { |
| + |
| DeviceMonitorMac::DeviceMonitorMac() { |
| - qt_monitor_.reset(new QTMonitorImpl(this)); |
| - qt_monitor_->Start(); |
| + if (AVFoundationGlue::IsAVFoundationSupported()) { |
| + DVLOG(1) << "Monitoring via AVFoundation"; |
| + device_monitor_impl_.reset(new AVFoundationMonitorImpl(this)); |
| + // Force the device enumeration so we enumerate correctly devices already in |
| + // the system and at the same time use the AVCaptureDeviceGlue so it in |
| + // turn forces the AVCaptureDeviceGlue alloc-init. |
| + device_monitor_impl_->OnDeviceChanged(); |
| + } else { |
| + DVLOG(1) << "Monitoring via QTKit"; |
| + device_monitor_impl_.reset(new QTKitMonitorImpl(this)); |
| + } |
| } |
| -DeviceMonitorMac::~DeviceMonitorMac() { |
| - qt_monitor_->Stop(); |
| -} |
| +DeviceMonitorMac::~DeviceMonitorMac() {} |
| void DeviceMonitorMac::NotifyDeviceChanged( |
| base::SystemMonitor::DeviceType type) { |