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

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: Added comments following avi@ ones. Created 7 years, 1 month 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
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 kUnknown
22 };
23
24 DeviceInfo(std::string unique_id, DeviceType type)
25 : unique_id_(unique_id), type_(type) {}
26
27 // Operator== is needed here to use this class in a std::find. A given
28 // |unique_id_| always has the same |type_| so for comparison purposes the
29 // latter can be safely ignored.
30 bool operator==(const DeviceInfo& device) const {
31 return unique_id_ == device.unique_id_;
32 }
33
34 const std::string& unique_id() const { return unique_id_; }
35 DeviceType type() const { return type_; }
20 36
21 private: 37 private:
22 void OnDeviceChanged(); 38 std::string unique_id_;
23 39 DeviceType type_;
24 DeviceMonitorMac* monitor_; 40 // Allow generated copy constructor and assignment.
25 int number_audio_devices_; 41 };
26 int number_video_devices_; 42
43 // Base abstract class used by DeviceMonitorMac to interact with either a QTKit
44 // or an AVFoundation implementation of events and notifications.
45 class DeviceMonitorMacImpl {
46 public:
47 explicit DeviceMonitorMacImpl(content::DeviceMonitorMac* monitor)
48 : monitor_(monitor),
49 cached_devices_(),
50 device_arrival_(nil),
51 device_removal_(nil) {
52 DCHECK(monitor);
53 }
54 virtual ~DeviceMonitorMacImpl() {}
55
56 virtual void OnDeviceChanged() = 0;
57
58 // Method called by the default notification center when a device is removed
59 // or added to the system. It will compare the |cached_devices_| with the
60 // current situation, update it, and, if there's an update, signal to
61 // |monitor_| with the appropriate device type.
62 void ConsolidateDevicesListAndNotify(
63 const std::vector<DeviceInfo>& snapshot_devices);
64
65 protected:
66 content::DeviceMonitorMac* monitor_;
67 std::vector<DeviceInfo> cached_devices_;
68
69 // Handles to NSNotificationCenter block observers.
27 id device_arrival_; 70 id device_arrival_;
28 id device_removal_; 71 id device_removal_;
29 72
30 DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl); 73 private:
31 }; 74 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl);
32 75 };
33 DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor) 76
34 : monitor_(monitor), 77 void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
35 number_audio_devices_(0), 78 const std::vector<DeviceInfo>& snapshot_devices) {
36 number_video_devices_(0), 79 bool video_device_added = false;
37 device_arrival_(nil), 80 bool audio_device_added = false;
38 device_removal_(nil) { 81 bool video_device_removed = false;
39 DCHECK(monitor); 82 bool audio_device_removed = false;
40 } 83
41 84 // Compare the current system devices snapshot with the ones cached to detect
42 void DeviceMonitorMac::QTMonitorImpl::Start() { 85 // additions, present in the former but not in the latter. If we find a device
86 // in snapshot_devices entry also present in cached_devices, we remove it from
87 // the latter vector.
88 std::vector<DeviceInfo>::const_iterator it;
89 for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
90 std::vector<DeviceInfo>::iterator cached_devices_iterator =
91 std::find(cached_devices_.begin(), cached_devices_.end(), *it);
92 if (cached_devices_iterator == cached_devices_.end()) {
93 video_device_added |= ((it->type() == DeviceInfo::kVideo) ||
94 (it->type() == DeviceInfo::kMuxed));
95 audio_device_added |= ((it->type() == DeviceInfo::kAudio) ||
96 (it->type() == DeviceInfo::kMuxed));
97 DVLOG(1) << "Device has been added, id: " << it->unique_id();
98 } else {
99 cached_devices_.erase(cached_devices_iterator);
100 }
101 }
102 // All the remaining entries in cached_devices are removed devices.
103 for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
104 video_device_removed |= ((it->type() == DeviceInfo::kVideo) ||
105 (it->type() == DeviceInfo::kMuxed));
106 audio_device_removed |= ((it->type() == DeviceInfo::kAudio) ||
107 (it->type() == DeviceInfo::kMuxed));
108 DVLOG(1) << "Device has been removed, id: " << it->unique_id();
109 }
110 // Update the cached devices with the current system snapshot.
111 cached_devices_ = snapshot_devices;
112
113 if (video_device_added || video_device_removed)
114 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
115 if (audio_device_added || video_device_removed)
116 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
117 }
118
119 class QTKitMonitorImpl : public DeviceMonitorMacImpl {
120 public:
121 explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
122 virtual ~QTKitMonitorImpl();
123
124 virtual void OnDeviceChanged() OVERRIDE;
125 };
126
127 QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
128 : DeviceMonitorMacImpl(monitor) {
43 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 129 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
44 device_arrival_ = 130 device_arrival_ =
45 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification 131 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
46 object:nil 132 object:nil
47 queue:nil 133 queue:nil
48 usingBlock:^(NSNotification* notification) { 134 usingBlock:^(NSNotification* notification) {
49 OnDeviceChanged();}]; 135 OnDeviceChanged();
136 }];
50 137
51 device_removal_ = 138 device_removal_ =
52 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification 139 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
53 object:nil 140 object:nil
54 queue:nil 141 queue:nil
55 usingBlock:^(NSNotification* notification) { 142 usingBlock:^(NSNotification* notification) {
56 OnDeviceChanged();}]; 143 OnDeviceChanged();
57 } 144 }];
58 145 }
59 void DeviceMonitorMac::QTMonitorImpl::Stop() { 146
60 if (!monitor_) 147 QTKitMonitorImpl::~QTKitMonitorImpl() {
61 return;
62
63 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 148 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
64 [nc removeObserver:device_arrival_]; 149 [nc removeObserver:device_arrival_];
65 [nc removeObserver:device_removal_]; 150 [nc removeObserver:device_removal_];
66 } 151 }
67 152
68 void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() { 153 void QTKitMonitorImpl::OnDeviceChanged() {
154 std::vector<DeviceInfo> snapshot_devices;
155
69 NSArray* devices = [QTCaptureDevice inputDevices]; 156 NSArray* devices = [QTCaptureDevice inputDevices];
70 int number_video_devices = 0;
71 int number_audio_devices = 0;
72 for (QTCaptureDevice* device in devices) { 157 for (QTCaptureDevice* device in devices) {
73 if ([device hasMediaType:QTMediaTypeVideo] || 158 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
74 [device hasMediaType:QTMediaTypeMuxed]) 159 if ([device hasMediaType:QTMediaTypeVideo])
75 ++number_video_devices; 160 device_type = DeviceInfo::kVideo;
76 161 else if ([device hasMediaType:QTMediaTypeMuxed])
77 if ([device hasMediaType:QTMediaTypeSound] || 162 device_type = DeviceInfo::kMuxed;
78 [device hasMediaType:QTMediaTypeMuxed]) 163 else if ([device hasMediaType:QTMediaTypeSound])
79 ++number_audio_devices; 164 device_type = DeviceInfo::kAudio;
80 } 165
81 166 snapshot_devices.push_back(
82 if (number_video_devices_ != number_video_devices) { 167 DeviceInfo([[device uniqueID] UTF8String], device_type));
83 number_video_devices_ = number_video_devices; 168 }
84 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); 169
85 } 170 ConsolidateDevicesListAndNotify(snapshot_devices);
86 171 }
87 if (number_audio_devices_ != number_audio_devices) { 172
88 number_audio_devices_ = number_audio_devices; 173 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
89 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); 174 public:
90 } 175 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
91 } 176 virtual ~AVFoundationMonitorImpl();
177
178 virtual void OnDeviceChanged() OVERRIDE;
179 };
180
181 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
182 content::DeviceMonitorMac* monitor)
183 : DeviceMonitorMacImpl(monitor) {
184 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
185
186 device_arrival_ =
187 [nc addObserverForName:AVFoundationGlue::
188 AVCaptureDeviceWasConnectedNotification()
189 object:nil
190 queue:nil
191 usingBlock:^(NSNotification* notification) {
192 OnDeviceChanged();
193 }];
194 device_removal_ =
195 [nc addObserverForName:AVFoundationGlue::
196 AVCaptureDeviceWasDisconnectedNotification()
197 object:nil
198 queue:nil
199 usingBlock:^(NSNotification* notification) {
200 OnDeviceChanged();
201 }];
202 }
203
204 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
205 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
206 [nc removeObserver:device_arrival_];
207 [nc removeObserver:device_removal_];
208 }
209
210 void AVFoundationMonitorImpl::OnDeviceChanged() {
211 std::vector<DeviceInfo> snapshot_devices;
212
213 NSArray* devices = [AVCaptureDeviceGlue devices];
214 for (CrAVCaptureDevice* device in devices) {
215 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
216 if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::AVMediaTypeVideo()
217 forCaptureDevice:device]) {
218 device_type = DeviceInfo::kVideo;
219 } else if ([AVCaptureDeviceGlue
220 hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()
221 forCaptureDevice:device]) {
222 device_type = DeviceInfo::kMuxed;
223 } else if ([AVCaptureDeviceGlue
224 hasMediaType:AVFoundationGlue::AVMediaTypeAudio()
225 forCaptureDevice:device]) {
226 device_type = DeviceInfo::kAudio;
227 }
228 snapshot_devices.push_back(DeviceInfo(
229 [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_type));
230 }
231
232 ConsolidateDevicesListAndNotify(snapshot_devices);
233 }
234
235 } // namespace
236
237 namespace content {
92 238
93 DeviceMonitorMac::DeviceMonitorMac() { 239 DeviceMonitorMac::DeviceMonitorMac() {
94 qt_monitor_.reset(new QTMonitorImpl(this)); 240 if (AVFoundationGlue::IsAVFoundationSupported()) {
95 qt_monitor_->Start(); 241 DVLOG(1) << "Monitoring via AVFoundation";
96 } 242 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this));
97 243 } else {
98 DeviceMonitorMac::~DeviceMonitorMac() { 244 DVLOG(1) << "Monitoring via QTKit";
99 qt_monitor_->Stop(); 245 device_monitor_impl_.reset(new QTKitMonitorImpl(this));
100 } 246 }
247 // Force device enumeration to correctly list those already in the system.
248 device_monitor_impl_->OnDeviceChanged();
249 }
250
251 DeviceMonitorMac::~DeviceMonitorMac() {}
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
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698