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/bind_helpers.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/mac/scoped_nsobject.h" | 13 #include "base/mac/scoped_nsobject.h" |
| 14 #include "base/threading/thread_checker.h" | |
| 15 #include "content/public/browser/browser_thread.h" | |
| 14 #import "media/video/capture/mac/avfoundation_glue.h" | 16 #import "media/video/capture/mac/avfoundation_glue.h" |
| 15 | 17 |
| 16 namespace { | 18 namespace { |
| 17 | 19 |
| 18 // This class is used to keep track of system devices names and their types. | 20 // This class is used to keep track of system devices names and their types. |
| 19 class DeviceInfo { | 21 class DeviceInfo { |
| 20 public: | 22 public: |
| 21 enum DeviceType { | 23 enum DeviceType { |
| 22 kAudio, | 24 kAudio, |
| 23 kVideo, | 25 kVideo, |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 boolValue]) { | 203 boolValue]) { |
| 202 device_type = DeviceInfo::kAudio; | 204 device_type = DeviceInfo::kAudio; |
| 203 } | 205 } |
| 204 snapshot_devices.push_back( | 206 snapshot_devices.push_back( |
| 205 DeviceInfo([[device uniqueID] UTF8String], device_type)); | 207 DeviceInfo([[device uniqueID] UTF8String], device_type)); |
| 206 } | 208 } |
| 207 ConsolidateDevicesListAndNotify(snapshot_devices); | 209 ConsolidateDevicesListAndNotify(snapshot_devices); |
| 208 } | 210 } |
| 209 | 211 |
| 210 // Forward declaration for use by CrAVFoundationDeviceObserver. | 212 // Forward declaration for use by CrAVFoundationDeviceObserver. |
| 211 class AVFoundationMonitorImpl; | 213 class SuspendObserverDelegate; |
| 212 | 214 |
| 213 } // namespace | 215 } // namespace |
| 214 | 216 |
| 215 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ | 217 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ |
| 216 // classes cannot observe Key-Values directly. This class is used by | 218 // classes cannot observe Key-Values directly. This class is used and |
| 217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a. | 219 // manipulated by SuspendObserverDelegate in Device Thread. -stopObserving is |
|
Robert Sesek
2014/05/15 17:01:00
Can you simplify this to say that "Created, manipu
mcasas
2014/05/16 07:06:13
Done.
| |
| 218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread. | 220 // called dutifully on -dealloc on Device Thread too. |
| 219 @interface CrAVFoundationDeviceObserver : NSObject { | 221 @interface CrAVFoundationDeviceObserver : NSObject { |
| 220 @private | 222 @private |
| 221 AVFoundationMonitorImpl* receiver_; | 223 SuspendObserverDelegate* receiver_; |
|
Robert Sesek
2014/05/15 17:01:00
nit: comment " // weak" at the end of the line
mcasas
2014/05/16 07:06:13
Done.
| |
| 222 // Member to keep track of the devices we are already monitoring. | 224 // Member to keep track of the devices we are already monitoring. |
| 223 std::set<CrAVCaptureDevice*> monitoredDevices_; | 225 std::set<CrAVCaptureDevice*> monitoredDevices_; |
| 224 } | 226 } |
| 225 | 227 |
| 226 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; | 228 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver; |
| 227 - (void)startObserving:(CrAVCaptureDevice*)device; | 229 - (void)startObserving:(CrAVCaptureDevice*)device; |
| 228 - (void)stopObserving:(CrAVCaptureDevice*)device; | 230 - (void)stopObserving:(CrAVCaptureDevice*)device; |
| 229 | 231 |
| 230 @end | 232 @end |
| 231 | 233 |
| 232 namespace { | 234 namespace { |
| 233 | 235 |
| 236 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. | |
| 237 // Provides a callback for this device observer to indicate that there has been | |
| 238 // a device change of some kind. Created by AVFoundationMonitorImpl in UI thread | |
| 239 // but living in Device Thread. | |
| 240 class SuspendObserverDelegate : | |
| 241 public base::RefCountedThreadSafe<SuspendObserverDelegate> { | |
| 242 public: | |
| 243 SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) | |
|
Robert Sesek
2014/05/15 17:01:00
explicit
mcasas
2014/05/16 07:06:13
Done.
| |
| 244 : avfoundation_monitor_impl_(monitor) { | |
| 245 device_thread_checker_.DetachFromThread(); | |
| 246 } | |
| 247 | |
| 248 void OnDeviceChanged(); | |
| 249 void StartObserver(); | |
| 250 void ResetDeviceMonitorOnUIThread(); | |
| 251 | |
| 252 private: | |
| 253 virtual ~SuspendObserverDelegate() {} | |
| 254 void OnDeviceChangedOnUIThread( | |
| 255 const std::vector<DeviceInfo>& snapshot_devices); | |
| 256 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; | |
|
Robert Sesek
2014/05/15 17:01:00
nit: friends come first in the private section
mcasas
2014/05/16 07:06:13
Done.
| |
| 257 | |
| 258 base::ThreadChecker device_thread_checker_; | |
| 259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; | |
| 260 DeviceMonitorMacImpl* avfoundation_monitor_impl_; | |
| 261 }; | |
| 262 | |
| 263 void SuspendObserverDelegate::OnDeviceChanged() { | |
| 264 DCHECK(device_thread_checker_.CalledOnValidThread()); | |
| 265 NSArray* devices = [AVCaptureDeviceGlue devices]; | |
| 266 std::vector<DeviceInfo> snapshot_devices; | |
| 267 for (CrAVCaptureDevice* device in devices) { | |
| 268 [suspend_observer_ startObserving:device]; | |
| 269 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && | |
| 270 [device isSuspended]; | |
| 271 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | |
| 272 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { | |
| 273 if (suspended) | |
| 274 continue; | |
| 275 device_type = DeviceInfo::kVideo; | |
| 276 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { | |
| 277 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; | |
| 278 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { | |
| 279 device_type = DeviceInfo::kAudio; | |
| 280 } | |
| 281 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], | |
| 282 device_type)); | |
| 283 } | |
| 284 // Post the consolidation of enumerated devices to be done on UI thread. | |
| 285 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
| 286 base::Bind(&SuspendObserverDelegate::OnDeviceChangedOnUIThread, | |
| 287 this, snapshot_devices)); | |
| 288 } | |
| 289 | |
| 290 void SuspendObserverDelegate::StartObserver() { | |
| 291 DCHECK(device_thread_checker_.CalledOnValidThread()); | |
| 292 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] | |
| 293 initWithChangeReceiver:this]); | |
| 294 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) | |
| 295 [suspend_observer_ startObserving:device]; | |
| 296 } | |
| 297 | |
| 298 void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() { | |
| 299 DCHECK(base::MessageLoopForUI::IsCurrent()); | |
|
Robert Sesek
2014/05/15 17:01:00
More common to do DCHECK(content::BrowserThread::C
mcasas
2014/05/16 07:06:13
Done.
| |
| 300 avfoundation_monitor_impl_ = NULL; | |
| 301 } | |
| 302 | |
| 303 void SuspendObserverDelegate::OnDeviceChangedOnUIThread( | |
| 304 const std::vector<DeviceInfo>& snapshot_devices) { | |
| 305 DCHECK(base::MessageLoopForUI::IsCurrent()); | |
|
Robert Sesek
2014/05/15 17:01:00
Same.
mcasas
2014/05/16 07:06:13
Done.
| |
| 306 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before | |
| 307 // arriving at this line. | |
| 308 if (avfoundation_monitor_impl_) { | |
| 309 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( | |
| 310 snapshot_devices); | |
| 311 } | |
| 312 } | |
| 313 | |
| 234 // AVFoundation implementation of the Mac Device Monitor, registers as a global | 314 // AVFoundation implementation of the Mac Device Monitor, registers as a global |
| 235 // device connect/disconnect observer and plugs suspend/wake up device observers | 315 // 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 | 316 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_| |
| 237 // and operations involving |suspend_observer_| happen on |device_task_runner_|. | 317 // and gets notified when a device is suspended/resumed. This class is created |
| 318 // and lives in UI thread; | |
| 238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { | 319 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { |
| 239 public: | 320 public: |
| 240 AVFoundationMonitorImpl( | 321 AVFoundationMonitorImpl( |
| 241 content::DeviceMonitorMac* monitor, | 322 content::DeviceMonitorMac* monitor, |
| 242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); | 323 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); |
| 243 virtual ~AVFoundationMonitorImpl(); | 324 virtual ~AVFoundationMonitorImpl(); |
| 244 | 325 |
| 245 virtual void OnDeviceChanged() OVERRIDE; | 326 virtual void OnDeviceChanged() OVERRIDE; |
| 246 | 327 |
| 247 private: | 328 private: |
| 248 void OnDeviceChangedOnDeviceThread( | |
| 249 const scoped_refptr<base::MessageLoopProxy>& ui_thread); | |
| 250 void StartObserverOnDeviceThread(); | |
| 251 | |
| 252 base::ThreadChecker thread_checker_; | 329 base::ThreadChecker thread_checker_; |
| 253 | 330 |
| 254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for | 331 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for |
| 255 // device enumeration, valid after MediaStreamManager calls StartMonitoring(). | 332 // posting tasks to |suspend_observer_delegate_|; valid after |
| 333 // MediaStreamManager calls StartMonitoring(). | |
| 256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; | 334 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; |
| 257 | 335 |
| 258 // Created and executed in |device_task_runnner_|. | 336 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; |
| 259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; | |
| 260 | 337 |
| 261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); | 338 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); |
| 262 }; | 339 }; |
| 263 | 340 |
| 264 AVFoundationMonitorImpl::AVFoundationMonitorImpl( | 341 AVFoundationMonitorImpl::AVFoundationMonitorImpl( |
| 265 content::DeviceMonitorMac* monitor, | 342 content::DeviceMonitorMac* monitor, |
| 266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) | 343 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) |
| 267 : DeviceMonitorMacImpl(monitor), | 344 : DeviceMonitorMacImpl(monitor), |
| 268 device_task_runner_(device_task_runner) { | 345 device_task_runner_(device_task_runner), |
| 346 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { | |
| 269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 347 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 270 device_arrival_ = | 348 device_arrival_ = |
| 271 [nc addObserverForName:AVFoundationGlue:: | 349 [nc addObserverForName:AVFoundationGlue:: |
| 272 AVCaptureDeviceWasConnectedNotification() | 350 AVCaptureDeviceWasConnectedNotification() |
| 273 object:nil | 351 object:nil |
| 274 queue:nil | 352 queue:nil |
| 275 usingBlock:^(NSNotification* notification) { | 353 usingBlock:^(NSNotification* notification) { |
| 276 OnDeviceChanged();}]; | 354 OnDeviceChanged();}]; |
| 277 device_removal_ = | 355 device_removal_ = |
| 278 [nc addObserverForName:AVFoundationGlue:: | 356 [nc addObserverForName:AVFoundationGlue:: |
| 279 AVCaptureDeviceWasDisconnectedNotification() | 357 AVCaptureDeviceWasDisconnectedNotification() |
| 280 object:nil | 358 object:nil |
| 281 queue:nil | 359 queue:nil |
| 282 usingBlock:^(NSNotification* notification) { | 360 usingBlock:^(NSNotification* notification) { |
| 283 OnDeviceChanged();}]; | 361 OnDeviceChanged();}]; |
| 284 device_task_runner_->PostTask(FROM_HERE, | 362 device_task_runner_->PostTask(FROM_HERE, |
| 285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread, | 363 base::Bind(&SuspendObserverDelegate::StartObserver, |
| 286 base::Unretained(this))); | 364 suspend_observer_delegate_)); |
| 287 } | 365 } |
| 288 | 366 |
| 289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { | 367 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { |
| 368 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 369 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread(); | |
| 290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 370 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 291 [nc removeObserver:device_arrival_]; | 371 [nc removeObserver:device_arrival_]; |
| 292 [nc removeObserver:device_removal_]; | 372 [nc removeObserver:device_removal_]; |
| 293 } | 373 } |
| 294 | 374 |
| 295 void AVFoundationMonitorImpl::OnDeviceChanged() { | 375 void AVFoundationMonitorImpl::OnDeviceChanged() { |
| 296 DCHECK(thread_checker_.CalledOnValidThread()); | 376 DCHECK(thread_checker_.CalledOnValidThread()); |
| 297 device_task_runner_->PostTask(FROM_HERE, | 377 device_task_runner_->PostTask(FROM_HERE, |
| 298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread, | 378 base::Bind(&SuspendObserverDelegate::OnDeviceChanged, |
| 299 base::Unretained(this), | 379 suspend_observer_delegate_)); |
| 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]; | |
| 307 std::vector<DeviceInfo> snapshot_devices; | |
| 308 for (CrAVCaptureDevice* device in devices) { | |
| 309 [suspend_observer_ startObserving:device]; | |
| 310 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && | |
| 311 [device isSuspended]; | |
| 312 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | |
| 313 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { | |
| 314 if (suspended) | |
| 315 continue; | |
| 316 device_type = DeviceInfo::kVideo; | |
| 317 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { | |
| 318 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; | |
| 319 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { | |
| 320 device_type = DeviceInfo::kAudio; | |
| 321 } | |
| 322 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], | |
| 323 device_type)); | |
| 324 } | |
| 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]; | |
| 337 } | 380 } |
| 338 | 381 |
| 339 } // namespace | 382 } // namespace |
| 340 | 383 |
| 341 @implementation CrAVFoundationDeviceObserver | 384 @implementation CrAVFoundationDeviceObserver |
| 342 | 385 |
| 343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { | 386 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver { |
| 344 if ((self = [super init])) { | 387 if ((self = [super init])) { |
| 345 DCHECK(receiver != NULL); | 388 DCHECK(receiver != NULL); |
| 346 receiver_ = receiver; | 389 receiver_ = receiver; |
| 347 } | 390 } |
| 348 return self; | 391 return self; |
| 349 } | 392 } |
| 350 | 393 |
| 351 - (void)dealloc { | 394 - (void)dealloc { |
| 352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); | 395 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); |
| 353 while (it != monitoredDevices_.end()) | 396 while (it != monitoredDevices_.end()) |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 } | 470 } |
| 428 | 471 |
| 429 void DeviceMonitorMac::NotifyDeviceChanged( | 472 void DeviceMonitorMac::NotifyDeviceChanged( |
| 430 base::SystemMonitor::DeviceType type) { | 473 base::SystemMonitor::DeviceType type) { |
| 431 DCHECK(thread_checker_.CalledOnValidThread()); | 474 DCHECK(thread_checker_.CalledOnValidThread()); |
| 432 // TODO(xians): Remove the global variable for SystemMonitor. | 475 // TODO(xians): Remove the global variable for SystemMonitor. |
| 433 base::SystemMonitor::Get()->ProcessDevicesChanged(type); | 476 base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
| 434 } | 477 } |
| 435 | 478 |
| 436 } // namespace content | 479 } // namespace content |
| OLD | NEW |