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

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: rsesek@ and tommi@ comments 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"
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
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 void DoStartObserver(NSArray* devices);
257 const std::vector<DeviceInfo>& snapshot_devices); 270 void DoOnDeviceChanged(NSArray* devices);
tommi (sloooow) - chröme 2014/07/09 09:19:39 same for DoOnDeviceChanged
mcasas 2014/07/09 09:56:44 Done.
258 271
259 base::ThreadChecker device_thread_checker_;
260 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; 272 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
261 DeviceMonitorMacImpl* avfoundation_monitor_impl_; 273 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
262 }; 274 };
263 275
264 void SuspendObserverDelegate::OnDeviceChanged() { 276 SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
265 DCHECK(device_thread_checker_.CalledOnValidThread()); 277 : avfoundation_monitor_impl_(monitor) {
266 NSArray* devices = [AVCaptureDeviceGlue devices]; 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279 }
280
281 void SuspendObserverDelegate::StartObserver(
282 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284
285 base::Closure on_device_changed_callback =
286 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
287 this, device_thread);
288 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
289 initWithOnChangedCallback:on_device_changed_callback]);
290
291 base::PostTaskAndReplyWithResult(device_thread, FROM_HERE,
292 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
293 base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
294 }
295
296 void SuspendObserverDelegate::OnDeviceChanged(
297 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299 // Enumerate the devices in Device thread and post the consolidation of
300 // the devices and the old ones to be done on UI thread.
301 PostTaskAndReplyWithResult(device_thread, FROM_HERE,
302 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
303 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
304 }
305
306 void SuspendObserverDelegate::ResetDeviceMonitor() {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 avfoundation_monitor_impl_ = NULL;
309 [suspend_observer_ clearOnDeviceChangedCallback];
310 }
311
312 SuspendObserverDelegate::~SuspendObserverDelegate() {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
314 }
315
316 // DoStartObserver explicitly owns the devices array.
tommi (sloooow) - chröme 2014/07/09 09:19:40 nit: instead of "explicitly owns the devices array
mcasas 2014/07/09 09:56:44 Done.
317 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319 for (CrAVCaptureDevice* device in devices) {
320 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
321 [suspend_observer_ startObserving:device_ptr];
322 }
323 [devices release];
tommi (sloooow) - chröme 2014/07/09 09:19:40 another way to do this would be to create a scoped
mcasas 2014/07/09 09:56:44 Done.
324 }
325
326 // DoStartObserver explicitly owns the devices array.
327 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267 std::vector<DeviceInfo> snapshot_devices; 329 std::vector<DeviceInfo> snapshot_devices;
268 for (CrAVCaptureDevice* device in devices) { 330 for (CrAVCaptureDevice* device in devices) {
269 [suspend_observer_ startObserving:device]; 331 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
332 [suspend_observer_ startObserving:device_ptr];
333
270 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && 334 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
271 [device isSuspended]; 335 [device isSuspended];
272 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; 336 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
273 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { 337 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
274 if (suspended) 338 if (suspended)
275 continue; 339 continue;
276 device_type = DeviceInfo::kVideo; 340 device_type = DeviceInfo::kVideo;
277 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { 341 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
278 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; 342 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
279 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { 343 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
280 device_type = DeviceInfo::kAudio; 344 device_type = DeviceInfo::kAudio;
281 } 345 }
282 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], 346 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
283 device_type)); 347 device_type));
284 } 348 }
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 349
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 350 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before
308 // arriving at this line. 351 // arriving at this line.
309 if (avfoundation_monitor_impl_) { 352 if (avfoundation_monitor_impl_) {
310 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( 353 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
311 snapshot_devices); 354 snapshot_devices);
312 } 355 }
356 [devices release];
tommi (sloooow) - chröme 2014/07/09 09:19:40 I would prefer the scoped_nsobject<> approach to r
mcasas 2014/07/09 09:56:44 Done.
313 } 357 }
314 358
315 // AVFoundation implementation of the Mac Device Monitor, registers as a global 359 // AVFoundation implementation of the Mac Device Monitor, registers as a global
316 // device connect/disconnect observer and plugs suspend/wake up device observers 360 // device connect/disconnect observer and plugs suspend/wake up device observers
317 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_| 361 // 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 362 // SuspendObserverDelegate that notifies when a device is suspended/resumed.
319 // and lives in UI thread;
320 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 363 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
321 public: 364 public:
322 AVFoundationMonitorImpl( 365 AVFoundationMonitorImpl(
323 content::DeviceMonitorMac* monitor, 366 content::DeviceMonitorMac* monitor,
324 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 367 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
325 virtual ~AVFoundationMonitorImpl(); 368 virtual ~AVFoundationMonitorImpl();
326 369
327 virtual void OnDeviceChanged() OVERRIDE; 370 virtual void OnDeviceChanged() OVERRIDE;
328 371
329 private: 372 private:
330 base::ThreadChecker thread_checker_;
331
332 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 373 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
333 // posting tasks to |suspend_observer_delegate_|; valid after 374 // posting tasks to |suspend_observer_delegate_|; valid after
334 // MediaStreamManager calls StartMonitoring(). 375 // MediaStreamManager calls StartMonitoring().
335 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 376 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
336 377
337 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; 378 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
338 379
339 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 380 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
340 }; 381 };
341 382
342 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 383 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
343 content::DeviceMonitorMac* monitor, 384 content::DeviceMonitorMac* monitor,
344 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 385 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
345 : DeviceMonitorMacImpl(monitor), 386 : DeviceMonitorMacImpl(monitor),
346 device_task_runner_(device_task_runner), 387 device_task_runner_(device_task_runner),
347 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { 388 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 390 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
349 device_arrival_ = 391 device_arrival_ =
350 [nc addObserverForName:AVFoundationGlue:: 392 [nc addObserverForName:AVFoundationGlue::
351 AVCaptureDeviceWasConnectedNotification() 393 AVCaptureDeviceWasConnectedNotification()
352 object:nil 394 object:nil
353 queue:nil 395 queue:nil
354 usingBlock:^(NSNotification* notification) { 396 usingBlock:^(NSNotification* notification) {
355 OnDeviceChanged();}]; 397 OnDeviceChanged();}];
356 device_removal_ = 398 device_removal_ =
357 [nc addObserverForName:AVFoundationGlue:: 399 [nc addObserverForName:AVFoundationGlue::
358 AVCaptureDeviceWasDisconnectedNotification() 400 AVCaptureDeviceWasDisconnectedNotification()
359 object:nil 401 object:nil
360 queue:nil 402 queue:nil
361 usingBlock:^(NSNotification* notification) { 403 usingBlock:^(NSNotification* notification) {
362 OnDeviceChanged();}]; 404 OnDeviceChanged();}];
363 device_task_runner_->PostTask(FROM_HERE, 405 suspend_observer_delegate_->StartObserver(device_task_runner_);
364 base::Bind(&SuspendObserverDelegate::StartObserver,
365 suspend_observer_delegate_));
366 } 406 }
367 407
368 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 408 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
369 DCHECK(thread_checker_.CalledOnValidThread()); 409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread(); 410 suspend_observer_delegate_->ResetDeviceMonitor();
371 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 411 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
372 [nc removeObserver:device_arrival_]; 412 [nc removeObserver:device_arrival_];
373 [nc removeObserver:device_removal_]; 413 [nc removeObserver:device_removal_];
374 } 414 }
375 415
376 void AVFoundationMonitorImpl::OnDeviceChanged() { 416 void AVFoundationMonitorImpl::OnDeviceChanged() {
377 DCHECK(thread_checker_.CalledOnValidThread()); 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 device_task_runner_->PostTask(FROM_HERE, 418 suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
379 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
380 suspend_observer_delegate_));
381 } 419 }
382 420
383 } // namespace 421 } // namespace
384 422
385 @implementation CrAVFoundationDeviceObserver 423 @implementation CrAVFoundationDeviceObserver
386 424
387 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver { 425 - (id)initWithOnChangedCallback:(const base::Closure&)callback {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388 if ((self = [super init])) { 427 if ((self = [super init])) {
389 DCHECK(receiver != NULL); 428 DCHECK(!callback.is_null());
390 receiver_ = receiver; 429 onDeviceChangedCallback_ = callback;
391 } 430 }
392 return self; 431 return self;
393 } 432 }
394 433
395 - (void)dealloc { 434 - (void)dealloc {
396 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
436 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
437 monitoredDevices_.begin();
397 while (it != monitoredDevices_.end()) 438 while (it != monitoredDevices_.end())
398 [self stopObserving:*it++]; 439 [self removeObservers:*(it++)];
399 [super dealloc]; 440 [super dealloc];
400 } 441 }
401 442
402 - (void)startObserving:(CrAVCaptureDevice*)device { 443 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403 DCHECK(device != nil); 445 DCHECK(device != nil);
404 // Skip this device if there are already observers connected to it. 446 // Skip this device if there are already observers connected to it.
405 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != 447 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
406 monitoredDevices_.end()) { 448 monitoredDevices_.end()) {
407 return; 449 return;
408 } 450 }
409 [device addObserver:self 451 [device addObserver:self
410 forKeyPath:@"suspended" 452 forKeyPath:@"suspended"
411 options:0 453 options:0
412 context:device]; 454 context:device.get()];
413 [device addObserver:self 455 [device addObserver:self
414 forKeyPath:@"connected" 456 forKeyPath:@"connected"
415 options:0 457 options:0
416 context:device]; 458 context:device.get()];
417 monitoredDevices_.insert(device); 459 monitoredDevices_.insert(device);
418 } 460 }
419 461
420 - (void)stopObserving:(CrAVCaptureDevice*)device { 462 - (void)stopObserving:(CrAVCaptureDevice*)device {
463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 DCHECK(device != nil); 464 DCHECK(device != nil);
422 std::set<CrAVCaptureDevice*>::iterator found = 465
466 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
423 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); 467 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
424 DCHECK(found != monitoredDevices_.end()); 468 DCHECK(found != monitoredDevices_.end());
425 // Every so seldom, |device| might be gone when getting here, in that case 469 [self removeObservers:*found];
426 // removing the observer causes a crash. Try to avoid it by checking sanity of 470 monitoredDevices_.erase(found);
427 // the |device| via its -observationInfo. http://crbug.com/371271. 471 }
472
473 - (void)clearOnDeviceChangedCallback {
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
475 onDeviceChangedCallback_.Reset();
476 }
477
478 - (void)removeObservers:(CrAVCaptureDevice*)device {
479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
480 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
428 if ([device observationInfo]) { 481 if ([device observationInfo]) {
429 [device removeObserver:self 482 [device removeObserver:self
430 forKeyPath:@"suspended"]; 483 forKeyPath:@"suspended"];
431 [device removeObserver:self 484 [device removeObserver:self
432 forKeyPath:@"connected"]; 485 forKeyPath:@"connected"];
433 } 486 }
434 monitoredDevices_.erase(found);
435 } 487 }
436 488
437 - (void)observeValueForKeyPath:(NSString*)keyPath 489 - (void)observeValueForKeyPath:(NSString*)keyPath
438 ofObject:(id)object 490 ofObject:(id)object
439 change:(NSDictionary*)change 491 change:(NSDictionary*)change
440 context:(void*)context { 492 context:(void*)context {
493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441 if ([keyPath isEqual:@"suspended"]) 494 if ([keyPath isEqual:@"suspended"])
442 receiver_->OnDeviceChanged(); 495 onDeviceChangedCallback_.Run();
443 if ([keyPath isEqual:@"connected"]) 496 if ([keyPath isEqual:@"connected"])
444 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; 497 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
445 } 498 }
446 499
447 @end // @implementation CrAVFoundationDeviceObserver 500 @end // @implementation CrAVFoundationDeviceObserver
448 501
449 namespace content { 502 namespace content {
450 503
451 DeviceMonitorMac::DeviceMonitorMac() { 504 DeviceMonitorMac::DeviceMonitorMac() {
452 // Both QTKit and AVFoundation do not need to be fired up until the user 505 // Both QTKit and AVFoundation do not need to be fired up until the user
(...skipping 18 matching lines...) Expand all
471 } 524 }
472 525
473 void DeviceMonitorMac::NotifyDeviceChanged( 526 void DeviceMonitorMac::NotifyDeviceChanged(
474 base::SystemMonitor::DeviceType type) { 527 base::SystemMonitor::DeviceType type) {
475 DCHECK(thread_checker_.CalledOnValidThread()); 528 DCHECK(thread_checker_.CalledOnValidThread());
476 // TODO(xians): Remove the global variable for SystemMonitor. 529 // TODO(xians): Remove the global variable for SystemMonitor.
477 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 530 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
478 } 531 }
479 532
480 } // namespace content 533 } // 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