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

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: Added comments following avi@ ones. 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
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | media/media.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..4c2238ff3ffea125612c12c0c312dc09d9b6b260 100644
--- a/content/browser/device_monitor_mac.mm
+++ b/content/browser/device_monitor_mac.mm
@@ -7,97 +7,248 @@
#import <QTKit/QTKit.h>
#include "base/logging.h"
+#import "media/video/capture/mac/avfoundation_glue.h"
-namespace content {
+namespace {
-class DeviceMonitorMac::QTMonitorImpl {
+// This class is used to keep track of system devices names and their types.
+class DeviceInfo {
public:
- explicit QTMonitorImpl(DeviceMonitorMac* monitor);
- virtual ~QTMonitorImpl() {}
+ enum DeviceType {
+ kAudio,
+ kVideo,
+ kMuxed,
+ kUnknown
+ };
+
+ DeviceInfo(std::string unique_id, DeviceType type)
+ : unique_id_(unique_id), type_(type) {}
+
+ // Operator== is needed here to use this class in a std::find. A given
+ // |unique_id_| always has the same |type_| so for comparison purposes the
+ // latter can be safely ignored.
+ bool operator==(const DeviceInfo& device) const {
+ return unique_id_ == device.unique_id_;
+ }
- void Start();
- void Stop();
+ const std::string& unique_id() const { return unique_id_; }
+ DeviceType type() const { return type_; }
private:
- void OnDeviceChanged();
+ std::string unique_id_;
+ DeviceType type_;
+ // Allow generated copy constructor and assignment.
+};
+
+// Base abstract class used by DeviceMonitorMac to interact with either a QTKit
+// or an AVFoundation implementation of events and notifications.
+class DeviceMonitorMacImpl {
+ public:
+ explicit DeviceMonitorMacImpl(content::DeviceMonitorMac* monitor)
+ : monitor_(monitor),
+ cached_devices_(),
+ device_arrival_(nil),
+ device_removal_(nil) {
+ DCHECK(monitor);
+ }
+ virtual ~DeviceMonitorMacImpl() {}
- DeviceMonitorMac* monitor_;
- int number_audio_devices_;
- int number_video_devices_;
+ virtual void OnDeviceChanged() = 0;
+
+ // Method called by the default notification center when a device is removed
+ // or added to the system. It will compare the |cached_devices_| with the
+ // current situation, update it, and, if there's an update, signal to
+ // |monitor_| with the appropriate device type.
+ void ConsolidateDevicesListAndNotify(
+ const std::vector<DeviceInfo>& snapshot_devices);
+
+ protected:
+ content::DeviceMonitorMac* monitor_;
+ std::vector<DeviceInfo> cached_devices_;
+
+ // Handles to NSNotificationCenter block observers.
id device_arrival_;
id device_removal_;
- DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl);
};
-DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor)
- : monitor_(monitor),
- number_audio_devices_(0),
- number_video_devices_(0),
- device_arrival_(nil),
- device_removal_(nil) {
- DCHECK(monitor);
+void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
+ const std::vector<DeviceInfo>& snapshot_devices) {
+ bool video_device_added = false;
+ bool audio_device_added = false;
+ bool video_device_removed = false;
+ bool audio_device_removed = false;
+
+ // 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>::const_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_ = 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 DeviceMonitorMacImpl {
+ public:
+ explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
+ virtual ~QTKitMonitorImpl();
+
+ virtual void OnDeviceChanged() OVERRIDE;
+};
+
+QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
+ : DeviceMonitorMacImpl(monitor) {
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
device_arrival_ =
- [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
+ [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ OnDeviceChanged();
+ }];
device_removal_ =
[nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
+ 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;
+
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;
+ DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
+ if ([device hasMediaType:QTMediaTypeVideo])
+ device_type = DeviceInfo::kVideo;
+ else if ([device hasMediaType:QTMediaTypeMuxed])
+ device_type = DeviceInfo::kMuxed;
+ else if ([device hasMediaType:QTMediaTypeSound])
+ device_type = DeviceInfo::kAudio;
- if ([device hasMediaType:QTMediaTypeSound] ||
- [device hasMediaType:QTMediaTypeMuxed])
- ++number_audio_devices;
+ snapshot_devices.push_back(
+ DeviceInfo([[device uniqueID] UTF8String], device_type));
}
- 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 DeviceMonitorMacImpl {
+ public:
+ explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
+ virtual ~AVFoundationMonitorImpl();
+
+ virtual void OnDeviceChanged() OVERRIDE;
+};
+
+AVFoundationMonitorImpl::AVFoundationMonitorImpl(
+ content::DeviceMonitorMac* monitor)
+ : DeviceMonitorMacImpl(monitor) {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+
+ device_arrival_ =
+ [nc addObserverForName:AVFoundationGlue::
+ AVCaptureDeviceWasConnectedNotification()
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ OnDeviceChanged();
+ }];
+ device_removal_ =
+ [nc addObserverForName:AVFoundationGlue::
+ AVCaptureDeviceWasDisconnectedNotification()
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ OnDeviceChanged();
+ }];
+}
+
+AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:device_arrival_];
+ [nc removeObserver:device_removal_];
+}
+
+void AVFoundationMonitorImpl::OnDeviceChanged() {
+ std::vector<DeviceInfo> snapshot_devices;
+
+ NSArray* devices = [AVCaptureDeviceGlue devices];
+ for (CrAVCaptureDevice* device in devices) {
+ DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
+ if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::AVMediaTypeVideo()
+ forCaptureDevice:device]) {
+ device_type = DeviceInfo::kVideo;
+ } else if ([AVCaptureDeviceGlue
+ hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()
+ forCaptureDevice:device]) {
+ device_type = DeviceInfo::kMuxed;
+ } else if ([AVCaptureDeviceGlue
+ hasMediaType:AVFoundationGlue::AVMediaTypeAudio()
+ forCaptureDevice:device]) {
+ device_type = DeviceInfo::kAudio;
+ }
+ snapshot_devices.push_back(DeviceInfo(
+ [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_type));
}
+
+ 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));
+ } else {
+ DVLOG(1) << "Monitoring via QTKit";
+ device_monitor_impl_.reset(new QTKitMonitorImpl(this));
+ }
+ // Force device enumeration to correctly list those already in the system.
+ device_monitor_impl_->OnDeviceChanged();
}
-DeviceMonitorMac::~DeviceMonitorMac() {
- qt_monitor_->Stop();
-}
+DeviceMonitorMac::~DeviceMonitorMac() {}
void DeviceMonitorMac::NotifyDeviceChanged(
base::SystemMonitor::DeviceType type) {
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698