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

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@ comments, adding reference counting to |device| manipulation, simplified use of Device Thre… 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:(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
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
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