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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/device_monitor_mac.h" 5 #include "content/browser/device_monitor_mac.h"
6 6
7 #import <QTKit/QTKit.h> 7 #import <QTKit/QTKit.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #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.
10 11
11 namespace content { 12 namespace {
12 13
13 class DeviceMonitorMac::QTMonitorImpl { 14 // This class is used to keep track of system devices names and their types.
15 class DeviceInfo {
16
Robert Sesek 2013/10/15 20:44:46 nit: remove
mcasas 2013/10/16 11:04:40 Done.
14 public: 17 public:
15 explicit QTMonitorImpl(DeviceMonitorMac* monitor); 18 enum DeviceType {
16 virtual ~QTMonitorImpl() {} 19 kAudio,
20 kVideo,
21 kMuxed
22 };
17 23
18 void Start(); 24 DeviceInfo(std::string unique_id, DeviceType type)
19 void Stop(); 25 : unique_id_(unique_id), type_(type) {}
20 26
21 private: 27 // Operator== is needed here to use this class in a std::vector.
22 void OnDeviceChanged(); 28 bool operator==(const DeviceInfo& device) const {
29 return unique_id_ == device.unique_id_;
30 }
Robert Sesek 2013/10/15 20:44:46 nit: blank line after
mcasas 2013/10/16 11:04:40 Done.
31 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.
32 DeviceType type() const { return type_; }
23 33
24 DeviceMonitorMac* monitor_; 34 private:
Robert Sesek 2013/10/15 20:44:46 nit: 1 space indent
mcasas 2013/10/16 11:04:40 Done.
25 int number_audio_devices_; 35 std::string unique_id_;
26 int number_video_devices_; 36 DeviceType type_;
37 // Allow generated copy constructor and assignment.
38 };
39
40 // Base class used by DeviceMonitorMac to interact with either a QTKit or an
41 // AVFoundation implementation of events and notifications. This class should
42 // never be instantiated on its own.
43 class MacMonitor {
44 public:
45 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
46 explicit MacMonitor(content::DeviceMonitorMac* monitor)
47 : monitor_(monitor),
48 cached_devices_(),
49 device_arrival_(nil),
50 device_removal_(nil) { DCHECK(monitor); }
51 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.
52
53 virtual void OnDeviceChanged() = 0;
54 void ConsolidateDevicesListAndNotify(
Robert Sesek 2013/10/15 20:44:46 Comments needed.
mcasas 2013/10/16 11:04:40 Done.
55 std::vector<DeviceInfo> snapshot_devices);
56
57 protected:
58 content::DeviceMonitorMac* monitor_;
59 std::vector<DeviceInfo> cached_devices_;
27 id device_arrival_; 60 id device_arrival_;
28 id device_removal_; 61 id device_removal_;
29 62 DISALLOW_COPY_AND_ASSIGN(MacMonitor);
30 DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl);
31 }; 63 };
32 64
33 DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor) 65 void MacMonitor::ConsolidateDevicesListAndNotify(
34 : monitor_(monitor), 66 std::vector<DeviceInfo> snapshot_devices) {
35 number_audio_devices_(0), 67 int video_device_added = 0;
36 number_video_devices_(0), 68 int audio_device_added = 0;
37 device_arrival_(nil), 69 int video_device_removed = 0;
38 device_removal_(nil) { 70 int audio_device_removed = 0;
39 DCHECK(monitor); 71
72 // Compare the current system devices snapshot with the ones cached to detect
73 // additions, present in the former but not in the latter. If we find a device
74 // in snapshot_devices entry also present in cached_devices, we remove it from
75 // the latter vector.
76 std::vector<DeviceInfo>::iterator it;
77 for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
78 std::vector<DeviceInfo>::iterator cached_devices_iterator =
79 std::find(cached_devices_.begin(), cached_devices_.end(), *it);
80 if (cached_devices_iterator == cached_devices_.end()) {
81 video_device_added += ((it->type() == DeviceInfo::kVideo) ||
82 (it->type() == DeviceInfo::kMuxed));
83 audio_device_added += ((it->type() == DeviceInfo::kAudio) ||
84 (it->type() == DeviceInfo::kMuxed));
85 DVLOG(1) << "Device has been added, id: " << it->unique_id();
86 } else {
87 cached_devices_.erase(cached_devices_iterator);
88 }
89 }
90 // All the remaining entries in cached_devices are removed devices.
91 for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
92 video_device_removed += ((it->type() == DeviceInfo::kVideo) ||
93 (it->type() == DeviceInfo::kMuxed));
94 audio_device_removed += ((it->type() == DeviceInfo::kAudio) ||
95 (it->type() == DeviceInfo::kMuxed));
96 DVLOG(1) << "Device has been removed, id: " << it->unique_id();
97 }
98 // Update the cached devices with the current system snapshot.
99 cached_devices_.swap(snapshot_devices);
100
101 if (video_device_added || video_device_removed)
102 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
103 if (audio_device_added || video_device_removed)
104 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
40 } 105 }
41 106
42 void DeviceMonitorMac::QTMonitorImpl::Start() { 107 class QTKitMonitorImpl : public MacMonitor {
108 public:
109 explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
110 virtual ~QTKitMonitorImpl();
111
112 virtual void OnDeviceChanged() OVERRIDE;
113 };
114
115 QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor) {
43 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 116 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
44 device_arrival_ = 117 device_arrival_ =
45 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification 118 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
46 object:nil 119 object:nil
47 queue:nil 120 queue:nil
48 usingBlock:^(NSNotification* notification) { 121 usingBlock:^(NSNotification* notification) {
49 OnDeviceChanged();}]; 122 OnDeviceChanged();}];
50 123
51 device_removal_ = 124 device_removal_ =
52 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification 125 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
53 object:nil 126 object:nil
54 queue:nil 127 queue:nil
55 usingBlock:^(NSNotification* notification) { 128 usingBlock:^(NSNotification* notification) {
56 OnDeviceChanged();}]; 129 OnDeviceChanged();}];
57 } 130 }
58 131
59 void DeviceMonitorMac::QTMonitorImpl::Stop() { 132 QTKitMonitorImpl::~QTKitMonitorImpl() {
60 if (!monitor_)
61 return;
62
63 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 133 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
64 [nc removeObserver:device_arrival_]; 134 [nc removeObserver:device_arrival_];
65 [nc removeObserver:device_removal_]; 135 [nc removeObserver:device_removal_];
66 } 136 }
67 137
68 void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() { 138 void QTKitMonitorImpl::OnDeviceChanged() {
139 std::vector<DeviceInfo> snapshot_devices;
140 DeviceInfo::DeviceType device_info;
141
69 NSArray* devices = [QTCaptureDevice inputDevices]; 142 NSArray* devices = [QTCaptureDevice inputDevices];
70 int number_video_devices = 0;
71 int number_audio_devices = 0;
72 for (QTCaptureDevice* device in devices) { 143 for (QTCaptureDevice* device in devices) {
73 if ([device hasMediaType:QTMediaTypeVideo] || 144 if ([device hasMediaType:QTMediaTypeVideo])
74 [device hasMediaType:QTMediaTypeMuxed]) 145 device_info = DeviceInfo::kVideo;
75 ++number_video_devices; 146 else if ([device hasMediaType:QTMediaTypeMuxed])
147 device_info = DeviceInfo::kMuxed;
148 else if ([device hasMediaType:QTMediaTypeSound])
149 device_info = DeviceInfo::kAudio;
76 150
77 if ([device hasMediaType:QTMediaTypeSound] || 151 snapshot_devices.push_back(
78 [device hasMediaType:QTMediaTypeMuxed]) 152 DeviceInfo([[device uniqueID] UTF8String], device_info));
79 ++number_audio_devices;
80 } 153 }
81 154
82 if (number_video_devices_ != number_video_devices) { 155 ConsolidateDevicesListAndNotify(snapshot_devices);
83 number_video_devices_ = number_video_devices; 156 }
84 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); 157
158 class AVFoundationMonitorImpl : public MacMonitor {
159 public:
160 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
161 virtual ~AVFoundationMonitorImpl();
162
163 virtual void OnDeviceChanged() OVERRIDE;
164 };
165
166 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
167 content::DeviceMonitorMac* monitor) {
168 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
169 NSOperationQueue* main_queue = [NSOperationQueue mainQueue];
170
171 device_arrival_ =
172 [nc addObserverForName:AVFoundationGlue::
173 AvCaptureDeviceWasConnectedNotification()
174 object:nil
175 queue:main_queue
176 usingBlock:^(NSNotification* notification) {
177 OnDeviceChanged();}];
178 DCHECK(device_arrival_);
179 device_removal_ =
Robert Sesek 2013/10/15 20:44:46 nit: check indention after ths line
mcasas 2013/10/16 11:04:40 Done.
180 [nc addObserverForName:AVFoundationGlue::
181 AvCaptureDeviceWasDisconnectedNotification()
182 object:nil
183 queue:main_queue
184 usingBlock:^(NSNotification* notification) {
185 OnDeviceChanged();}];
186 DCHECK(device_removal_);
187 }
188
189 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
190 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
191 [nc removeObserver:device_arrival_];
192 [nc removeObserver:device_removal_];
193 }
194
195 void AVFoundationMonitorImpl::OnDeviceChanged() {
196 std::vector<DeviceInfo> snapshot_devices;
197 DeviceInfo::DeviceType device_info;
198
199 NSArray* devices = [AVCaptureDeviceGlue devices];
200 for (CrAVCaptureDevice* device in devices) {
201 if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::AvMediaTypeVideo()
202 forCaptureDevice:device]) {
203 device_info = DeviceInfo::kVideo;
204 } else if ([AVCaptureDeviceGlue
205 hasMediaType:AVFoundationGlue::AvMediaTypeMuxed()
206 forCaptureDevice:device]) {
207 device_info = DeviceInfo::kMuxed;
208 } else if ([AVCaptureDeviceGlue
209 hasMediaType:AVFoundationGlue::AvMediaTypeAudio()
210 forCaptureDevice:device]) {
211 device_info = DeviceInfo::kAudio;
212 }
213 snapshot_devices.push_back(DeviceInfo(
214 [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_info));
85 } 215 }
86 216
87 if (number_audio_devices_ != number_audio_devices) { 217 ConsolidateDevicesListAndNotify(snapshot_devices);
88 number_audio_devices_ = number_audio_devices; 218 }
89 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); 219
220 } // namespace
221
222 namespace content {
223
224 DeviceMonitorMac::DeviceMonitorMac() {
225 if (AVFoundationGlue::IsAVFoundationSupported()) {
226 DVLOG(1) << "Monitoring via AVFoundation";
227 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this));
228 // Force the device enumeration so we enumerate correctly devices already in
229 // the system and at the same time use the AVCaptureDeviceGlue so it in
230 // turn forces the AVCaptureDeviceGlue alloc-init.
231 device_monitor_impl_->OnDeviceChanged();
232 } else {
233 DVLOG(1) << "Monitoring via QTKit";
234 device_monitor_impl_.reset(new QTKitMonitorImpl(this));
90 } 235 }
91 } 236 }
92 237
93 DeviceMonitorMac::DeviceMonitorMac() { 238 DeviceMonitorMac::~DeviceMonitorMac() {}
94 qt_monitor_.reset(new QTMonitorImpl(this));
95 qt_monitor_->Start();
96 }
97
98 DeviceMonitorMac::~DeviceMonitorMac() {
99 qt_monitor_->Stop();
100 }
101 239
102 void DeviceMonitorMac::NotifyDeviceChanged( 240 void DeviceMonitorMac::NotifyDeviceChanged(
103 base::SystemMonitor::DeviceType type) { 241 base::SystemMonitor::DeviceType type) {
104 // TODO(xians): Remove the global variable for SystemMonitor. 242 // TODO(xians): Remove the global variable for SystemMonitor.
105 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 243 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
106 } 244 }
107 245
108 } // namespace content 246 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698