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/bind_objc_block.h" | |
| 13 #include "base/mac/scoped_nsobject.h" | 14 #include "base/mac/scoped_nsobject.h" |
| 14 #include "base/threading/thread_checker.h" | 15 #include "base/threading/thread_checker.h" |
| 15 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
| 17 #include "media/base/bind_to_current_loop.h" | |
| 16 #import "media/video/capture/mac/avfoundation_glue.h" | 18 #import "media/video/capture/mac/avfoundation_glue.h" |
| 17 | 19 |
| 20 using content::BrowserThread; | |
| 21 | |
| 18 namespace { | 22 namespace { |
| 19 | 23 |
| 20 // This class is used to keep track of system devices names and their types. | 24 // This class is used to keep track of system devices names and their types. |
| 21 class DeviceInfo { | 25 class DeviceInfo { |
| 22 public: | 26 public: |
| 23 enum DeviceType { | 27 enum DeviceType { |
| 24 kAudio, | 28 kAudio, |
| 25 kVideo, | 29 kVideo, |
| 26 kMuxed, | 30 kMuxed, |
| 27 kUnknown, | 31 kUnknown, |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 ConsolidateDevicesListAndNotify(snapshot_devices); | 213 ConsolidateDevicesListAndNotify(snapshot_devices); |
| 210 } | 214 } |
| 211 | 215 |
| 212 // Forward declaration for use by CrAVFoundationDeviceObserver. | 216 // Forward declaration for use by CrAVFoundationDeviceObserver. |
| 213 class SuspendObserverDelegate; | 217 class SuspendObserverDelegate; |
| 214 | 218 |
| 215 } // namespace | 219 } // namespace |
| 216 | 220 |
| 217 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ | 221 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ |
| 218 // classes cannot observe Key-Values directly. Created, manipulated, and | 222 // classes cannot observe Key-Values directly. Created, manipulated, and |
| 219 // destroyed on the Device Thread by SuspendedObserverDelegate. | 223 // destroyed on the UI Thread by SuspendObserverDelegate. |
| 220 @interface CrAVFoundationDeviceObserver : NSObject { | 224 @interface CrAVFoundationDeviceObserver : NSObject { |
| 221 @private | 225 @private |
| 222 SuspendObserverDelegate* receiver_; // weak | 226 // Callback for device changed, has to run on Device Thread. |
| 227 base::Closure onDeviceChangedCallback_; | |
| 228 | |
| 223 // Member to keep track of the devices we are already monitoring. | 229 // Member to keep track of the devices we are already monitoring. |
| 224 std::set<CrAVCaptureDevice*> monitoredDevices_; | 230 std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_; |
| 225 } | 231 } |
| 226 | 232 |
| 227 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver; | 233 - (id)initWithOnChangedCallback:(const base::Closure&)callback; |
| 228 - (void)startObserving:(CrAVCaptureDevice*)device; | 234 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device; |
| 229 - (void)stopObserving:(CrAVCaptureDevice*)device; | 235 - (void)stopObserving:(const CrAVCaptureDevice*)device; |
| 236 - (void)clearOnDeviceChangedCallback; | |
| 230 | 237 |
| 231 @end | 238 @end |
| 232 | 239 |
| 233 namespace { | 240 namespace { |
| 234 | 241 |
| 235 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. | 242 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. |
| 236 // Provides a callback for this device observer to indicate that there has been | 243 // It is created and destroyed in UI thread by AVFoundationMonitorImpl, and it |
| 237 // a device change of some kind. Created by AVFoundationMonitorImpl in UI thread | 244 // operates in this thread except for the expensive device enumerations which |
| 238 // but living in Device Thread. | 245 // are run on Device Thread. |
| 239 class SuspendObserverDelegate : | 246 class SuspendObserverDelegate : |
| 240 public base::RefCountedThreadSafe<SuspendObserverDelegate> { | 247 public base::RefCountedThreadSafe<SuspendObserverDelegate> { |
| 241 public: | 248 public: |
| 242 explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) | 249 explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor); |
| 243 : avfoundation_monitor_impl_(monitor) { | |
| 244 device_thread_checker_.DetachFromThread(); | |
| 245 } | |
| 246 | 250 |
| 247 void OnDeviceChanged(); | 251 void StartObserver( |
|
Robert Sesek
2014/07/08 17:05:40
Comment these please.
mcasas
2014/07/09 08:27:33
Done.
| |
| 248 void StartObserver(); | 252 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); |
| 249 void ResetDeviceMonitorOnUIThread(); | 253 void OnDeviceChanged( |
| 254 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); | |
| 255 void ResetDeviceMonitor(); | |
| 250 | 256 |
| 251 private: | 257 private: |
| 252 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; | 258 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; |
| 253 | 259 |
| 254 virtual ~SuspendObserverDelegate() {} | 260 virtual ~SuspendObserverDelegate(); |
| 255 | 261 |
| 256 void OnDeviceChangedOnUIThread( | 262 void DoStartObserver(NSArray* devices); |
|
Robert Sesek
2014/07/08 17:05:40
Comment about ownership of |devices| here, after y
tommi (sloooow) - chröme
2014/07/08 17:23:42
Does scoped_nsobject<> support this sort of scenar
Robert Sesek
2014/07/08 17:25:25
It's pretty atypical I think to see things passed
tommi (sloooow) - chröme
2014/07/08 17:29:29
OK, what I was after was basically the same patter
mcasas
2014/07/09 08:27:33
Added comment about DoStartObserver owning the |de
tommi (sloooow) - chröme
2014/07/09 09:19:39
Since DoStartObserver releases the reference of |d
| |
| 257 const std::vector<DeviceInfo>& snapshot_devices); | 263 void DoOnDeviceChanged(NSArray* devices); |
| 258 | 264 |
| 259 base::ThreadChecker device_thread_checker_; | |
| 260 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; | 265 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; |
| 261 DeviceMonitorMacImpl* avfoundation_monitor_impl_; | 266 DeviceMonitorMacImpl* avfoundation_monitor_impl_; |
| 262 }; | 267 }; |
| 263 | 268 |
| 264 void SuspendObserverDelegate::OnDeviceChanged() { | 269 SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) |
| 265 DCHECK(device_thread_checker_.CalledOnValidThread()); | 270 : avfoundation_monitor_impl_(monitor) { |
| 266 NSArray* devices = [AVCaptureDeviceGlue devices]; | 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 272 } | |
| 273 | |
| 274 void SuspendObserverDelegate::StartObserver( | |
| 275 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { | |
| 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 277 | |
| 278 base::Closure on_device_changed_callback = | |
| 279 base::Bind(&SuspendObserverDelegate::OnDeviceChanged, | |
| 280 this, device_thread); | |
| 281 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] | |
| 282 initWithOnChangedCallback:on_device_changed_callback]); | |
| 283 | |
| 284 base::PostTaskAndReplyWithResult(device_thread, FROM_HERE, | |
| 285 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }), | |
|
Robert Sesek
2014/07/08 17:05:40
nit: indent 2 more spaces, same with the next line
tommi (sloooow) - chröme
2014/07/08 17:23:42
use scoped_nsobject wherever possible to reduce th
mcasas
2014/07/09 08:27:33
As per the discussion above, I'll avoid using
sco
mcasas
2014/07/09 08:27:33
Done.
| |
| 286 base::Bind(&SuspendObserverDelegate::DoStartObserver, this)); | |
| 287 } | |
| 288 | |
| 289 void SuspendObserverDelegate::OnDeviceChanged( | |
| 290 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { | |
| 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 292 // Enumerate the devices in Device thread and post the consolidation of | |
| 293 // the devices and the old ones to be done on UI thread. | |
| 294 PostTaskAndReplyWithResult(device_thread, FROM_HERE, | |
| 295 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }), | |
|
tommi (sloooow) - chröme
2014/07/08 17:23:42
same here
mcasas
2014/07/09 08:27:33
Ditto: No scoped_nsobject<T> in params.
| |
| 296 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this)); | |
| 297 } | |
| 298 | |
| 299 void SuspendObserverDelegate::ResetDeviceMonitor() { | |
| 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 301 avfoundation_monitor_impl_ = NULL; | |
| 302 [suspend_observer_ clearOnDeviceChangedCallback]; | |
| 303 } | |
| 304 | |
| 305 SuspendObserverDelegate::~SuspendObserverDelegate() { | |
| 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 307 } | |
| 308 | |
| 309 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) { | |
|
Robert Sesek
2014/07/08 17:05:40
|devices| is going to be leaked from line 284 / 29
mcasas
2014/07/09 08:27:34
Done here and inside DoOnDeviceChanged(), that als
| |
| 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 311 for (CrAVCaptureDevice* device in devices) { | |
| 312 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); | |
|
Robert Sesek
2014/07/08 17:05:40
Do you need this line? The array owns the object.
mcasas
2014/07/09 08:27:33
We/I need to keep an extra reference for the scope
| |
| 313 [suspend_observer_ startObserving:device_ptr]; | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) { | |
| 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 267 std::vector<DeviceInfo> snapshot_devices; | 319 std::vector<DeviceInfo> snapshot_devices; |
| 268 for (CrAVCaptureDevice* device in devices) { | 320 for (CrAVCaptureDevice* device in devices) { |
| 269 [suspend_observer_ startObserving:device]; | 321 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); |
| 322 [suspend_observer_ startObserving:device_ptr]; | |
| 323 | |
| 270 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && | 324 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && |
| 271 [device isSuspended]; | 325 [device isSuspended]; |
| 272 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | 326 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; |
| 273 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { | 327 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { |
| 274 if (suspended) | 328 if (suspended) |
| 275 continue; | 329 continue; |
| 276 device_type = DeviceInfo::kVideo; | 330 device_type = DeviceInfo::kVideo; |
| 277 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { | 331 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { |
| 278 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; | 332 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; |
| 279 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { | 333 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { |
| 280 device_type = DeviceInfo::kAudio; | 334 device_type = DeviceInfo::kAudio; |
| 281 } | 335 } |
| 282 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], | 336 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], |
| 283 device_type)); | 337 device_type)); |
| 284 } | 338 } |
| 285 // Post the consolidation of enumerated devices to be done on UI thread. | |
| 286 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
| 287 base::Bind(&SuspendObserverDelegate::OnDeviceChangedOnUIThread, | |
| 288 this, snapshot_devices)); | |
| 289 } | |
| 290 | 339 |
| 291 void SuspendObserverDelegate::StartObserver() { | |
| 292 DCHECK(device_thread_checker_.CalledOnValidThread()); | |
| 293 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] | |
| 294 initWithChangeReceiver:this]); | |
| 295 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) | |
| 296 [suspend_observer_ startObserving:device]; | |
| 297 } | |
| 298 | |
| 299 void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() { | |
| 300 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 301 avfoundation_monitor_impl_ = NULL; | |
| 302 } | |
| 303 | |
| 304 void SuspendObserverDelegate::OnDeviceChangedOnUIThread( | |
| 305 const std::vector<DeviceInfo>& snapshot_devices) { | |
| 306 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 307 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before | 340 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before |
| 308 // arriving at this line. | 341 // arriving at this line. |
| 309 if (avfoundation_monitor_impl_) { | 342 if (avfoundation_monitor_impl_) { |
| 310 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( | 343 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( |
| 311 snapshot_devices); | 344 snapshot_devices); |
| 312 } | 345 } |
| 313 } | 346 } |
| 314 | 347 |
| 315 // AVFoundation implementation of the Mac Device Monitor, registers as a global | 348 // AVFoundation implementation of the Mac Device Monitor, registers as a global |
| 316 // device connect/disconnect observer and plugs suspend/wake up device observers | 349 // device connect/disconnect observer and plugs suspend/wake up device observers |
| 317 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_| | 350 // per device. This class is created and lives in UI thread. Owns a |
| 318 // and gets notified when a device is suspended/resumed. This class is created | 351 // SuspendObserverDelegate that notifies when a device is suspended/resumed. |
| 319 // and lives in UI thread; | |
| 320 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { | 352 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { |
| 321 public: | 353 public: |
| 322 AVFoundationMonitorImpl( | 354 AVFoundationMonitorImpl( |
| 323 content::DeviceMonitorMac* monitor, | 355 content::DeviceMonitorMac* monitor, |
| 324 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); | 356 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); |
| 325 virtual ~AVFoundationMonitorImpl(); | 357 virtual ~AVFoundationMonitorImpl(); |
| 326 | 358 |
| 327 virtual void OnDeviceChanged() OVERRIDE; | 359 virtual void OnDeviceChanged() OVERRIDE; |
| 328 | 360 |
| 329 private: | 361 private: |
| 330 base::ThreadChecker thread_checker_; | |
| 331 | |
| 332 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for | 362 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for |
| 333 // posting tasks to |suspend_observer_delegate_|; valid after | 363 // posting tasks to |suspend_observer_delegate_|; valid after |
| 334 // MediaStreamManager calls StartMonitoring(). | 364 // MediaStreamManager calls StartMonitoring(). |
| 335 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; | 365 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; |
| 336 | 366 |
| 337 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; | 367 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; |
| 338 | 368 |
| 339 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); | 369 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); |
| 340 }; | 370 }; |
| 341 | 371 |
| 342 AVFoundationMonitorImpl::AVFoundationMonitorImpl( | 372 AVFoundationMonitorImpl::AVFoundationMonitorImpl( |
| 343 content::DeviceMonitorMac* monitor, | 373 content::DeviceMonitorMac* monitor, |
| 344 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) | 374 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) |
| 345 : DeviceMonitorMacImpl(monitor), | 375 : DeviceMonitorMacImpl(monitor), |
| 346 device_task_runner_(device_task_runner), | 376 device_task_runner_(device_task_runner), |
| 347 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { | 377 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { |
| 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 348 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 379 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 349 device_arrival_ = | 380 device_arrival_ = |
| 350 [nc addObserverForName:AVFoundationGlue:: | 381 [nc addObserverForName:AVFoundationGlue:: |
| 351 AVCaptureDeviceWasConnectedNotification() | 382 AVCaptureDeviceWasConnectedNotification() |
| 352 object:nil | 383 object:nil |
| 353 queue:nil | 384 queue:nil |
| 354 usingBlock:^(NSNotification* notification) { | 385 usingBlock:^(NSNotification* notification) { |
| 355 OnDeviceChanged();}]; | 386 OnDeviceChanged();}]; |
| 356 device_removal_ = | 387 device_removal_ = |
| 357 [nc addObserverForName:AVFoundationGlue:: | 388 [nc addObserverForName:AVFoundationGlue:: |
| 358 AVCaptureDeviceWasDisconnectedNotification() | 389 AVCaptureDeviceWasDisconnectedNotification() |
| 359 object:nil | 390 object:nil |
| 360 queue:nil | 391 queue:nil |
| 361 usingBlock:^(NSNotification* notification) { | 392 usingBlock:^(NSNotification* notification) { |
| 362 OnDeviceChanged();}]; | 393 OnDeviceChanged();}]; |
| 363 device_task_runner_->PostTask(FROM_HERE, | 394 suspend_observer_delegate_->StartObserver(device_task_runner_); |
| 364 base::Bind(&SuspendObserverDelegate::StartObserver, | |
| 365 suspend_observer_delegate_)); | |
| 366 } | 395 } |
| 367 | 396 |
| 368 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { | 397 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { |
| 369 DCHECK(thread_checker_.CalledOnValidThread()); | 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 370 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread(); | 399 suspend_observer_delegate_->ResetDeviceMonitor(); |
| 371 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 400 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 372 [nc removeObserver:device_arrival_]; | 401 [nc removeObserver:device_arrival_]; |
| 373 [nc removeObserver:device_removal_]; | 402 [nc removeObserver:device_removal_]; |
| 374 } | 403 } |
| 375 | 404 |
| 376 void AVFoundationMonitorImpl::OnDeviceChanged() { | 405 void AVFoundationMonitorImpl::OnDeviceChanged() { |
| 377 DCHECK(thread_checker_.CalledOnValidThread()); | 406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 378 device_task_runner_->PostTask(FROM_HERE, | 407 suspend_observer_delegate_->OnDeviceChanged(device_task_runner_); |
| 379 base::Bind(&SuspendObserverDelegate::OnDeviceChanged, | |
| 380 suspend_observer_delegate_)); | |
| 381 } | 408 } |
| 382 | 409 |
| 383 } // namespace | 410 } // namespace |
| 384 | 411 |
| 385 @implementation CrAVFoundationDeviceObserver | 412 @implementation CrAVFoundationDeviceObserver |
| 386 | 413 |
| 387 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver { | 414 - (id)initWithOnChangedCallback:(const base::Closure&)callback { |
| 415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 388 if ((self = [super init])) { | 416 if ((self = [super init])) { |
| 389 DCHECK(receiver != NULL); | 417 DCHECK(!callback.is_null()); |
| 390 receiver_ = receiver; | 418 onDeviceChangedCallback_ = callback; |
| 391 } | 419 } |
| 392 return self; | 420 return self; |
| 393 } | 421 } |
| 394 | 422 |
| 395 - (void)dealloc { | 423 - (void)dealloc { |
| 396 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); | 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 425 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it = | |
| 426 monitoredDevices_.begin(); | |
| 397 while (it != monitoredDevices_.end()) | 427 while (it != monitoredDevices_.end()) |
| 398 [self stopObserving:*it++]; | 428 [self removeObservers:*(it++)]; |
| 399 [super dealloc]; | 429 [super dealloc]; |
| 400 } | 430 } |
| 401 | 431 |
| 402 - (void)startObserving:(CrAVCaptureDevice*)device { | 432 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device { |
| 433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 403 DCHECK(device != nil); | 434 DCHECK(device != nil); |
| 404 // Skip this device if there are already observers connected to it. | 435 // Skip this device if there are already observers connected to it. |
| 405 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != | 436 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != |
| 406 monitoredDevices_.end()) { | 437 monitoredDevices_.end()) { |
| 407 return; | 438 return; |
| 408 } | 439 } |
| 409 [device addObserver:self | 440 [device addObserver:self |
| 410 forKeyPath:@"suspended" | 441 forKeyPath:@"suspended" |
| 411 options:0 | 442 options:0 |
| 412 context:device]; | 443 context:device.get()]; |
| 413 [device addObserver:self | 444 [device addObserver:self |
| 414 forKeyPath:@"connected" | 445 forKeyPath:@"connected" |
| 415 options:0 | 446 options:0 |
| 416 context:device]; | 447 context:device.get()]; |
| 417 monitoredDevices_.insert(device); | 448 monitoredDevices_.insert(device); |
| 418 } | 449 } |
| 419 | 450 |
| 420 - (void)stopObserving:(CrAVCaptureDevice*)device { | 451 - (void)stopObserving:(const CrAVCaptureDevice*)device { |
|
Robert Sesek
2014/07/08 17:05:40
ObjC objects are never const.
mcasas
2014/07/09 08:27:33
Done.
| |
| 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 421 DCHECK(device != nil); | 453 DCHECK(device != nil); |
| 422 std::set<CrAVCaptureDevice*>::iterator found = | 454 |
| 455 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found = | |
| 423 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); | 456 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); |
| 424 DCHECK(found != monitoredDevices_.end()); | 457 DCHECK(found != monitoredDevices_.end()); |
| 425 // Every so seldom, |device| might be gone when getting here, in that case | 458 [self removeObservers:*found]; |
| 426 // removing the observer causes a crash. Try to avoid it by checking sanity of | 459 monitoredDevices_.erase(found); |
| 427 // the |device| via its -observationInfo. http://crbug.com/371271. | 460 } |
| 461 | |
| 462 - (void)clearOnDeviceChangedCallback { | |
| 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 464 onDeviceChangedCallback_.Reset(); | |
| 465 } | |
| 466 | |
| 467 - (void)removeObservers:(const CrAVCaptureDevice*)device { | |
| 468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 469 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271. | |
| 428 if ([device observationInfo]) { | 470 if ([device observationInfo]) { |
| 429 [device removeObserver:self | 471 [device removeObserver:self |
| 430 forKeyPath:@"suspended"]; | 472 forKeyPath:@"suspended"]; |
| 431 [device removeObserver:self | 473 [device removeObserver:self |
| 432 forKeyPath:@"connected"]; | 474 forKeyPath:@"connected"]; |
| 433 } | 475 } |
| 434 monitoredDevices_.erase(found); | |
| 435 } | 476 } |
| 436 | 477 |
| 437 - (void)observeValueForKeyPath:(NSString*)keyPath | 478 - (void)observeValueForKeyPath:(NSString*)keyPath |
| 438 ofObject:(id)object | 479 ofObject:(id)object |
| 439 change:(NSDictionary*)change | 480 change:(NSDictionary*)change |
| 440 context:(void*)context { | 481 context:(void*)context { |
| 482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 441 if ([keyPath isEqual:@"suspended"]) | 483 if ([keyPath isEqual:@"suspended"]) |
| 442 receiver_->OnDeviceChanged(); | 484 onDeviceChangedCallback_.Run(); |
| 443 if ([keyPath isEqual:@"connected"]) | 485 if ([keyPath isEqual:@"connected"]) |
| 444 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; | 486 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; |
| 445 } | 487 } |
| 446 | 488 |
| 447 @end // @implementation CrAVFoundationDeviceObserver | 489 @end // @implementation CrAVFoundationDeviceObserver |
| 448 | 490 |
| 449 namespace content { | 491 namespace content { |
| 450 | 492 |
| 451 DeviceMonitorMac::DeviceMonitorMac() { | 493 DeviceMonitorMac::DeviceMonitorMac() { |
| 452 // Both QTKit and AVFoundation do not need to be fired up until the user | 494 // Both QTKit and AVFoundation do not need to be fired up until the user |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 471 } | 513 } |
| 472 | 514 |
| 473 void DeviceMonitorMac::NotifyDeviceChanged( | 515 void DeviceMonitorMac::NotifyDeviceChanged( |
| 474 base::SystemMonitor::DeviceType type) { | 516 base::SystemMonitor::DeviceType type) { |
| 475 DCHECK(thread_checker_.CalledOnValidThread()); | 517 DCHECK(thread_checker_.CalledOnValidThread()); |
| 476 // TODO(xians): Remove the global variable for SystemMonitor. | 518 // TODO(xians): Remove the global variable for SystemMonitor. |
| 477 base::SystemMonitor::Get()->ProcessDevicesChanged(type); | 519 base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
| 478 } | 520 } |
| 479 | 521 |
| 480 } // namespace content | 522 } // namespace content |
| OLD | NEW |