OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/device_monitors/device_monitor_mac.h" | 5 #include "media/device_monitors/device_monitor_mac.h" |
6 | 6 |
| 7 #include <AVFoundation/AVFoundation.h> |
7 #include <set> | 8 #include <set> |
8 | 9 |
9 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/mac/bind_objc_block.h" | 12 #include "base/mac/bind_objc_block.h" |
12 #include "base/mac/scoped_nsobject.h" | 13 #include "base/mac/scoped_nsobject.h" |
13 #include "base/macros.h" | 14 #include "base/macros.h" |
14 #include "base/profiler/scoped_tracker.h" | 15 #include "base/profiler/scoped_tracker.h" |
15 #include "base/task_runner_util.h" | 16 #include "base/task_runner_util.h" |
16 #include "base/threading/thread_checker.h" | 17 #include "base/threading/thread_checker.h" |
17 #import "media/base/mac/avfoundation_glue.h" | |
18 | 18 |
19 namespace { | 19 namespace { |
20 | 20 |
21 // This class is used to keep track of system devices names and their types. | 21 // This class is used to keep track of system devices names and their types. |
22 class DeviceInfo { | 22 class DeviceInfo { |
23 public: | 23 public: |
24 enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid }; | 24 enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid }; |
25 | 25 |
26 DeviceInfo(const std::string& unique_id, DeviceType type) | 26 DeviceInfo(const std::string& unique_id, DeviceType type) |
27 : unique_id_(unique_id), type_(type) {} | 27 : unique_id_(unique_id), type_(type) {} |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 | 131 |
132 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ | 132 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ |
133 // classes cannot observe Key-Values directly. Created, manipulated, and | 133 // classes cannot observe Key-Values directly. Created, manipulated, and |
134 // destroyed on the UI Thread by SuspendObserverDelegate. | 134 // destroyed on the UI Thread by SuspendObserverDelegate. |
135 @interface CrAVFoundationDeviceObserver : NSObject { | 135 @interface CrAVFoundationDeviceObserver : NSObject { |
136 @private | 136 @private |
137 // Callback for device changed, has to run on Device Thread. | 137 // Callback for device changed, has to run on Device Thread. |
138 base::Closure onDeviceChangedCallback_; | 138 base::Closure onDeviceChangedCallback_; |
139 | 139 |
140 // Member to keep track of the devices we are already monitoring. | 140 // Member to keep track of the devices we are already monitoring. |
141 std::set<base::scoped_nsobject<CrAVCaptureDevice>> monitoredDevices_; | 141 std::set<base::scoped_nsobject<AVCaptureDevice>> monitoredDevices_; |
142 | 142 |
143 // Pegged to the "main" thread -- usually content::BrowserThread::UI. | 143 // Pegged to the "main" thread -- usually content::BrowserThread::UI. |
144 base::ThreadChecker mainThreadChecker_; | 144 base::ThreadChecker mainThreadChecker_; |
145 } | 145 } |
146 | 146 |
147 - (id)initWithOnChangedCallback:(const base::Closure&)callback; | 147 - (id)initWithOnChangedCallback:(const base::Closure&)callback; |
148 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device; | 148 - (void)startObserving:(base::scoped_nsobject<AVCaptureDevice>)device; |
149 - (void)stopObserving:(CrAVCaptureDevice*)device; | 149 - (void)stopObserving:(AVCaptureDevice*)device; |
150 - (void)clearOnDeviceChangedCallback; | 150 - (void)clearOnDeviceChangedCallback; |
151 | 151 |
152 @end | 152 @end |
153 | 153 |
154 namespace { | 154 namespace { |
155 | 155 |
156 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. | 156 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. |
157 // It is created and destroyed on AVFoundationMonitorImpl's main thread (usually | 157 // It is created and destroyed on AVFoundationMonitorImpl's main thread (usually |
158 // browser's UI thread), and it operates on this thread except for the expensive | 158 // browser's UI thread), and it operates on this thread except for the expensive |
159 // device enumerations which are run on Device Thread. | 159 // device enumerations which are run on Device Thread. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 base::Closure on_device_changed_callback = base::Bind( | 209 base::Closure on_device_changed_callback = base::Bind( |
210 &SuspendObserverDelegate::OnDeviceChanged, this, device_thread); | 210 &SuspendObserverDelegate::OnDeviceChanged, this, device_thread); |
211 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] | 211 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] |
212 initWithOnChangedCallback:on_device_changed_callback]); | 212 initWithOnChangedCallback:on_device_changed_callback]); |
213 | 213 |
214 // Enumerate the devices in Device thread and post the observers start to be | 214 // Enumerate the devices in Device thread and post the observers start to be |
215 // done on UI thread. The devices array is retained in |device_thread| and | 215 // done on UI thread. The devices array is retained in |device_thread| and |
216 // released in DoStartObserver(). | 216 // released in DoStartObserver(). |
217 base::PostTaskAndReplyWithResult( | 217 base::PostTaskAndReplyWithResult( |
218 device_thread.get(), FROM_HERE, base::BindBlock(^{ | 218 device_thread.get(), FROM_HERE, base::BindBlock(^{ |
219 return [[AVCaptureDeviceGlue devices] retain]; | 219 return [[AVCaptureDevice devices] retain]; |
220 }), | 220 }), |
221 base::Bind(&SuspendObserverDelegate::DoStartObserver, this)); | 221 base::Bind(&SuspendObserverDelegate::DoStartObserver, this)); |
222 } | 222 } |
223 | 223 |
224 void SuspendObserverDelegate::OnDeviceChanged( | 224 void SuspendObserverDelegate::OnDeviceChanged( |
225 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { | 225 const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { |
226 DCHECK(main_thread_checker_.CalledOnValidThread()); | 226 DCHECK(main_thread_checker_.CalledOnValidThread()); |
227 // Enumerate the devices in Device thread and post the consolidation of the | 227 // Enumerate the devices in Device thread and post the consolidation of the |
228 // new devices and the old ones to be done on main thread. The devices array | 228 // new devices and the old ones to be done on main thread. The devices array |
229 // is retained in |device_thread| and released in DoOnDeviceChanged(). | 229 // is retained in |device_thread| and released in DoOnDeviceChanged(). |
230 PostTaskAndReplyWithResult( | 230 PostTaskAndReplyWithResult( |
231 device_thread.get(), FROM_HERE, base::BindBlock(^{ | 231 device_thread.get(), FROM_HERE, base::BindBlock(^{ |
232 return [[AVCaptureDeviceGlue devices] retain]; | 232 return [[AVCaptureDevice devices] retain]; |
233 }), | 233 }), |
234 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this)); | 234 base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this)); |
235 } | 235 } |
236 | 236 |
237 void SuspendObserverDelegate::ResetDeviceMonitor() { | 237 void SuspendObserverDelegate::ResetDeviceMonitor() { |
238 DCHECK(main_thread_checker_.CalledOnValidThread()); | 238 DCHECK(main_thread_checker_.CalledOnValidThread()); |
239 avfoundation_monitor_impl_ = NULL; | 239 avfoundation_monitor_impl_ = NULL; |
240 [suspend_observer_ clearOnDeviceChangedCallback]; | 240 [suspend_observer_ clearOnDeviceChangedCallback]; |
241 } | 241 } |
242 | 242 |
243 SuspendObserverDelegate::~SuspendObserverDelegate() { | 243 SuspendObserverDelegate::~SuspendObserverDelegate() { |
244 DCHECK(main_thread_checker_.CalledOnValidThread()); | 244 DCHECK(main_thread_checker_.CalledOnValidThread()); |
245 } | 245 } |
246 | 246 |
247 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) { | 247 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) { |
248 DCHECK(main_thread_checker_.CalledOnValidThread()); | 248 DCHECK(main_thread_checker_.CalledOnValidThread()); |
249 base::scoped_nsobject<NSArray> auto_release(devices); | 249 base::scoped_nsobject<NSArray> auto_release(devices); |
250 for (CrAVCaptureDevice* device in devices) { | 250 for (AVCaptureDevice* device in devices) { |
251 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); | 251 base::scoped_nsobject<AVCaptureDevice> device_ptr([device retain]); |
252 [suspend_observer_ startObserving:device_ptr]; | 252 [suspend_observer_ startObserving:device_ptr]; |
253 } | 253 } |
254 } | 254 } |
255 | 255 |
256 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) { | 256 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) { |
257 DCHECK(main_thread_checker_.CalledOnValidThread()); | 257 DCHECK(main_thread_checker_.CalledOnValidThread()); |
258 base::scoped_nsobject<NSArray> auto_release(devices); | 258 base::scoped_nsobject<NSArray> auto_release(devices); |
259 std::vector<DeviceInfo> snapshot_devices; | 259 std::vector<DeviceInfo> snapshot_devices; |
260 for (CrAVCaptureDevice* device in devices) { | 260 for (AVCaptureDevice* device in devices) { |
261 base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); | 261 base::scoped_nsobject<AVCaptureDevice> device_ptr([device retain]); |
262 [suspend_observer_ startObserving:device_ptr]; | 262 [suspend_observer_ startObserving:device_ptr]; |
263 | 263 |
264 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && | 264 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && |
265 [device isSuspended]; | 265 [device isSuspended]; |
266 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; | 266 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; |
267 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { | 267 if ([device hasMediaType:AVMediaTypeVideo]) { |
268 if (suspended) | 268 if (suspended) |
269 continue; | 269 continue; |
270 device_type = DeviceInfo::kVideo; | 270 device_type = DeviceInfo::kVideo; |
271 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { | 271 } else if ([device hasMediaType:AVMediaTypeMuxed]) { |
272 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; | 272 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; |
273 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { | 273 } else if ([device hasMediaType:AVMediaTypeAudio]) { |
274 device_type = DeviceInfo::kAudio; | 274 device_type = DeviceInfo::kAudio; |
275 } | 275 } |
276 snapshot_devices.push_back( | 276 snapshot_devices.push_back( |
277 DeviceInfo([[device uniqueID] UTF8String], device_type)); | 277 DeviceInfo([[device uniqueID] UTF8String], device_type)); |
278 } | 278 } |
279 // Make sure no references are held to |devices| when | 279 // Make sure no references are held to |devices| when |
280 // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager | 280 // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager |
281 // and AudioCaptureManagers also enumerates the available devices but on | 281 // and AudioCaptureManagers also enumerates the available devices but on |
282 // another thread. | 282 // another thread. |
283 auto_release.reset(); | 283 auto_release.reset(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 | 318 |
319 AVFoundationMonitorImpl::AVFoundationMonitorImpl( | 319 AVFoundationMonitorImpl::AVFoundationMonitorImpl( |
320 media::DeviceMonitorMac* monitor, | 320 media::DeviceMonitorMac* monitor, |
321 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) | 321 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) |
322 : DeviceMonitorMacImpl(monitor), | 322 : DeviceMonitorMacImpl(monitor), |
323 device_task_runner_(device_task_runner), | 323 device_task_runner_(device_task_runner), |
324 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { | 324 suspend_observer_delegate_(new SuspendObserverDelegate(this)) { |
325 DCHECK(main_thread_checker_.CalledOnValidThread()); | 325 DCHECK(main_thread_checker_.CalledOnValidThread()); |
326 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 326 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
327 device_arrival_ = | 327 device_arrival_ = |
328 [nc addObserverForName:AVFoundationGlue:: | 328 [nc addObserverForName:AVCaptureDeviceWasConnectedNotification |
329 AVCaptureDeviceWasConnectedNotification() | |
330 object:nil | 329 object:nil |
331 queue:nil | 330 queue:nil |
332 usingBlock:^(NSNotification* notification) { | 331 usingBlock:^(NSNotification* notification) { |
333 OnDeviceChanged(); | 332 OnDeviceChanged(); |
334 }]; | 333 }]; |
335 device_removal_ = | 334 device_removal_ = |
336 [nc addObserverForName:AVFoundationGlue:: | 335 [nc addObserverForName:AVCaptureDeviceWasDisconnectedNotification |
337 AVCaptureDeviceWasDisconnectedNotification() | |
338 object:nil | 336 object:nil |
339 queue:nil | 337 queue:nil |
340 usingBlock:^(NSNotification* notification) { | 338 usingBlock:^(NSNotification* notification) { |
341 OnDeviceChanged(); | 339 OnDeviceChanged(); |
342 }]; | 340 }]; |
343 suspend_observer_delegate_->StartObserver(device_task_runner_); | 341 suspend_observer_delegate_->StartObserver(device_task_runner_); |
344 } | 342 } |
345 | 343 |
346 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { | 344 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { |
347 DCHECK(main_thread_checker_.CalledOnValidThread()); | 345 DCHECK(main_thread_checker_.CalledOnValidThread()); |
(...skipping 16 matching lines...) Expand all Loading... |
364 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 362 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
365 if ((self = [super init])) { | 363 if ((self = [super init])) { |
366 DCHECK(!callback.is_null()); | 364 DCHECK(!callback.is_null()); |
367 onDeviceChangedCallback_ = callback; | 365 onDeviceChangedCallback_ = callback; |
368 } | 366 } |
369 return self; | 367 return self; |
370 } | 368 } |
371 | 369 |
372 - (void)dealloc { | 370 - (void)dealloc { |
373 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 371 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
374 std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator it = | 372 std::set<base::scoped_nsobject<AVCaptureDevice>>::iterator it = |
375 monitoredDevices_.begin(); | 373 monitoredDevices_.begin(); |
376 while (it != monitoredDevices_.end()) | 374 while (it != monitoredDevices_.end()) |
377 [self removeObservers:*(it++)]; | 375 [self removeObservers:*(it++)]; |
378 [super dealloc]; | 376 [super dealloc]; |
379 } | 377 } |
380 | 378 |
381 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device { | 379 - (void)startObserving:(base::scoped_nsobject<AVCaptureDevice>)device { |
382 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 380 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
383 DCHECK(device != nil); | 381 DCHECK(device != nil); |
384 // Skip this device if there are already observers connected to it. | 382 // Skip this device if there are already observers connected to it. |
385 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != | 383 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != |
386 monitoredDevices_.end()) { | 384 monitoredDevices_.end()) { |
387 return; | 385 return; |
388 } | 386 } |
389 [device addObserver:self | 387 [device addObserver:self |
390 forKeyPath:@"suspended" | 388 forKeyPath:@"suspended" |
391 options:0 | 389 options:0 |
392 context:device.get()]; | 390 context:device.get()]; |
393 [device addObserver:self | 391 [device addObserver:self |
394 forKeyPath:@"connected" | 392 forKeyPath:@"connected" |
395 options:0 | 393 options:0 |
396 context:device.get()]; | 394 context:device.get()]; |
397 monitoredDevices_.insert(device); | 395 monitoredDevices_.insert(device); |
398 } | 396 } |
399 | 397 |
400 - (void)stopObserving:(CrAVCaptureDevice*)device { | 398 - (void)stopObserving:(AVCaptureDevice*)device { |
401 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 399 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
402 DCHECK(device != nil); | 400 DCHECK(device != nil); |
403 | 401 |
404 std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator found = | 402 std::set<base::scoped_nsobject<AVCaptureDevice>>::iterator found = |
405 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); | 403 std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); |
406 DCHECK(found != monitoredDevices_.end()); | 404 DCHECK(found != monitoredDevices_.end()); |
407 [self removeObservers:*found]; | 405 [self removeObservers:*found]; |
408 monitoredDevices_.erase(found); | 406 monitoredDevices_.erase(found); |
409 } | 407 } |
410 | 408 |
411 - (void)clearOnDeviceChangedCallback { | 409 - (void)clearOnDeviceChangedCallback { |
412 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 410 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
413 onDeviceChangedCallback_.Reset(); | 411 onDeviceChangedCallback_.Reset(); |
414 } | 412 } |
415 | 413 |
416 - (void)removeObservers:(CrAVCaptureDevice*)device { | 414 - (void)removeObservers:(AVCaptureDevice*)device { |
417 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 415 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
418 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271. | 416 // Check sanity of |device| via its -observationInfo. http://crbug.com/371271. |
419 if ([device observationInfo]) { | 417 if ([device observationInfo]) { |
420 [device removeObserver:self | 418 [device removeObserver:self |
421 forKeyPath:@"suspended"]; | 419 forKeyPath:@"suspended"]; |
422 [device removeObserver:self | 420 [device removeObserver:self |
423 forKeyPath:@"connected"]; | 421 forKeyPath:@"connected"]; |
424 } | 422 } |
425 } | 423 } |
426 | 424 |
427 - (void)observeValueForKeyPath:(NSString*)keyPath | 425 - (void)observeValueForKeyPath:(NSString*)keyPath |
428 ofObject:(id)object | 426 ofObject:(id)object |
429 change:(NSDictionary*)change | 427 change:(NSDictionary*)change |
430 context:(void*)context { | 428 context:(void*)context { |
431 DCHECK(mainThreadChecker_.CalledOnValidThread()); | 429 DCHECK(mainThreadChecker_.CalledOnValidThread()); |
432 if ([keyPath isEqual:@"suspended"]) | 430 if ([keyPath isEqual:@"suspended"]) |
433 onDeviceChangedCallback_.Run(); | 431 onDeviceChangedCallback_.Run(); |
434 if ([keyPath isEqual:@"connected"]) | 432 if ([keyPath isEqual:@"connected"]) |
435 [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; | 433 [self stopObserving:static_cast<AVCaptureDevice*>(context)]; |
436 } | 434 } |
437 | 435 |
438 @end // @implementation CrAVFoundationDeviceObserver | 436 @end // @implementation CrAVFoundationDeviceObserver |
439 | 437 |
440 namespace media { | 438 namespace media { |
441 | 439 |
442 DeviceMonitorMac::DeviceMonitorMac() { | 440 DeviceMonitorMac::DeviceMonitorMac() { |
443 // AVFoundation do not need to be fired up until the user | 441 // AVFoundation do not need to be fired up until the user |
444 // exercises a GetUserMedia. Bringing up either library and enumerating the | 442 // exercises a GetUserMedia. Bringing up either library and enumerating the |
445 // devices in the system is an operation taking in the range of hundred of ms, | 443 // devices in the system is an operation taking in the range of hundred of ms, |
446 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). | 444 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). |
447 } | 445 } |
448 | 446 |
449 DeviceMonitorMac::~DeviceMonitorMac() {} | 447 DeviceMonitorMac::~DeviceMonitorMac() {} |
450 | 448 |
451 void DeviceMonitorMac::StartMonitoring( | 449 void DeviceMonitorMac::StartMonitoring( |
452 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { | 450 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { |
453 DCHECK(thread_checker_.CalledOnValidThread()); | 451 DCHECK(thread_checker_.CalledOnValidThread()); |
454 | 452 |
455 // We're on the UI thread so let's try to initialize AVFoundation. | |
456 AVFoundationGlue::InitializeAVFoundation(); | |
457 | |
458 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 | 453 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 |
459 // is fixed. | 454 // is fixed. |
460 tracked_objects::ScopedTracker tracking_profile( | 455 tracked_objects::ScopedTracker tracking_profile( |
461 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 456 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
462 "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); | 457 "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); |
463 DVLOG(1) << "Monitoring via AVFoundation"; | 458 DVLOG(1) << "Monitoring via AVFoundation"; |
464 device_monitor_impl_.reset( | 459 device_monitor_impl_.reset( |
465 new AVFoundationMonitorImpl(this, device_task_runner)); | 460 new AVFoundationMonitorImpl(this, device_task_runner)); |
466 } | 461 } |
467 | 462 |
468 void DeviceMonitorMac::NotifyDeviceChanged( | 463 void DeviceMonitorMac::NotifyDeviceChanged( |
469 base::SystemMonitor::DeviceType type) { | 464 base::SystemMonitor::DeviceType type) { |
470 DCHECK(thread_checker_.CalledOnValidThread()); | 465 DCHECK(thread_checker_.CalledOnValidThread()); |
471 // TODO(xians): Remove the global variable for SystemMonitor. | 466 // TODO(xians): Remove the global variable for SystemMonitor. |
472 base::SystemMonitor::Get()->ProcessDevicesChanged(type); | 467 base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
473 } | 468 } |
474 | 469 |
475 } // namespace media | 470 } // namespace media |
OLD | NEW |