Chromium Code Reviews| 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 "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 <set> | 9 #include <set> |
| 10 | 10 |
| 11 #include "base/bind_helpers.h" | |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/mac/scoped_nsobject.h" | 13 #include "base/mac/scoped_nsobject.h" |
| 13 #import "media/video/capture/mac/avfoundation_glue.h" | 14 #import "media/video/capture/mac/avfoundation_glue.h" |
| 14 | 15 |
| 15 namespace { | 16 namespace { |
| 16 | 17 |
| 17 // This class is used to keep track of system devices names and their types. | 18 // This class is used to keep track of system devices names and their types. |
| 18 class DeviceInfo { | 19 class DeviceInfo { |
| 19 public: | 20 public: |
| 20 enum DeviceType { | 21 enum DeviceType { |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 DeviceInfo([[device uniqueID] UTF8String], device_type)); | 205 DeviceInfo([[device uniqueID] UTF8String], device_type)); |
| 205 } | 206 } |
| 206 ConsolidateDevicesListAndNotify(snapshot_devices); | 207 ConsolidateDevicesListAndNotify(snapshot_devices); |
| 207 } | 208 } |
| 208 | 209 |
| 209 // Forward declaration for use by CrAVFoundationDeviceObserver. | 210 // Forward declaration for use by CrAVFoundationDeviceObserver. |
| 210 class AVFoundationMonitorImpl; | 211 class AVFoundationMonitorImpl; |
| 211 | 212 |
| 212 } // namespace | 213 } // namespace |
| 213 | 214 |
| 214 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ | 215 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ |
| 215 // classes cannot observe Key-Values directly. | 216 // classes cannot observe Key-Values directly. This class is used by |
| 217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a. | |
| 218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread. | |
| 216 @interface CrAVFoundationDeviceObserver : NSObject { | 219 @interface CrAVFoundationDeviceObserver : NSObject { |
| 217 @private | 220 @private |
| 218 AVFoundationMonitorImpl* receiver_; | 221 AVFoundationMonitorImpl* receiver_; |
| 219 // Member to keep track of the devices we are already monitoring. | 222 // Member to keep track of the devices we are already monitoring. |
| 220 std::set<CrAVCaptureDevice*> monitoredDevices_; | 223 std::set<CrAVCaptureDevice*> monitoredDevices_; |
| 221 } | 224 } |
| 222 | 225 |
| 223 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; | 226 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; |
| 224 - (void)startObserving:(CrAVCaptureDevice*)device; | 227 - (void)startObserving:(CrAVCaptureDevice*)device; |
| 225 - (void)stopObserving:(CrAVCaptureDevice*)device; | 228 - (void)stopObserving:(CrAVCaptureDevice*)device; |
| 226 | 229 |
| 227 @end | 230 @end |
| 228 | 231 |
| 229 namespace { | 232 namespace { |
| 230 | 233 |
| 234 // AVFoundation implementation of the Mac Device Monitor, registers as a global | |
| 235 // device connect/disconnect observer and plugs suspend/wake up device observers | |
| 236 // per device. This class is created and lives in UI thread; device enumeration | |
| 237 // and operations involving |suspend_observer_| happen on |device_task_runner_|. | |
| 231 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { | 238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { |
| 232 public: | 239 public: |
| 233 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor); | 240 AVFoundationMonitorImpl( |
| 241 content::DeviceMonitorMac* monitor, | |
| 242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); | |
| 234 virtual ~AVFoundationMonitorImpl(); | 243 virtual ~AVFoundationMonitorImpl(); |
| 235 | 244 |
| 236 virtual void OnDeviceChanged() OVERRIDE; | 245 virtual void OnDeviceChanged() OVERRIDE; |
| 237 | 246 |
| 238 private: | 247 private: |
| 248 void OnDeviceChangedOnDeviceThread( | |
| 249 const scoped_refptr<base::MessageLoopProxy>& ui_thread); | |
| 250 void StartObserverOnDeviceThread(); | |
| 251 | |
| 252 base::ThreadChecker thread_checker_; | |
| 253 | |
| 254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for | |
| 255 // device enumeration, valid after MediaStreamManager calls StartMonitoring(). | |
| 256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; | |
| 257 | |
| 258 // Created and executed in |device_task_runnner_|. | |
| 239 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; | 259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; |
| 260 | |
| 240 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); | 261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); |
| 241 }; | 262 }; |
| 242 | 263 |
| 243 AVFoundationMonitorImpl::AVFoundationMonitorImpl( | 264 AVFoundationMonitorImpl::AVFoundationMonitorImpl( |
| 244 content::DeviceMonitorMac* monitor) | 265 content::DeviceMonitorMac* monitor, |
| 245 : DeviceMonitorMacImpl(monitor) { | 266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) |
| 267 : DeviceMonitorMacImpl(monitor), | |
| 268 device_task_runner_(device_task_runner) { | |
| 246 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 247 device_arrival_ = | 270 device_arrival_ = |
| 248 [nc addObserverForName:AVFoundationGlue:: | 271 [nc addObserverForName:AVFoundationGlue:: |
| 249 AVCaptureDeviceWasConnectedNotification() | 272 AVCaptureDeviceWasConnectedNotification() |
| 250 object:nil | 273 object:nil |
| 251 queue:nil | 274 queue:nil |
| 252 usingBlock:^(NSNotification* notification) { | 275 usingBlock:^(NSNotification* notification) { |
| 253 OnDeviceChanged();}]; | 276 OnDeviceChanged();}]; |
| 254 device_removal_ = | 277 device_removal_ = |
| 255 [nc addObserverForName:AVFoundationGlue:: | 278 [nc addObserverForName:AVFoundationGlue:: |
| 256 AVCaptureDeviceWasDisconnectedNotification() | 279 AVCaptureDeviceWasDisconnectedNotification() |
| 257 object:nil | 280 object:nil |
| 258 queue:nil | 281 queue:nil |
| 259 usingBlock:^(NSNotification* notification) { | 282 usingBlock:^(NSNotification* notification) { |
| 260 OnDeviceChanged();}]; | 283 OnDeviceChanged();}]; |
| 261 suspend_observer_.reset( | 284 device_task_runner_->PostTask(FROM_HERE, |
| 262 [[CrAVFoundationDeviceObserver alloc] initWithChangeReceiver:this]); | 285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread, |
| 263 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) | 286 base::Unretained(this))); |
| 264 [suspend_observer_ startObserving:device]; | |
| 265 } | 287 } |
| 266 | 288 |
| 267 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { | 289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { |
| 268 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 269 [nc removeObserver:device_arrival_]; | 291 [nc removeObserver:device_arrival_]; |
| 270 [nc removeObserver:device_removal_]; | 292 [nc removeObserver:device_removal_]; |
| 271 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) | |
| 272 [suspend_observer_ stopObserving:device]; | |
| 273 } | 293 } |
| 274 | 294 |
| 275 void AVFoundationMonitorImpl::OnDeviceChanged() { | 295 void AVFoundationMonitorImpl::OnDeviceChanged() { |
| 296 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 297 device_task_runner_->PostTask(FROM_HERE, | |
| 298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread, | |
| 299 base::Unretained(this), | |
| 300 base::MessageLoop::current()->message_loop_proxy())); | |
| 301 } | |
| 302 | |
| 303 void AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread( | |
| 304 const scoped_refptr<base::MessageLoopProxy>& ui_thread) { | |
| 305 DCHECK(device_task_runner_->BelongsToCurrentThread()); | |
| 306 NSArray* devices = [AVCaptureDeviceGlue devices]; | |
| 276 std::vector<DeviceInfo> snapshot_devices; | 307 std::vector<DeviceInfo> snapshot_devices; |
| 277 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) { | 308 for (CrAVCaptureDevice* device in devices) { |
| 278 [suspend_observer_ startObserving:device]; | 309 [suspend_observer_ startObserving:device]; |
| 279 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && | 310 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && |
| 280 [device isSuspended]; | 311 [device isSuspended]; |
| 281 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | 312 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; |
| 282 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { | 313 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { |
| 283 if (suspended) | 314 if (suspended) |
| 284 continue; | 315 continue; |
| 285 device_type = DeviceInfo::kVideo; | 316 device_type = DeviceInfo::kVideo; |
| 286 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { | 317 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { |
| 287 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; | 318 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; |
| 288 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { | 319 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { |
| 289 device_type = DeviceInfo::kAudio; | 320 device_type = DeviceInfo::kAudio; |
| 290 } | 321 } |
| 291 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], | 322 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], |
| 292 device_type)); | 323 device_type)); |
| 293 } | 324 } |
| 294 ConsolidateDevicesListAndNotify(snapshot_devices); | 325 // Post the consolidation of enumerated devices to be done on UI thread. |
| 326 ui_thread->PostTask(FROM_HERE, | |
| 327 base::Bind(&DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify, | |
| 328 base::Unretained(this), snapshot_devices)); | |
| 329 } | |
| 330 | |
| 331 void AVFoundationMonitorImpl::StartObserverOnDeviceThread() { | |
| 332 DCHECK(device_task_runner_->BelongsToCurrentThread()); | |
| 333 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] | |
| 334 initWithChangeReceiver:this]); | |
| 335 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) | |
| 336 [suspend_observer_ startObserving:device]; | |
| 295 } | 337 } |
| 296 | 338 |
| 297 } // namespace | 339 } // namespace |
| 298 | 340 |
| 299 @implementation CrAVFoundationDeviceObserver | 341 @implementation CrAVFoundationDeviceObserver |
| 300 | 342 |
| 301 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { | 343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { |
| 302 if ((self = [super init])) { | 344 if (self = [super init]) { |
|
Robert Sesek
2014/04/29 15:19:53
nit: keep these
| |
| 303 DCHECK(receiver != NULL); | 345 DCHECK(receiver != NULL); |
| 304 receiver_ = receiver; | 346 receiver_ = receiver; |
| 305 } | 347 } |
| 306 return self; | 348 return self; |
| 307 } | 349 } |
| 308 | 350 |
| 351 - (void)dealloc { | |
| 352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); | |
| 353 while (it != monitoredDevices_.end()) | |
| 354 [self stopObserving:*it++]; | |
| 355 [super dealloc]; | |
| 356 } | |
| 357 | |
| 309 - (void)startObserving:(CrAVCaptureDevice*)device { | 358 - (void)startObserving:(CrAVCaptureDevice*)device { |
| 310 DCHECK(device != nil); | 359 DCHECK(device != nil); |
| 311 // Skip this device if there are already observers connected to it. | 360 // Skip this device if there are already observers connected to it. |
| 312 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != | 361 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != |
| 313 monitoredDevices_.end()) { | 362 monitoredDevices_.end()) { |
| 314 return; | 363 return; |
| 315 } | 364 } |
| 316 [device addObserver:self | 365 [device addObserver:self |
| 317 forKeyPath:@"suspended" | 366 forKeyPath:@"suspended" |
| 318 options:0 | 367 options:0 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 | 401 |
| 353 DeviceMonitorMac::DeviceMonitorMac() { | 402 DeviceMonitorMac::DeviceMonitorMac() { |
| 354 // Both QTKit and AVFoundation do not need to be fired up until the user | 403 // Both QTKit and AVFoundation do not need to be fired up until the user |
| 355 // exercises a GetUserMedia. Bringing up either library and enumerating the | 404 // exercises a GetUserMedia. Bringing up either library and enumerating the |
| 356 // devices in the system is an operation taking in the range of hundred of ms, | 405 // devices in the system is an operation taking in the range of hundred of ms, |
| 357 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). | 406 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). |
| 358 } | 407 } |
| 359 | 408 |
| 360 DeviceMonitorMac::~DeviceMonitorMac() {} | 409 DeviceMonitorMac::~DeviceMonitorMac() {} |
| 361 | 410 |
| 362 void DeviceMonitorMac::StartMonitoring() { | 411 void DeviceMonitorMac::StartMonitoring( |
| 412 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { | |
| 363 DCHECK(thread_checker_.CalledOnValidThread()); | 413 DCHECK(thread_checker_.CalledOnValidThread()); |
| 364 if (AVFoundationGlue::IsAVFoundationSupported()) { | 414 if (AVFoundationGlue::IsAVFoundationSupported()) { |
| 365 DVLOG(1) << "Monitoring via AVFoundation"; | 415 DVLOG(1) << "Monitoring via AVFoundation"; |
| 366 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this)); | 416 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this, |
| 417 device_task_runner)); | |
| 367 } else { | 418 } else { |
| 368 DVLOG(1) << "Monitoring via QTKit"; | 419 DVLOG(1) << "Monitoring via QTKit"; |
| 369 device_monitor_impl_.reset(new QTKitMonitorImpl(this)); | 420 device_monitor_impl_.reset(new QTKitMonitorImpl(this)); |
| 370 } | 421 } |
| 371 } | 422 } |
| 372 | 423 |
| 373 void DeviceMonitorMac::NotifyDeviceChanged( | 424 void DeviceMonitorMac::NotifyDeviceChanged( |
| 374 base::SystemMonitor::DeviceType type) { | 425 base::SystemMonitor::DeviceType type) { |
| 426 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 375 // TODO(xians): Remove the global variable for SystemMonitor. | 427 // TODO(xians): Remove the global variable for SystemMonitor. |
| 376 base::SystemMonitor::Get()->ProcessDevicesChanged(type); | 428 base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
| 377 } | 429 } |
| 378 | 430 |
| 379 } // namespace content | 431 } // namespace content |
| OLD | NEW |