Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(870)

Unified Diff: content/browser/device_monitor_mac.mm

Issue 24615005: Added AVFoundation Glue and Device Monitoring for Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rsesek@'s comments addressed. Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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) {

Powered by Google App Engine
This is Rietveld 408576698