Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Side by Side Diff: content/browser/device_monitor_mac.mm

Issue 368613002: DeviceMonitorMac: move CrAVFoundationDeviceObserver and most of SuspendObserverDelegate to UI Thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments and using scoped_nsobject<> for auto releasing |devices| Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
jochen (gone - plz use gerrit) 2014/07/11 12:55:22 should not be needed?
mcasas 2014/07/11 13:11:28 Done.
16 #import "media/video/capture/mac/avfoundation_glue.h" 18 #import "media/video/capture/mac/avfoundation_glue.h"
17 19
20 using content::BrowserThread;
jochen (gone - plz use gerrit) 2014/07/11 12:55:22 no using content inside content. the entire file s
mcasas 2014/07/11 13:11:28 Objective-C++ classes cannot go inside a namespace
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
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:(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 on 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 // Create |suspend_observer_| for all devices and register OnDeviceChanged()
248 void StartObserver(); 252 // as its change callback. Schedule bottom half in DoStartObserver().
249 void ResetDeviceMonitorOnUIThread(); 253 void StartObserver(
254 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
255 // Enumerate devices in |device_thread| and run the bottom half in
256 // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event,
257 // and our parent AVFoundationMonitorImpl calls on connect/disconnect device.
258 void OnDeviceChanged(
259 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
260 // Remove the device monitor's weak reference. Remove ourselves as suspend
261 // notification observer from |suspend_observer_|.
262 void ResetDeviceMonitor();
250 263
251 private: 264 private:
252 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; 265 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
253 266
254 virtual ~SuspendObserverDelegate() {} 267 virtual ~SuspendObserverDelegate();
255 268
256 void OnDeviceChangedOnUIThread( 269 // Bottom half of StartObserver(), starts |suspend_observer_| for all devices.
257 const std::vector<DeviceInfo>& snapshot_devices); 270 // Assumes that |devices| has been retained prior to being called, and
271 // releases it internally.
272 void DoStartObserver(NSArray* devices);
273 // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current
274 // devices and composes a snapshot of them to send it to
275 // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained
276 // prior to being called, and releases it internally.
277 void DoOnDeviceChanged(NSArray* devices);
258 278
259 base::ThreadChecker device_thread_checker_;
260 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; 279 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
261 DeviceMonitorMacImpl* avfoundation_monitor_impl_; 280 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
262 }; 281 };
263 282
264 void SuspendObserverDelegate::OnDeviceChanged() { 283 SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
265 DCHECK(device_thread_checker_.CalledOnValidThread()); 284 : avfoundation_monitor_impl_(monitor) {
266 NSArray* devices = [AVCaptureDeviceGlue devices]; 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286 }
287
288 void SuspendObserverDelegate::StartObserver(
289 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291
292 base::Closure on_device_changed_callback =
293 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
294 this, device_thread);
295 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
296 initWithOnChangedCallback:on_device_changed_callback]);
297
298 // Enumerate the devices in Device thread and post the observers start to be
299 // done on UI thread. The devices array is retained in |device_thread| and
300 // released in DoStartObserver().
301 base::PostTaskAndReplyWithResult(device_thread, FROM_HERE,
302 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
303 base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
304 }
305
306 void SuspendObserverDelegate::OnDeviceChanged(
307 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309 // Enumerate the devices in Device thread and post the consolidation of the
310 // new devices and the old ones to be done on UI thread. The devices array
311 // is retained in |device_thread| and released in DoOnDeviceChanged().
312 PostTaskAndReplyWithResult(device_thread, FROM_HERE,
313 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
314 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
315 }
316
317 void SuspendObserverDelegate::ResetDeviceMonitor() {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319 avfoundation_monitor_impl_ = NULL;
320 [suspend_observer_ clearOnDeviceChangedCallback];
321 }
322
323 SuspendObserverDelegate::~SuspendObserverDelegate() {
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
325 }
326
327 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329 base::scoped_nsobject<NSArray> auto_release(devices);
330 for (CrAVCaptureDevice* device in devices) {
331 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
332 [suspend_observer_ startObserving:device_ptr];
333 }
334 }
335
336 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338 base::scoped_nsobject<NSArray> auto_release(devices);
267 std::vector<DeviceInfo> snapshot_devices; 339 std::vector<DeviceInfo> snapshot_devices;
268 for (CrAVCaptureDevice* device in devices) { 340 for (CrAVCaptureDevice* device in devices) {
269 [suspend_observer_ startObserving:device]; 341 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
342 [suspend_observer_ startObserving:device_ptr];
343
270 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && 344 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
271 [device isSuspended]; 345 [device isSuspended];
272 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; 346 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
273 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { 347 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
274 if (suspended) 348 if (suspended)
275 continue; 349 continue;
276 device_type = DeviceInfo::kVideo; 350 device_type = DeviceInfo::kVideo;
277 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { 351 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
278 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; 352 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
279 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { 353 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
280 device_type = DeviceInfo::kAudio; 354 device_type = DeviceInfo::kAudio;
281 } 355 }
282 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], 356 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
283 device_type)); 357 device_type));
284 } 358 }
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 359
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 360 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before
308 // arriving at this line. 361 // arriving at this line.
309 if (avfoundation_monitor_impl_) { 362 if (avfoundation_monitor_impl_) {
310 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( 363 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
311 snapshot_devices); 364 snapshot_devices);
312 } 365 }
313 } 366 }
314 367
315 // AVFoundation implementation of the Mac Device Monitor, registers as a global 368 // AVFoundation implementation of the Mac Device Monitor, registers as a global
316 // device connect/disconnect observer and plugs suspend/wake up device observers 369 // device connect/disconnect observer and plugs suspend/wake up device observers
317 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_| 370 // 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 371 // SuspendObserverDelegate that notifies when a device is suspended/resumed.
319 // and lives in UI thread;
320 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 372 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
321 public: 373 public:
322 AVFoundationMonitorImpl( 374 AVFoundationMonitorImpl(
323 content::DeviceMonitorMac* monitor, 375 content::DeviceMonitorMac* monitor,
324 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 376 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
325 virtual ~AVFoundationMonitorImpl(); 377 virtual ~AVFoundationMonitorImpl();
326 378
327 virtual void OnDeviceChanged() OVERRIDE; 379 virtual void OnDeviceChanged() OVERRIDE;
328 380
329 private: 381 private:
330 base::ThreadChecker thread_checker_;
331
332 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 382 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
333 // posting tasks to |suspend_observer_delegate_|; valid after 383 // posting tasks to |suspend_observer_delegate_|; valid after
334 // MediaStreamManager calls StartMonitoring(). 384 // MediaStreamManager calls StartMonitoring().
335 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 385 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
336 386
337 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; 387 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
338 388
339 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 389 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
340 }; 390 };
341 391
342 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 392 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
343 content::DeviceMonitorMac* monitor, 393 content::DeviceMonitorMac* monitor,
344 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 394 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
345 : DeviceMonitorMacImpl(monitor), 395 : DeviceMonitorMacImpl(monitor),
346 device_task_runner_(device_task_runner), 396 device_task_runner_(device_task_runner),
347 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { 397 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 399 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
349 device_arrival_ = 400 device_arrival_ =
350 [nc addObserverForName:AVFoundationGlue:: 401 [nc addObserverForName:AVFoundationGlue::
351 AVCaptureDeviceWasConnectedNotification() 402 AVCaptureDeviceWasConnectedNotification()
352 object:nil 403 object:nil
353 queue:nil 404 queue:nil
354 usingBlock:^(NSNotification* notification) { 405 usingBlock:^(NSNotification* notification) {
355 OnDeviceChanged();}]; 406 OnDeviceChanged();}];
356 device_removal_ = 407 device_removal_ =
357 [nc addObserverForName:AVFoundationGlue:: 408 [nc addObserverForName:AVFoundationGlue::
358 AVCaptureDeviceWasDisconnectedNotification() 409 AVCaptureDeviceWasDisconnectedNotification()
359 object:nil 410 object:nil
360 queue:nil 411 queue:nil
361 usingBlock:^(NSNotification* notification) { 412 usingBlock:^(NSNotification* notification) {
362 OnDeviceChanged();}]; 413 OnDeviceChanged();}];
363 device_task_runner_->PostTask(FROM_HERE, 414 suspend_observer_delegate_->StartObserver(device_task_runner_);
364 base::Bind(&SuspendObserverDelegate::StartObserver,
365 suspend_observer_delegate_));
366 } 415 }
367 416
368 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 417 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
369 DCHECK(thread_checker_.CalledOnValidThread()); 418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread(); 419 suspend_observer_delegate_->ResetDeviceMonitor();
371 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 420 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
372 [nc removeObserver:device_arrival_]; 421 [nc removeObserver:device_arrival_];
373 [nc removeObserver:device_removal_]; 422 [nc removeObserver:device_removal_];
374 } 423 }
375 424
376 void AVFoundationMonitorImpl::OnDeviceChanged() { 425 void AVFoundationMonitorImpl::OnDeviceChanged() {
377 DCHECK(thread_checker_.CalledOnValidThread()); 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 device_task_runner_->PostTask(FROM_HERE, 427 suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
379 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
380 suspend_observer_delegate_));
381 } 428 }
382 429
383 } // namespace 430 } // namespace
384 431
385 @implementation CrAVFoundationDeviceObserver 432 @implementation CrAVFoundationDeviceObserver
386 433
387 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver { 434 - (id)initWithOnChangedCallback:(const base::Closure&)callback {
435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388 if ((self = [super init])) { 436 if ((self = [super init])) {
389 DCHECK(receiver != NULL); 437 DCHECK(!callback.is_null());
390 receiver_ = receiver; 438 onDeviceChangedCallback_ = callback;
391 } 439 }
392 return self; 440 return self;
393 } 441 }
394 442
395 - (void)dealloc { 443 - (void)dealloc {
396 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
445 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
446 monitoredDevices_.begin();
397 while (it != monitoredDevices_.end()) 447 while (it != monitoredDevices_.end())
398 [self stopObserving:*it++]; 448 [self removeObservers:*(it++)];
399 [super dealloc]; 449 [super dealloc];
400 } 450 }
401 451
402 - (void)startObserving:(CrAVCaptureDevice*)device { 452 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403 DCHECK(device != nil); 454 DCHECK(device != nil);
404 // Skip this device if there are already observers connected to it. 455 // Skip this device if there are already observers connected to it.
405 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != 456 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
406 monitoredDevices_.end()) { 457 monitoredDevices_.end()) {
407 return; 458 return;
408 } 459 }
409 [device addObserver:self 460 [device addObserver:self
410 forKeyPath:@"suspended" 461 forKeyPath:@"suspended"
411 options:0 462 options:0
412 context:device]; 463 context:device.get()];
413 [device addObserver:self 464 [device addObserver:self
414 forKeyPath:@"connected" 465 forKeyPath:@"connected"
415 options:0 466 options:0
416 context:device]; 467 context:device.get()];
417 monitoredDevices_.insert(device); 468 monitoredDevices_.insert(device);
418 } 469 }
419 470
420 - (void)stopObserving:(CrAVCaptureDevice*)device { 471 - (void)stopObserving:(CrAVCaptureDevice*)device {
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 DCHECK(device != nil); 473 DCHECK(device != nil);
422 std::set<CrAVCaptureDevice*>::iterator found = 474
475 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
423 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); 476 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
424 DCHECK(found != monitoredDevices_.end()); 477 DCHECK(found != monitoredDevices_.end());
425 // Every so seldom, |device| might be gone when getting here, in that case 478 [self removeObservers:*found];
426 // removing the observer causes a crash. Try to avoid it by checking sanity of 479 monitoredDevices_.erase(found);
427 // the |device| via its -observationInfo. http://crbug.com/371271. 480 }
481
482 - (void)clearOnDeviceChangedCallback {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484 onDeviceChangedCallback_.Reset();
485 }
486
487 - (void)removeObservers:(CrAVCaptureDevice*)device {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
489 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
428 if ([device observationInfo]) { 490 if ([device observationInfo]) {
429 [device removeObserver:self 491 [device removeObserver:self
430 forKeyPath:@"suspended"]; 492 forKeyPath:@"suspended"];
431 [device removeObserver:self 493 [device removeObserver:self
432 forKeyPath:@"connected"]; 494 forKeyPath:@"connected"];
433 } 495 }
434 monitoredDevices_.erase(found);
435 } 496 }
436 497
437 - (void)observeValueForKeyPath:(NSString*)keyPath 498 - (void)observeValueForKeyPath:(NSString*)keyPath
438 ofObject:(id)object 499 ofObject:(id)object
439 change:(NSDictionary*)change 500 change:(NSDictionary*)change
440 context:(void*)context { 501 context:(void*)context {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441 if ([keyPath isEqual:@"suspended"]) 503 if ([keyPath isEqual:@"suspended"])
442 receiver_->OnDeviceChanged(); 504 onDeviceChangedCallback_.Run();
443 if ([keyPath isEqual:@"connected"]) 505 if ([keyPath isEqual:@"connected"])
444 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; 506 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
445 } 507 }
446 508
447 @end // @implementation CrAVFoundationDeviceObserver 509 @end // @implementation CrAVFoundationDeviceObserver
448 510
449 namespace content { 511 namespace content {
450 512
451 DeviceMonitorMac::DeviceMonitorMac() { 513 DeviceMonitorMac::DeviceMonitorMac() {
452 // Both QTKit and AVFoundation do not need to be fired up until the user 514 // Both QTKit and AVFoundation do not need to be fired up until the user
(...skipping 18 matching lines...) Expand all
471 } 533 }
472 534
473 void DeviceMonitorMac::NotifyDeviceChanged( 535 void DeviceMonitorMac::NotifyDeviceChanged(
474 base::SystemMonitor::DeviceType type) { 536 base::SystemMonitor::DeviceType type) {
475 DCHECK(thread_checker_.CalledOnValidThread()); 537 DCHECK(thread_checker_.CalledOnValidThread());
476 // TODO(xians): Remove the global variable for SystemMonitor. 538 // TODO(xians): Remove the global variable for SystemMonitor.
477 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 539 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
478 } 540 }
479 541
480 } // namespace content 542 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698