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

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

Powered by Google App Engine
This is Rietveld 408576698