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

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: mark@'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"
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 {
Robert Sesek 2013/10/14 17:26:44 If you're going to have public members, this needs
mcasas 2013/10/15 11:50:11 I changed them to private and provided getters/acc
16
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 }
23 31
24 DeviceMonitorMac* monitor_; 32 std::string unique_id_;
25 int number_audio_devices_; 33 DeviceType type_;
26 int number_video_devices_; 34 // Allow generated copy constructor and assignment.
35 };
36
37 // Base class used by DeviceMonitorMac to interact with either a QTKit or an
38 // AVFoundation implementation of events and notifications. This class should
39 // never be instantiated on its own.
40 class MacMonitor {
41 public:
42 MacMonitor() {}
43 explicit MacMonitor(content::DeviceMonitorMac* monitor)
44 : monitor_(monitor),
45 cached_devices_(),
46 device_arrival_(nil),
47 device_removal_(nil) {}
48 virtual ~MacMonitor() {}
49
50 virtual void OnDeviceChanged() = 0;
51 void ConsolidateDevicesListAndNotify(
52 std::vector<DeviceInfo> snapshot_devices);
53
54 protected:
55 content::DeviceMonitorMac* monitor_;
56 std::vector<DeviceInfo> cached_devices_;
27 id device_arrival_; 57 id device_arrival_;
28 id device_removal_; 58 id device_removal_;
29 59 DISALLOW_COPY_AND_ASSIGN(MacMonitor);
30 DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl);
31 }; 60 };
32 61
33 DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor) 62 void MacMonitor::ConsolidateDevicesListAndNotify(
34 : monitor_(monitor), 63 std::vector<DeviceInfo> snapshot_devices) {
35 number_audio_devices_(0), 64 int video_device_added = 0;
Robert Sesek 2013/10/14 17:26:44 Why are these ints? It seems like you're just usin
mcasas 2013/10/15 11:50:11 Since several devices might have been plugged in/o
Robert Sesek 2013/10/15 20:44:46 What about bool and |= ? This isn't really a quest
mcasas 2013/10/16 11:04:40 Done. Boolean it is.
36 number_video_devices_(0), 65 int audio_device_added = 0;
37 device_arrival_(nil), 66 int video_device_removed = 0;
38 device_removal_(nil) { 67 int audio_device_removed = 0;
39 DCHECK(monitor); 68
69 // Compare the current system devices snapshot with the ones cached to detect
70 // additions, present in the former but not in the latter. If we find a device
71 // in snapshot_devices entry also present in cached_devices, we remove it from
72 // the latter vector.
73 std::vector<DeviceInfo>::iterator it;
74 for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
75 std::vector<DeviceInfo>::iterator cached_devices_iterator =
76 std::find(cached_devices_.begin(), cached_devices_.end(), *it);
77 if (cached_devices_iterator == cached_devices_.end()) {
78 video_device_added += ((it->type_ == DeviceInfo::kVideo) ||
79 (it->type_ == DeviceInfo::kMuxed));
80 audio_device_added += ((it->type_ == DeviceInfo::kAudio) ||
81 (it->type_ == DeviceInfo::kMuxed));
82 DVLOG(1) << "Device has been added, id: " << it->unique_id_;
83 } else {
84 cached_devices_.erase(cached_devices_iterator);
85 }
86 }
87 // All the remaining entries in cached_devices are removed devices.
88 for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
89 video_device_removed += ((it->type_ == DeviceInfo::kVideo) ||
90 (it->type_ == DeviceInfo::kMuxed));
91 audio_device_removed += ((it->type_ == DeviceInfo::kAudio) ||
92 (it->type_ == DeviceInfo::kMuxed));
93 DVLOG(1) << "Device has been removed, id: " << it->unique_id_;
94 }
95 // Update the cached devices with the current system snapshot.
96 cached_devices_.swap(snapshot_devices);
97
98 if (video_device_added || video_device_removed)
99 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
100 if (audio_device_added || video_device_removed)
101 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
40 } 102 }
41 103
42 void DeviceMonitorMac::QTMonitorImpl::Start() { 104 class QTKitMonitorImpl : public MacMonitor {
105 public:
106 QTKitMonitorImpl() {}
Robert Sesek 2013/10/14 17:26:44 Why do you need to provide this constructor?
mcasas 2013/10/15 11:50:11 No need - removed and also AVFoundationMonitorImpl
107 explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
108 virtual ~QTKitMonitorImpl();
109
110 virtual void OnDeviceChanged() OVERRIDE;
111 };
112
113 QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor) {
114 DCHECK(monitor);
Robert Sesek 2013/10/14 17:26:44 You DCHECK this but it is unused?
mcasas 2013/10/15 11:50:11 Moved it to the MacMonitor parent class constructo
115
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();
Robert Sesek 2013/10/14 17:26:44 These blocks are not formatted correctly. The cont
mcasas 2013/10/15 11:50:11 Done.
Robert Sesek 2013/10/15 20:44:46 Not quite. Look at the fourth and fifth examples.
mcasas 2013/10/16 11:04:40 I hope I got it right this time :) Interestingly,
Robert Sesek 2013/10/16 23:58:07 Yes, is good now. I don't think a Mac person revie
123 }];
50 124
51 device_removal_ = 125 device_removal_ =
52 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification 126 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
53 object:nil 127 object:nil
54 queue:nil 128 queue:nil
55 usingBlock:^(NSNotification* notification) { 129 usingBlock:^(NSNotification* notification) {
56 OnDeviceChanged();}]; 130 OnDeviceChanged();
131 }];
57 } 132 }
58 133
59 void DeviceMonitorMac::QTMonitorImpl::Stop() { 134 QTKitMonitorImpl::~QTKitMonitorImpl() {
60 if (!monitor_) 135 if (!monitor_)
Robert Sesek 2013/10/14 17:26:44 Couldn't this leave dangling observers? You do not
mcasas 2013/10/15 11:50:11 Most likely. RIght now I don't see why a not initi
61 return; 136 return;
62 137
63 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 138 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
64 [nc removeObserver:device_arrival_]; 139 [nc removeObserver:device_arrival_];
65 [nc removeObserver:device_removal_]; 140 [nc removeObserver:device_removal_];
66 } 141 }
67 142
68 void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() { 143 void QTKitMonitorImpl::OnDeviceChanged() {
144 std::vector<DeviceInfo> snapshot_devices;
145 DeviceInfo::DeviceType device_info;
146
69 NSArray* devices = [QTCaptureDevice inputDevices]; 147 NSArray* devices = [QTCaptureDevice inputDevices];
70 int number_video_devices = 0;
71 int number_audio_devices = 0;
72 for (QTCaptureDevice* device in devices) { 148 for (QTCaptureDevice* device in devices) {
73 if ([device hasMediaType:QTMediaTypeVideo] || 149 if ([device hasMediaType:QTMediaTypeVideo])
74 [device hasMediaType:QTMediaTypeMuxed]) 150 device_info = DeviceInfo::kVideo;
75 ++number_video_devices; 151 else if ([device hasMediaType:QTMediaTypeMuxed])
152 device_info = DeviceInfo::kMuxed;
153 else if ([device hasMediaType:QTMediaTypeSound])
154 device_info = DeviceInfo::kAudio;
76 155
77 if ([device hasMediaType:QTMediaTypeSound] || 156 snapshot_devices.push_back(
78 [device hasMediaType:QTMediaTypeMuxed]) 157 DeviceInfo([[device uniqueID] UTF8String], device_info));
79 ++number_audio_devices;
80 } 158 }
81 159
82 if (number_video_devices_ != number_video_devices) { 160 ConsolidateDevicesListAndNotify(snapshot_devices);
83 number_video_devices_ = number_video_devices; 161 }
84 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); 162
163 class AVFoundationMonitorImpl : public MacMonitor {
164 public:
165 AVFoundationMonitorImpl() {}
166 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
167 virtual ~AVFoundationMonitorImpl();
168
169 virtual void OnDeviceChanged() OVERRIDE;
170 };
171
172 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
173 content::DeviceMonitorMac* monitor) {
174 DCHECK(monitor);
175
176 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
177 NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
Robert Sesek 2013/10/14 17:26:44 naming: main_queue
mcasas 2013/10/15 11:50:11 Done.
178
179 device_arrival_ =
180 [nc addObserverForName:AVFoundationGlue::
181 avCaptureDeviceWasConnectedNotification()
182 object:nil
183 queue:mainQueue
184 usingBlock:^(NSNotification* notification) {
185 OnDeviceChanged();
186 }];
187 DCHECK(device_arrival_);
188 device_removal_ =
189 [nc addObserverForName:AVFoundationGlue::
190 avCaptureDeviceWasDisconnectedNotification()
191 object:nil
192 queue:mainQueue
193 usingBlock:^(NSNotification* notification) {
194 OnDeviceChanged();
195 }];
196 DCHECK(device_removal_);
197 }
198
199 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
200 if (!monitor_)
201 return;
202
203 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
204 [nc removeObserver:device_arrival_];
205 [nc removeObserver:device_removal_];
206 }
207
208 void AVFoundationMonitorImpl::OnDeviceChanged() {
209 std::vector<DeviceInfo> snapshot_devices;
210 DeviceInfo::DeviceType device_info;
211
212 NSArray* devices = [AVCaptureDeviceGlue devices];
213 for (CrAVCaptureDevice* device in devices) {
214 if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::avMediaTypeVideo()
215 forCaptureDevice:device]) {
216 device_info = DeviceInfo::kVideo;
217 } else if ([AVCaptureDeviceGlue
218 hasMediaType:AVFoundationGlue::avMediaTypeMuxed()
219 forCaptureDevice:device]) {
220 device_info = DeviceInfo::kMuxed;
221 } else if ([AVCaptureDeviceGlue
222 hasMediaType:AVFoundationGlue::avMediaTypeAudio()
223 forCaptureDevice:device]) {
224 device_info = DeviceInfo::kAudio;
225 }
226 snapshot_devices.push_back(DeviceInfo(
227 [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_info));
85 } 228 }
86 229
87 if (number_audio_devices_ != number_audio_devices) { 230 ConsolidateDevicesListAndNotify(snapshot_devices);
88 number_audio_devices_ = number_audio_devices; 231 }
89 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); 232
233 } // namespace
234
235 namespace content {
236
237 DeviceMonitorMac::DeviceMonitorMac() {
238 if (AVFoundationGlue::isAVFoundationSupported()) {
239 DVLOG(1) << "Monitoring via AVFoundation";
240 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this));
241 // Force the device enumeration so we enumerate correctly devices already in
242 // the system and at the same time use the AVCaptureDeviceGlue so it in
243 // turn forces the AVCaptureDeviceGlue alloc-init.
244 device_monitor_impl_->OnDeviceChanged();
245 } else {
246 DVLOG(1) << "Monitoring via QTKit";
247 device_monitor_impl_.reset(new QTKitMonitorImpl(this));
90 } 248 }
91 } 249 }
92 250
93 DeviceMonitorMac::DeviceMonitorMac() { 251 DeviceMonitorMac::~DeviceMonitorMac() {}
94 qt_monitor_.reset(new QTMonitorImpl(this));
95 qt_monitor_->Start();
96 }
97
98 DeviceMonitorMac::~DeviceMonitorMac() {
99 qt_monitor_->Stop();
100 }
101 252
102 void DeviceMonitorMac::NotifyDeviceChanged( 253 void DeviceMonitorMac::NotifyDeviceChanged(
103 base::SystemMonitor::DeviceType type) { 254 base::SystemMonitor::DeviceType type) {
104 // TODO(xians): Remove the global variable for SystemMonitor. 255 // TODO(xians): Remove the global variable for SystemMonitor.
105 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 256 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
106 } 257 }
107 258
108 } // namespace content 259 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698