| 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 |