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

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: jochen@ 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"
16 #import "media/video/capture/mac/avfoundation_glue.h" 17 #import "media/video/capture/mac/avfoundation_glue.h"
17 18
19 using content::BrowserThread;
20
18 namespace { 21 namespace {
19 22
20 // This class is used to keep track of system devices names and their types. 23 // This class is used to keep track of system devices names and their types.
21 class DeviceInfo { 24 class DeviceInfo {
22 public: 25 public:
23 enum DeviceType { 26 enum DeviceType {
24 kAudio, 27 kAudio,
25 kVideo, 28 kVideo,
26 kMuxed, 29 kMuxed,
27 kUnknown, 30 kUnknown,
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 ConsolidateDevicesListAndNotify(snapshot_devices); 212 ConsolidateDevicesListAndNotify(snapshot_devices);
210 } 213 }
211 214
212 // Forward declaration for use by CrAVFoundationDeviceObserver. 215 // Forward declaration for use by CrAVFoundationDeviceObserver.
213 class SuspendObserverDelegate; 216 class SuspendObserverDelegate;
214 217
215 } // namespace 218 } // namespace
216 219
217 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ 220 // This class is a Key-Value Observer (KVO) shim. It is needed because C++
218 // classes cannot observe Key-Values directly. Created, manipulated, and 221 // classes cannot observe Key-Values directly. Created, manipulated, and
219 // destroyed on the Device Thread by SuspendedObserverDelegate. 222 // destroyed on the UI Thread by SuspendObserverDelegate.
220 @interface CrAVFoundationDeviceObserver : NSObject { 223 @interface CrAVFoundationDeviceObserver : NSObject {
221 @private 224 @private
222 SuspendObserverDelegate* receiver_; // weak 225 // Callback for device changed, has to run on Device Thread.
226 base::Closure onDeviceChangedCallback_;
227
223 // Member to keep track of the devices we are already monitoring. 228 // Member to keep track of the devices we are already monitoring.
224 std::set<CrAVCaptureDevice*> monitoredDevices_; 229 std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_;
225 } 230 }
226 231
227 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver; 232 - (id)initWithOnChangedCallback:(const base::Closure&)callback;
228 - (void)startObserving:(CrAVCaptureDevice*)device; 233 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device;
229 - (void)stopObserving:(CrAVCaptureDevice*)device; 234 - (void)stopObserving:(CrAVCaptureDevice*)device;
235 - (void)clearOnDeviceChangedCallback;
230 236
231 @end 237 @end
232 238
233 namespace { 239 namespace {
234 240
235 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. 241 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
236 // Provides a callback for this device observer to indicate that there has been 242 // 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 243 // operates on this thread except for the expensive device enumerations which
238 // but living in Device Thread. 244 // are run on Device Thread.
239 class SuspendObserverDelegate : 245 class SuspendObserverDelegate :
240 public base::RefCountedThreadSafe<SuspendObserverDelegate> { 246 public base::RefCountedThreadSafe<SuspendObserverDelegate> {
241 public: 247 public:
242 explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) 248 explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor);
243 : avfoundation_monitor_impl_(monitor) {
244 device_thread_checker_.DetachFromThread();
245 }
246 249
247 void OnDeviceChanged(); 250 // Create |suspend_observer_| for all devices and register OnDeviceChanged()
248 void StartObserver(); 251 // as its change callback. Schedule bottom half in DoStartObserver().
249 void ResetDeviceMonitorOnUIThread(); 252 void StartObserver(
253 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
254 // Enumerate devices in |device_thread| and run the bottom half in
255 // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event,
256 // and our parent AVFoundationMonitorImpl calls on connect/disconnect device.
257 void OnDeviceChanged(
258 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
259 // Remove the device monitor's weak reference. Remove ourselves as suspend
260 // notification observer from |suspend_observer_|.
261 void ResetDeviceMonitor();
250 262
251 private: 263 private:
252 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; 264 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
253 265
254 virtual ~SuspendObserverDelegate() {} 266 virtual ~SuspendObserverDelegate();
255 267
256 void OnDeviceChangedOnUIThread( 268 // Bottom half of StartObserver(), starts |suspend_observer_| for all devices.
257 const std::vector<DeviceInfo>& snapshot_devices); 269 // Assumes that |devices| has been retained prior to being called, and
270 // releases it internally.
271 void DoStartObserver(NSArray* devices);
272 // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current
273 // devices and composes a snapshot of them to send it to
274 // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained
275 // prior to being called, and releases it internally.
276 void DoOnDeviceChanged(NSArray* devices);
258 277
259 base::ThreadChecker device_thread_checker_;
260 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; 278 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
261 DeviceMonitorMacImpl* avfoundation_monitor_impl_; 279 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
262 }; 280 };
263 281
264 void SuspendObserverDelegate::OnDeviceChanged() { 282 SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
265 DCHECK(device_thread_checker_.CalledOnValidThread()); 283 : avfoundation_monitor_impl_(monitor) {
266 NSArray* devices = [AVCaptureDeviceGlue devices]; 284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
285 }
286
287 void SuspendObserverDelegate::StartObserver(
288 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290
291 base::Closure on_device_changed_callback =
292 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
293 this, device_thread);
294 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
295 initWithOnChangedCallback:on_device_changed_callback]);
296
297 // Enumerate the devices in Device thread and post the observers start to be
298 // done on UI thread. The devices array is retained in |device_thread| and
299 // released in DoStartObserver().
300 base::PostTaskAndReplyWithResult(device_thread, FROM_HERE,
301 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
302 base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
303 }
304
305 void SuspendObserverDelegate::OnDeviceChanged(
306 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 // Enumerate the devices in Device thread and post the consolidation of the
309 // new devices and the old ones to be done on UI thread. The devices array
310 // is retained in |device_thread| and released in DoOnDeviceChanged().
311 PostTaskAndReplyWithResult(device_thread, FROM_HERE,
312 base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
313 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
314 }
315
316 void SuspendObserverDelegate::ResetDeviceMonitor() {
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
318 avfoundation_monitor_impl_ = NULL;
319 [suspend_observer_ clearOnDeviceChangedCallback];
320 }
321
322 SuspendObserverDelegate::~SuspendObserverDelegate() {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
324 }
325
326 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328 base::scoped_nsobject<NSArray> auto_release(devices);
329 for (CrAVCaptureDevice* device in devices) {
330 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
331 [suspend_observer_ startObserving:device_ptr];
332 }
333 }
334
335 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
337 base::scoped_nsobject<NSArray> auto_release(devices);
267 std::vector<DeviceInfo> snapshot_devices; 338 std::vector<DeviceInfo> snapshot_devices;
268 for (CrAVCaptureDevice* device in devices) { 339 for (CrAVCaptureDevice* device in devices) {
269 [suspend_observer_ startObserving:device]; 340 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
341 [suspend_observer_ startObserving:device_ptr];
342
270 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && 343 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
271 [device isSuspended]; 344 [device isSuspended];
272 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; 345 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
273 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { 346 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
274 if (suspended) 347 if (suspended)
275 continue; 348 continue;
276 device_type = DeviceInfo::kVideo; 349 device_type = DeviceInfo::kVideo;
277 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { 350 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
278 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; 351 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
279 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { 352 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
280 device_type = DeviceInfo::kAudio; 353 device_type = DeviceInfo::kAudio;
281 } 354 }
282 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], 355 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
283 device_type)); 356 device_type));
284 } 357 }
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 358
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 359 // |avfoundation_monitor_impl_| might have been NULLed asynchronously before
308 // arriving at this line. 360 // arriving at this line.
309 if (avfoundation_monitor_impl_) { 361 if (avfoundation_monitor_impl_) {
310 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( 362 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
311 snapshot_devices); 363 snapshot_devices);
312 } 364 }
313 } 365 }
314 366
315 // AVFoundation implementation of the Mac Device Monitor, registers as a global 367 // AVFoundation implementation of the Mac Device Monitor, registers as a global
316 // device connect/disconnect observer and plugs suspend/wake up device observers 368 // device connect/disconnect observer and plugs suspend/wake up device observers
317 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_| 369 // 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 370 // SuspendObserverDelegate that notifies when a device is suspended/resumed.
319 // and lives in UI thread;
320 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 371 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
321 public: 372 public:
322 AVFoundationMonitorImpl( 373 AVFoundationMonitorImpl(
323 content::DeviceMonitorMac* monitor, 374 content::DeviceMonitorMac* monitor,
324 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 375 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
325 virtual ~AVFoundationMonitorImpl(); 376 virtual ~AVFoundationMonitorImpl();
326 377
327 virtual void OnDeviceChanged() OVERRIDE; 378 virtual void OnDeviceChanged() OVERRIDE;
328 379
329 private: 380 private:
330 base::ThreadChecker thread_checker_;
331
332 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 381 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
333 // posting tasks to |suspend_observer_delegate_|; valid after 382 // posting tasks to |suspend_observer_delegate_|; valid after
334 // MediaStreamManager calls StartMonitoring(). 383 // MediaStreamManager calls StartMonitoring().
335 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 384 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
336 385
337 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; 386 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
338 387
339 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 388 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
340 }; 389 };
341 390
342 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 391 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
343 content::DeviceMonitorMac* monitor, 392 content::DeviceMonitorMac* monitor,
344 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 393 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
345 : DeviceMonitorMacImpl(monitor), 394 : DeviceMonitorMacImpl(monitor),
346 device_task_runner_(device_task_runner), 395 device_task_runner_(device_task_runner),
347 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { 396 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 398 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
349 device_arrival_ = 399 device_arrival_ =
350 [nc addObserverForName:AVFoundationGlue:: 400 [nc addObserverForName:AVFoundationGlue::
351 AVCaptureDeviceWasConnectedNotification() 401 AVCaptureDeviceWasConnectedNotification()
352 object:nil 402 object:nil
353 queue:nil 403 queue:nil
354 usingBlock:^(NSNotification* notification) { 404 usingBlock:^(NSNotification* notification) {
355 OnDeviceChanged();}]; 405 OnDeviceChanged();}];
356 device_removal_ = 406 device_removal_ =
357 [nc addObserverForName:AVFoundationGlue:: 407 [nc addObserverForName:AVFoundationGlue::
358 AVCaptureDeviceWasDisconnectedNotification() 408 AVCaptureDeviceWasDisconnectedNotification()
359 object:nil 409 object:nil
360 queue:nil 410 queue:nil
361 usingBlock:^(NSNotification* notification) { 411 usingBlock:^(NSNotification* notification) {
362 OnDeviceChanged();}]; 412 OnDeviceChanged();}];
363 device_task_runner_->PostTask(FROM_HERE, 413 suspend_observer_delegate_->StartObserver(device_task_runner_);
364 base::Bind(&SuspendObserverDelegate::StartObserver,
365 suspend_observer_delegate_));
366 } 414 }
367 415
368 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 416 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
369 DCHECK(thread_checker_.CalledOnValidThread()); 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread(); 418 suspend_observer_delegate_->ResetDeviceMonitor();
371 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 419 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
372 [nc removeObserver:device_arrival_]; 420 [nc removeObserver:device_arrival_];
373 [nc removeObserver:device_removal_]; 421 [nc removeObserver:device_removal_];
374 } 422 }
375 423
376 void AVFoundationMonitorImpl::OnDeviceChanged() { 424 void AVFoundationMonitorImpl::OnDeviceChanged() {
377 DCHECK(thread_checker_.CalledOnValidThread()); 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 device_task_runner_->PostTask(FROM_HERE, 426 suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
379 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
380 suspend_observer_delegate_));
381 } 427 }
382 428
383 } // namespace 429 } // namespace
384 430
385 @implementation CrAVFoundationDeviceObserver 431 @implementation CrAVFoundationDeviceObserver
386 432
387 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver { 433 - (id)initWithOnChangedCallback:(const base::Closure&)callback {
434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388 if ((self = [super init])) { 435 if ((self = [super init])) {
389 DCHECK(receiver != NULL); 436 DCHECK(!callback.is_null());
390 receiver_ = receiver; 437 onDeviceChangedCallback_ = callback;
391 } 438 }
392 return self; 439 return self;
393 } 440 }
394 441
395 - (void)dealloc { 442 - (void)dealloc {
396 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
445 monitoredDevices_.begin();
397 while (it != monitoredDevices_.end()) 446 while (it != monitoredDevices_.end())
398 [self stopObserving:*it++]; 447 [self removeObservers:*(it++)];
399 [super dealloc]; 448 [super dealloc];
400 } 449 }
401 450
402 - (void)startObserving:(CrAVCaptureDevice*)device { 451 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403 DCHECK(device != nil); 453 DCHECK(device != nil);
404 // Skip this device if there are already observers connected to it. 454 // Skip this device if there are already observers connected to it.
405 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != 455 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
406 monitoredDevices_.end()) { 456 monitoredDevices_.end()) {
407 return; 457 return;
408 } 458 }
409 [device addObserver:self 459 [device addObserver:self
410 forKeyPath:@"suspended" 460 forKeyPath:@"suspended"
411 options:0 461 options:0
412 context:device]; 462 context:device.get()];
413 [device addObserver:self 463 [device addObserver:self
414 forKeyPath:@"connected" 464 forKeyPath:@"connected"
415 options:0 465 options:0
416 context:device]; 466 context:device.get()];
417 monitoredDevices_.insert(device); 467 monitoredDevices_.insert(device);
418 } 468 }
419 469
420 - (void)stopObserving:(CrAVCaptureDevice*)device { 470 - (void)stopObserving:(CrAVCaptureDevice*)device {
471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 DCHECK(device != nil); 472 DCHECK(device != nil);
422 std::set<CrAVCaptureDevice*>::iterator found = 473
474 std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
423 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); 475 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
424 DCHECK(found != monitoredDevices_.end()); 476 DCHECK(found != monitoredDevices_.end());
425 // Every so seldom, |device| might be gone when getting here, in that case 477 [self removeObservers:*found];
426 // removing the observer causes a crash. Try to avoid it by checking sanity of 478 monitoredDevices_.erase(found);
427 // the |device| via its -observationInfo. http://crbug.com/371271. 479 }
480
481 - (void)clearOnDeviceChangedCallback {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 onDeviceChangedCallback_.Reset();
484 }
485
486 - (void)removeObservers:(CrAVCaptureDevice*)device {
487 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
488 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
428 if ([device observationInfo]) { 489 if ([device observationInfo]) {
429 [device removeObserver:self 490 [device removeObserver:self
430 forKeyPath:@"suspended"]; 491 forKeyPath:@"suspended"];
431 [device removeObserver:self 492 [device removeObserver:self
432 forKeyPath:@"connected"]; 493 forKeyPath:@"connected"];
433 } 494 }
434 monitoredDevices_.erase(found);
435 } 495 }
436 496
437 - (void)observeValueForKeyPath:(NSString*)keyPath 497 - (void)observeValueForKeyPath:(NSString*)keyPath
438 ofObject:(id)object 498 ofObject:(id)object
439 change:(NSDictionary*)change 499 change:(NSDictionary*)change
440 context:(void*)context { 500 context:(void*)context {
501 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441 if ([keyPath isEqual:@"suspended"]) 502 if ([keyPath isEqual:@"suspended"])
442 receiver_->OnDeviceChanged(); 503 onDeviceChangedCallback_.Run();
443 if ([keyPath isEqual:@"connected"]) 504 if ([keyPath isEqual:@"connected"])
444 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; 505 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
445 } 506 }
446 507
447 @end // @implementation CrAVFoundationDeviceObserver 508 @end // @implementation CrAVFoundationDeviceObserver
448 509
449 namespace content { 510 namespace content {
450 511
451 DeviceMonitorMac::DeviceMonitorMac() { 512 DeviceMonitorMac::DeviceMonitorMac() {
452 // Both QTKit and AVFoundation do not need to be fired up until the user 513 // Both QTKit and AVFoundation do not need to be fired up until the user
(...skipping 18 matching lines...) Expand all
471 } 532 }
472 533
473 void DeviceMonitorMac::NotifyDeviceChanged( 534 void DeviceMonitorMac::NotifyDeviceChanged(
474 base::SystemMonitor::DeviceType type) { 535 base::SystemMonitor::DeviceType type) {
475 DCHECK(thread_checker_.CalledOnValidThread()); 536 DCHECK(thread_checker_.CalledOnValidThread());
476 // TODO(xians): Remove the global variable for SystemMonitor. 537 // TODO(xians): Remove the global variable for SystemMonitor.
477 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 538 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
478 } 539 }
479 540
480 } // namespace content 541 } // 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