OLD | NEW |
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 "media/capture/device_monitor_mac.h" | 5 #include "media/capture/device_monitor_mac.h" |
6 | 6 |
7 #import <QTKit/QTKit.h> | |
8 | |
9 #include <set> | 7 #include <set> |
10 | 8 |
11 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
12 #include "base/logging.h" | 10 #include "base/logging.h" |
13 #include "base/mac/bind_objc_block.h" | 11 #include "base/mac/bind_objc_block.h" |
14 #include "base/mac/scoped_nsobject.h" | 12 #include "base/mac/scoped_nsobject.h" |
15 #include "base/macros.h" | 13 #include "base/macros.h" |
16 #include "base/profiler/scoped_tracker.h" | 14 #include "base/profiler/scoped_tracker.h" |
17 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
18 #include "base/threading/thread_checker.h" | 16 #include "base/threading/thread_checker.h" |
(...skipping 18 matching lines...) Expand all Loading... |
37 | 35 |
38 const std::string& unique_id() const { return unique_id_; } | 36 const std::string& unique_id() const { return unique_id_; } |
39 DeviceType type() const { return type_; } | 37 DeviceType type() const { return type_; } |
40 | 38 |
41 private: | 39 private: |
42 std::string unique_id_; | 40 std::string unique_id_; |
43 DeviceType type_; | 41 DeviceType type_; |
44 // Allow generated copy constructor and assignment. | 42 // Allow generated copy constructor and assignment. |
45 }; | 43 }; |
46 | 44 |
47 // Base abstract class used by DeviceMonitorMac to interact with either a QTKit | 45 // Base abstract class used by DeviceMonitorMac. |
48 // or an AVFoundation implementation of events and notifications. | |
49 class DeviceMonitorMacImpl { | 46 class DeviceMonitorMacImpl { |
50 public: | 47 public: |
51 explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor) | 48 explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor) |
52 : monitor_(monitor), | 49 : monitor_(monitor), |
53 cached_devices_(), | 50 cached_devices_(), |
54 device_arrival_(nil), | 51 device_arrival_(nil), |
55 device_removal_(nil) { | 52 device_removal_(nil) { |
56 DCHECK(monitor); | 53 DCHECK(monitor); |
57 // Initialise the devices_cache_ with a not-valid entry. For the case in | 54 // Initialise the devices_cache_ with a not-valid entry. For the case in |
58 // which there is one single device in the system and we get notified when | 55 // which there is one single device in the system and we get notified when |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 } | 117 } |
121 // Update the cached devices with the current system snapshot. | 118 // Update the cached devices with the current system snapshot. |
122 cached_devices_ = snapshot_devices; | 119 cached_devices_ = snapshot_devices; |
123 | 120 |
124 if (video_device_added || video_device_removed) | 121 if (video_device_added || video_device_removed) |
125 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); | 122 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
126 if (audio_device_added || audio_device_removed) | 123 if (audio_device_added || audio_device_removed) |
127 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); | 124 monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
128 } | 125 } |
129 | 126 |
130 class QTKitMonitorImpl : public DeviceMonitorMacImpl { | |
131 public: | |
132 explicit QTKitMonitorImpl(media::DeviceMonitorMac* monitor); | |
133 ~QTKitMonitorImpl() override; | |
134 | |
135 void OnDeviceChanged() override; | |
136 | |
137 private: | |
138 void CountDevices(); | |
139 void OnAttributeChanged(NSNotification* notification); | |
140 | |
141 id device_change_; | |
142 }; | |
143 | |
144 QTKitMonitorImpl::QTKitMonitorImpl(media::DeviceMonitorMac* monitor) | |
145 : DeviceMonitorMacImpl(monitor) { | |
146 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | |
147 device_arrival_ = | |
148 [nc addObserverForName:QTCaptureDeviceWasConnectedNotification | |
149 object:nil | |
150 queue:nil | |
151 usingBlock:^(NSNotification* notification) { | |
152 OnDeviceChanged(); | |
153 }]; | |
154 device_removal_ = | |
155 [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification | |
156 object:nil | |
157 queue:nil | |
158 usingBlock:^(NSNotification* notification) { | |
159 OnDeviceChanged(); | |
160 }]; | |
161 device_change_ = | |
162 [nc addObserverForName:QTCaptureDeviceAttributeDidChangeNotification | |
163 object:nil | |
164 queue:nil | |
165 usingBlock:^(NSNotification* notification) { | |
166 OnAttributeChanged(notification); | |
167 }]; | |
168 } | |
169 | |
170 QTKitMonitorImpl::~QTKitMonitorImpl() { | |
171 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | |
172 [nc removeObserver:device_arrival_]; | |
173 [nc removeObserver:device_removal_]; | |
174 [nc removeObserver:device_change_]; | |
175 } | |
176 | |
177 void QTKitMonitorImpl::OnAttributeChanged(NSNotification* notification) { | |
178 if ([[[notification userInfo] objectForKey:QTCaptureDeviceChangedAttributeKey] | |
179 isEqualToString:QTCaptureDeviceSuspendedAttribute]) { | |
180 OnDeviceChanged(); | |
181 } | |
182 } | |
183 | |
184 void QTKitMonitorImpl::OnDeviceChanged() { | |
185 std::vector<DeviceInfo> snapshot_devices; | |
186 | |
187 NSArray* devices = [QTCaptureDevice inputDevices]; | |
188 for (QTCaptureDevice* device in devices) { | |
189 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | |
190 // Act as if suspended video capture devices are not attached. For | |
191 // example, a laptop's internal webcam is suspended when the lid is closed. | |
192 if ([device hasMediaType:QTMediaTypeVideo] && | |
193 ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute] | |
194 boolValue]) { | |
195 device_type = DeviceInfo::kVideo; | |
196 } else if ([device hasMediaType:QTMediaTypeMuxed] && | |
197 ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute] | |
198 boolValue]) { | |
199 device_type = DeviceInfo::kMuxed; | |
200 } else if ([device hasMediaType:QTMediaTypeSound] && | |
201 ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute] | |
202 boolValue]) { | |
203 device_type = DeviceInfo::kAudio; | |
204 } | |
205 snapshot_devices.push_back( | |
206 DeviceInfo([[device uniqueID] UTF8String], device_type)); | |
207 } | |
208 ConsolidateDevicesListAndNotify(snapshot_devices); | |
209 } | |
210 | |
211 // Forward declaration for use by CrAVFoundationDeviceObserver. | 127 // Forward declaration for use by CrAVFoundationDeviceObserver. |
212 class SuspendObserverDelegate; | 128 class SuspendObserverDelegate; |
213 | 129 |
214 } // namespace | 130 } // namespace |
215 | 131 |
216 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ | 132 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ |
217 // classes cannot observe Key-Values directly. Created, manipulated, and | 133 // classes cannot observe Key-Values directly. Created, manipulated, and |
218 // destroyed on the UI Thread by SuspendObserverDelegate. | 134 // destroyed on the UI Thread by SuspendObserverDelegate. |
219 @interface CrAVFoundationDeviceObserver : NSObject { | 135 @interface CrAVFoundationDeviceObserver : NSObject { |
220 @private | 136 @private |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 onDeviceChangedCallback_.Run(); | 433 onDeviceChangedCallback_.Run(); |
518 if ([keyPath isEqual:@"connected"]) | 434 if ([keyPath isEqual:@"connected"]) |
519 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; | 435 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; |
520 } | 436 } |
521 | 437 |
522 @end // @implementation CrAVFoundationDeviceObserver | 438 @end // @implementation CrAVFoundationDeviceObserver |
523 | 439 |
524 namespace media { | 440 namespace media { |
525 | 441 |
526 DeviceMonitorMac::DeviceMonitorMac() { | 442 DeviceMonitorMac::DeviceMonitorMac() { |
527 // Both QTKit and AVFoundation do not need to be fired up until the user | 443 // AVFoundation do not need to be fired up until the user |
528 // exercises a GetUserMedia. Bringing up either library and enumerating the | 444 // exercises a GetUserMedia. Bringing up either library and enumerating the |
529 // devices in the system is an operation taking in the range of hundred of ms, | 445 // devices in the system is an operation taking in the range of hundred of ms, |
530 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). | 446 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). |
531 } | 447 } |
532 | 448 |
533 DeviceMonitorMac::~DeviceMonitorMac() {} | 449 DeviceMonitorMac::~DeviceMonitorMac() {} |
534 | 450 |
535 void DeviceMonitorMac::StartMonitoring( | 451 void DeviceMonitorMac::StartMonitoring( |
536 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { | 452 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { |
537 DCHECK(thread_checker_.CalledOnValidThread()); | 453 DCHECK(thread_checker_.CalledOnValidThread()); |
538 | 454 |
539 // We're on the UI thread so let's try to initialize AVFoundation and then | 455 // We're on the UI thread so let's try to initialize AVFoundation. |
540 // see if it's supported. IsAVFoundationSupported can't implicitly initialize | |
541 // the library since it can be called on different threads. | |
542 AVFoundationGlue::InitializeAVFoundation(); | 456 AVFoundationGlue::InitializeAVFoundation(); |
543 | 457 |
544 if (AVFoundationGlue::IsAVFoundationSupported()) { | |
545 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 | 458 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 |
546 // is fixed. | 459 // is fixed. |
547 tracked_objects::ScopedTracker tracking_profile( | 460 tracked_objects::ScopedTracker tracking_profile( |
548 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 461 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
549 "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); | 462 "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); |
550 DVLOG(1) << "Monitoring via AVFoundation"; | 463 DVLOG(1) << "Monitoring via AVFoundation"; |
551 device_monitor_impl_.reset( | 464 device_monitor_impl_.reset( |
552 new AVFoundationMonitorImpl(this, device_task_runner)); | 465 new AVFoundationMonitorImpl(this, device_task_runner)); |
553 } else { | |
554 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 | |
555 // is fixed. | |
556 tracked_objects::ScopedTracker tracking_profile( | |
557 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
558 "458404 DeviceMonitorMac::StartMonitoring::QTKit")); | |
559 DVLOG(1) << "Monitoring via QTKit"; | |
560 device_monitor_impl_.reset(new QTKitMonitorImpl(this)); | |
561 } | |
562 } | 466 } |
563 | 467 |
564 void DeviceMonitorMac::NotifyDeviceChanged( | 468 void DeviceMonitorMac::NotifyDeviceChanged( |
565 base::SystemMonitor::DeviceType type) { | 469 base::SystemMonitor::DeviceType type) { |
566 DCHECK(thread_checker_.CalledOnValidThread()); | 470 DCHECK(thread_checker_.CalledOnValidThread()); |
567 // TODO(xians): Remove the global variable for SystemMonitor. | 471 // TODO(xians): Remove the global variable for SystemMonitor. |
568 base::SystemMonitor::Get()->ProcessDevicesChanged(type); | 472 base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
569 } | 473 } |
570 | 474 |
571 } // namespace media | 475 } // namespace media |
OLD | NEW |