| 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) {
|
|
|