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

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: 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 "base/synchronization/lock.h"
11 #include "media/video/capture/mac/avfoundation_glue.h"
10 12
11 namespace content { 13 namespace {
12 14
13 class DeviceMonitorMac::QTMonitorImpl { 15 // Interface used by DeviceMonitorMac to interact with either a QTKit or an
16 // AVFoundation implementation of events and notifications.
17 class MacMonitorInterface {
14 public: 18 public:
15 explicit QTMonitorImpl(DeviceMonitorMac* monitor); 19 virtual ~MacMonitorInterface() {};
16 virtual ~QTMonitorImpl() {}
17 20
18 void Start(); 21 virtual void OnDeviceChanged() = 0;
19 void Stop(); 22 };
20 23
24 // This class is used to keep track of system devices names and their types.
25 class DeviceInfo{
Mark Mentovai 2013/10/09 16:05:12 Fix the formatting of this class to match the styl
mcasas 2013/10/12 09:59:27 Done.
26 public:
27 enum DeviceType{
28 audio,
29 video
30 };
31
32 DeviceInfo(std::string the_uniqueID, DeviceType the_type):
33 uniqueID(the_uniqueID), type(the_type) {};
34
35 bool operator==(const DeviceInfo& device) const {
36 return uniqueID == device.uniqueID;
37 }
38
39 std::string uniqueID;
40 DeviceType type;
Mark Mentovai 2013/10/09 16:05:12 Maybe this can be a bit mask, so that you can stuf
mcasas 2013/10/12 09:59:27 Instead of that I added a new category "kMuxed" an
41 // Allow generated copy constructor and assignment.
42 };
43
44 class QTKitMonitorImpl : public MacMonitorInterface {
45 public:
46 QTKitMonitorImpl() {};
47 explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
48 virtual ~QTKitMonitorImpl();
49
50 virtual void OnDeviceChanged() OVERRIDE;
21 private: 51 private:
22 void OnDeviceChanged(); 52 content::DeviceMonitorMac* monitor_;
23 53 std::vector<DeviceInfo> cached_devices;
Mark Mentovai 2013/10/09 16:05:12 Naming: members have trailing underscores.
mcasas 2013/10/12 09:59:27 Done.
24 DeviceMonitorMac* monitor_;
25 int number_audio_devices_;
26 int number_video_devices_;
27 id device_arrival_; 54 id device_arrival_;
28 id device_removal_; 55 id device_removal_;
29
30 DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl);
31 }; 56 };
32 57
33 DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor) 58 QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
34 : monitor_(monitor), 59 : monitor_(monitor),
35 number_audio_devices_(0), 60 cached_devices(),
36 number_video_devices_(0),
37 device_arrival_(nil), 61 device_arrival_(nil),
38 device_removal_(nil) { 62 device_removal_(nil) {
39 DCHECK(monitor); 63 DCHECK(monitor);
40 }
41 64
42 void DeviceMonitorMac::QTMonitorImpl::Start() {
43 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 65 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
44 device_arrival_ = 66 device_arrival_ =
45 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification 67 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
46 object:nil 68 object:nil
47 queue:nil 69 queue:nil
48 usingBlock:^(NSNotification* notification) { 70 usingBlock:^(NSNotification* notification) {
49 OnDeviceChanged();}]; 71 OnDeviceChanged();}];
50 72
51 device_removal_ = 73 device_removal_ =
52 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification 74 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
53 object:nil 75 object:nil
54 queue:nil 76 queue:nil
55 usingBlock:^(NSNotification* notification) { 77 usingBlock:^(NSNotification* notification) {
56 OnDeviceChanged();}]; 78 OnDeviceChanged();}];
57 } 79 }
58 80
59 void DeviceMonitorMac::QTMonitorImpl::Stop() { 81 QTKitMonitorImpl::~QTKitMonitorImpl() {
60 if (!monitor_) 82 if (!monitor_)
61 return; 83 return;
62 84
63 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 85 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
64 [nc removeObserver:device_arrival_]; 86 [nc removeObserver:device_arrival_];
65 [nc removeObserver:device_removal_]; 87 [nc removeObserver:device_removal_];
66 } 88 }
67 89
68 void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() { 90 void QTKitMonitorImpl::OnDeviceChanged() {
91 base::AutoLock lock(monitor_->lock_);
92 int video_device_added = 0;
93 int audio_device_added = 0;
94 int video_device_removed = 0;
95 int audio_device_removed = 0;
96
97 std::vector<DeviceInfo> snapshot_devices;
Mark Mentovai 2013/10/09 16:05:12 Maybe snapshot_devices and cached_devices would be
mcasas 2013/10/12 09:59:27 I think that would make sense if we would like to
Robert Sesek 2013/10/14 17:26:44 Side node: unless the order is explicitly guarante
98
69 NSArray* devices = [QTCaptureDevice inputDevices]; 99 NSArray* devices = [QTCaptureDevice inputDevices];
70 int number_video_devices = 0;
71 int number_audio_devices = 0;
72 for (QTCaptureDevice* device in devices) { 100 for (QTCaptureDevice* device in devices) {
73 if ([device hasMediaType:QTMediaTypeVideo] || 101 if ([device hasMediaType:QTMediaTypeVideo] ||
74 [device hasMediaType:QTMediaTypeMuxed]) 102 [device hasMediaType:QTMediaTypeMuxed]) {
75 ++number_video_devices; 103 snapshot_devices.push_back(DeviceInfo(
76 104 [[device uniqueID] UTF8String], DeviceInfo::video));
105 }
77 if ([device hasMediaType:QTMediaTypeSound] || 106 if ([device hasMediaType:QTMediaTypeSound] ||
78 [device hasMediaType:QTMediaTypeMuxed]) 107 [device hasMediaType:QTMediaTypeMuxed]) {
79 ++number_audio_devices; 108 snapshot_devices.push_back(DeviceInfo(
109 [[device uniqueID] UTF8String], DeviceInfo::audio));
110 }
80 } 111 }
81 112
82 if (number_video_devices_ != number_video_devices) { 113 std::vector<DeviceInfo>::iterator it;
83 number_video_devices_ = number_video_devices; 114 for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
84 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); 115 if (std::find(cached_devices.begin(), cached_devices.end(), *it)
116 == cached_devices.end()) {
117 video_device_added += (it->type == DeviceInfo::video);
118 audio_device_added += (it->type == DeviceInfo::audio);
119 DVLOG(1) << "Device has been added id: " << it->uniqueID;
120 }
Mark Mentovai 2013/10/09 16:05:12 If cached_devices isn’t going to be used on any ot
mcasas 2013/10/12 09:59:27 Done.
85 } 121 }
86 122
87 if (number_audio_devices_ != number_audio_devices) { 123 for (it = cached_devices.begin(); it != cached_devices.end(); ++it) {
88 number_audio_devices_ = number_audio_devices; 124 if (std::find(snapshot_devices.begin(), snapshot_devices.end(), *it)
125 == snapshot_devices.end()) {
126 video_device_removed += (it->type == DeviceInfo::video);
127 audio_device_removed += (it->type == DeviceInfo::audio);
128 DVLOG(1) << "Device has been removed id: " << it->uniqueID;
129 }
130 }
131
132 cached_devices.swap(snapshot_devices);
133
134 if (video_device_added || video_device_removed)
135 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
136 if (audio_device_added || video_device_removed)
89 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); 137 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
138 }
139
140 class AVFoundationMonitorImpl : public MacMonitorInterface {
141 public:
142 AVFoundationMonitorImpl() {};
143 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
144 virtual ~AVFoundationMonitorImpl();
145
146 virtual void OnDeviceChanged() OVERRIDE;
147 private:
148 content::DeviceMonitorMac* monitor_;
149 std::vector<DeviceInfo> cached_devices;
Mark Mentovai 2013/10/09 16:05:12 Similar comments apply in here.
mcasas 2013/10/12 09:59:27 Done.
150 id device_arrival_;
151 id device_removal_;
152 };
153
154 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
155 content::DeviceMonitorMac* monitor)
156 : monitor_(monitor),
157 cached_devices(),
158 device_arrival_(nil),
159 device_removal_(nil) {
160 DCHECK(monitor);
161
162 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
163 NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
164
165 device_arrival_ =
166 [nc addObserverForName:[AVFoundationGlue
167 avCaptureDeviceWasConnectedNotification]
168 object:nil
169 queue:mainQueue
170 usingBlock:^(NSNotification* notification) {
171 OnDeviceChanged();}];
172 DCHECK(device_arrival_);
173 device_removal_ =
174 [nc addObserverForName:[AVFoundationGlue
175 avCaptureDeviceWasDisconnectedNotification]
176 object:nil
177 queue:mainQueue
178 usingBlock:^(NSNotification* notification) {
179 OnDeviceChanged();}];
180 DCHECK(device_removal_);
181 }
182
183 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
184 if (!monitor_)
185 return;
186
187 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
188 [nc removeObserver:device_arrival_];
189 [nc removeObserver:device_removal_];
190 }
191
192 void AVFoundationMonitorImpl::OnDeviceChanged() {
193 base::AutoLock lock(monitor_->lock_);
194 int video_device_added = 0;
195 int audio_device_added = 0;
196 int video_device_removed = 0;
197 int audio_device_removed = 0;
198
199 std::vector<DeviceInfo> snapshot_devices;
200 NSArray* devices = [AVCaptureDeviceGlue devices];
201 for (CrAVCaptureDevice* device in devices) {
202 if ([AVCaptureDeviceGlue hasMediaType:[AVFoundationGlue avMediaTypeVideo]
203 forCaptureDevice:device] ||
204 [AVCaptureDeviceGlue hasMediaType:[AVFoundationGlue avMediaTypeMuxed]
205 forCaptureDevice:device]) {
206 snapshot_devices.push_back(DeviceInfo([[AVCaptureDeviceGlue
207 uniqueID:device] UTF8String], DeviceInfo::video));
208 }
209 if ([AVCaptureDeviceGlue hasMediaType:[AVFoundationGlue avMediaTypeAudio]
210 forCaptureDevice:device] ||
211 [AVCaptureDeviceGlue hasMediaType:[AVFoundationGlue avMediaTypeMuxed]
212 forCaptureDevice:device]) {
213 snapshot_devices.push_back(DeviceInfo([[AVCaptureDeviceGlue
214 uniqueID:device] UTF8String], DeviceInfo::audio));
215 }
216 }
217
218 // Compare the current system devices snapshot with the ones cached to detect
Mark Mentovai 2013/10/09 16:05:12 Looks like all, or almost all, of the rest of this
mcasas 2013/10/12 09:59:27 Done. Beefing the MacMonitorInterface actually mad
219 // additions, present in the former but not in the latter.
220 std::vector<DeviceInfo>::iterator it;
221 for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
222 if( std::find(cached_devices.begin(), cached_devices.end(), *it)
Mark Mentovai 2013/10/09 16:05:12 Spacing is interesting here and on line 233.
mcasas 2013/10/12 09:59:27 Done.
223 == cached_devices.end()) {
224 video_device_added += (it->type == DeviceInfo::video);
225 audio_device_added += (it->type == DeviceInfo::audio);
226 DVLOG(1) << "Device has been added id: " << it->uniqueID;
227 }
228 }
229
230 // Compare the cached devices snapshot with the current ones to detect missing
231 // devices. These will be present in the former but not in the latter.
232 for (it = cached_devices.begin(); it != cached_devices.end(); ++it) {
233 if( std::find(snapshot_devices.begin(), snapshot_devices.end(), *it)
234 == snapshot_devices.end()) {
235 video_device_removed += (it->type == DeviceInfo::video);
236 audio_device_removed += (it->type == DeviceInfo::audio);
237 DVLOG(1) << "Device has been removed id: " << it->uniqueID;
238 }
239 }
240 // Update the cached devices with the current system snapshot.
241 cached_devices.swap(snapshot_devices);
242
243 if (video_device_added || video_device_removed)
244 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
245 if (audio_device_added || video_device_removed)
246 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
247 }
248
249 } // namespace
250
251 namespace content {
252
253 DeviceMonitorMac::DeviceMonitorMac() {
254 if ([AVFoundationGlue isAVFoundationSupported]){
255 DVLOG(1) << "Monitoring via AVFoundation";
256 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this));
257 // Force the device enumeration so we enumerate correctly devices already in
258 // the system and at the same time use the AVCaptureDeviceGlue so it in
259 // turn forces the AVCaptureDeviceGlue alloc-init.
260 device_monitor_impl_->OnDeviceChanged();
261 } else {
262 DVLOG(1) << "Monitoring via QTKit";
263 device_monitor_impl_.reset(new QTKitMonitorImpl(this));
90 } 264 }
91 } 265 }
92 266
93 DeviceMonitorMac::DeviceMonitorMac() { 267 DeviceMonitorMac::~DeviceMonitorMac() {}
94 qt_monitor_.reset(new QTMonitorImpl(this));
95 qt_monitor_->Start();
96 }
97
98 DeviceMonitorMac::~DeviceMonitorMac() {
99 qt_monitor_->Stop();
100 }
101 268
102 void DeviceMonitorMac::NotifyDeviceChanged( 269 void DeviceMonitorMac::NotifyDeviceChanged(
103 base::SystemMonitor::DeviceType type) { 270 base::SystemMonitor::DeviceType type) {
104 // TODO(xians): Remove the global variable for SystemMonitor. 271 // TODO(xians): Remove the global variable for SystemMonitor.
105 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 272 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
106 } 273 }
107 274
108 } // namespace content 275 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698