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

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

Issue 276573009: DeviceMonitorMac AVFoundation: move mgmt of |suspend_observer_| to a class living in Device Thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tommi@s comments. Created 6 years, 7 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/scoped_nsobject.h" 13 #include "base/mac/scoped_nsobject.h"
14 #include "base/synchronization/lock.h"
15 #include "base/threading/thread_checker.h"
16 #include "content/public/browser/browser_thread.h"
14 #import "media/video/capture/mac/avfoundation_glue.h" 17 #import "media/video/capture/mac/avfoundation_glue.h"
15 18
16 namespace { 19 namespace {
17 20
18 // 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.
19 class DeviceInfo { 22 class DeviceInfo {
20 public: 23 public:
21 enum DeviceType { 24 enum DeviceType {
22 kAudio, 25 kAudio,
23 kVideo, 26 kVideo,
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 boolValue]) { 204 boolValue]) {
202 device_type = DeviceInfo::kAudio; 205 device_type = DeviceInfo::kAudio;
203 } 206 }
204 snapshot_devices.push_back( 207 snapshot_devices.push_back(
205 DeviceInfo([[device uniqueID] UTF8String], device_type)); 208 DeviceInfo([[device uniqueID] UTF8String], device_type));
206 } 209 }
207 ConsolidateDevicesListAndNotify(snapshot_devices); 210 ConsolidateDevicesListAndNotify(snapshot_devices);
208 } 211 }
209 212
210 // Forward declaration for use by CrAVFoundationDeviceObserver. 213 // Forward declaration for use by CrAVFoundationDeviceObserver.
211 class AVFoundationMonitorImpl; 214 class SuspendObserverDelegate;
212 215
213 } // namespace 216 } // namespace
214 217
215 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ 218 // This class is a Key-Value Observer (KVO) shim. It is needed because C++
216 // classes cannot observe Key-Values directly. This class is used by 219 // classes cannot observe Key-Values directly. This class is used and
217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a. 220 // manipulated by SuspendObserverDelegate in Device Thread. -stopObserving is
218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread. 221 // called dutifully on -dealloc on Device Thread too.
219 @interface CrAVFoundationDeviceObserver : NSObject { 222 @interface CrAVFoundationDeviceObserver : NSObject {
220 @private 223 @private
221 AVFoundationMonitorImpl* receiver_; 224 SuspendObserverDelegate* receiver_;
222 // Member to keep track of the devices we are already monitoring. 225 // Member to keep track of the devices we are already monitoring.
223 std::set<CrAVCaptureDevice*> monitoredDevices_; 226 std::set<CrAVCaptureDevice*> monitoredDevices_;
224 } 227 }
225 228
226 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; 229 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver;
227 - (void)startObserving:(CrAVCaptureDevice*)device; 230 - (void)startObserving:(CrAVCaptureDevice*)device;
228 - (void)stopObserving:(CrAVCaptureDevice*)device; 231 - (void)stopObserving:(CrAVCaptureDevice*)device;
229 232
230 @end 233 @end
231 234
232 namespace { 235 namespace {
233 236
237 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
238 // Provides a callback for this device observer to indicate that there has been
239 // a device change of some kind. Created by AVFoundationMonitorImpl in UI thread
240 // but living in Device Thread.
241 class SuspendObserverDelegate :
242 public base::RefCountedThreadSafe<SuspendObserverDelegate> {
243 public:
244 SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
245 : avfoundation_monitor_impl_(monitor) {
246 thread_checker_.DetachFromThread();
247 }
248
249 void OnDeviceChanged();
250 void StartObserver();
251 void ResetDeviceMonitorOnUIThread();
252
253 private:
254 virtual ~SuspendObserverDelegate() {}
255
256 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
257
258 base::ThreadChecker thread_checker_;
259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
260 // |lock_| protects concurrent usage + reset of |avfoundation_monitor_impl_|.
261 base::Lock lock_;
262 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
263 };
264
265 void SuspendObserverDelegate::OnDeviceChanged() {
266 DCHECK(thread_checker_.CalledOnValidThread());
267 NSArray* devices = [AVCaptureDeviceGlue devices];
268 std::vector<DeviceInfo> snapshot_devices;
269 for (CrAVCaptureDevice* device in devices) {
270 [suspend_observer_ startObserving:device];
271 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
272 [device isSuspended];
273 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
274 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
275 if (suspended)
276 continue;
277 device_type = DeviceInfo::kVideo;
278 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
279 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
280 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
281 device_type = DeviceInfo::kAudio;
282 }
283 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
284 device_type));
285 }
286 // Posts the consolidation of enumerated devices to be done on UI thread. This
287 // has to happen in mutex with ResetDeviceMonitorOnUIThread().
288 {
289 base::AutoLock auto_lock(lock_);
290 if (avfoundation_monitor_impl_) {
291 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
292 base::Bind(&DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify,
293 base::Unretained(avfoundation_monitor_impl_), snapshot_devices));
tommi (sloooow) - chröme 2014/05/15 13:35:39 This is unfortunately not safe either. The pointe
mcasas 2014/05/15 13:52:19 Good suggestion. Done.
294 }
295 }
296 }
297
298 void SuspendObserverDelegate::StartObserver() {
299 DCHECK(thread_checker_.CalledOnValidThread());
300 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
301 initWithChangeReceiver:this]);
302 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
303 [suspend_observer_ startObserving:device];
304 }
305
306 void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() {
307 DCHECK(base::MessageLoopForUI::IsCurrent());
308 base::AutoLock auto_lock(lock_);
309 avfoundation_monitor_impl_ = NULL;
310 }
311
234 // AVFoundation implementation of the Mac Device Monitor, registers as a global 312 // AVFoundation implementation of the Mac Device Monitor, registers as a global
235 // device connect/disconnect observer and plugs suspend/wake up device observers 313 // device connect/disconnect observer and plugs suspend/wake up device observers
236 // per device. This class is created and lives in UI thread; device enumeration 314 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_|
237 // and operations involving |suspend_observer_| happen on |device_task_runner_|. 315 // and gets notified when a device is suspended/resumed. This class is created
316 // and lives in UI thread;
238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 317 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
239 public: 318 public:
240 AVFoundationMonitorImpl( 319 AVFoundationMonitorImpl(
241 content::DeviceMonitorMac* monitor, 320 content::DeviceMonitorMac* monitor,
242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 321 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
243 virtual ~AVFoundationMonitorImpl(); 322 virtual ~AVFoundationMonitorImpl();
244 323
245 virtual void OnDeviceChanged() OVERRIDE; 324 virtual void OnDeviceChanged() OVERRIDE;
246 325
247 private: 326 private:
248 void OnDeviceChangedOnDeviceThread(
249 const scoped_refptr<base::MessageLoopProxy>& ui_thread);
250 void StartObserverOnDeviceThread();
251
252 base::ThreadChecker thread_checker_; 327 base::ThreadChecker thread_checker_;
253 328
254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 329 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
255 // device enumeration, valid after MediaStreamManager calls StartMonitoring(). 330 // posting tasks to |suspend_observer_delegate_|; valid after
331 // MediaStreamManager calls StartMonitoring().
256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 332 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
257 333
258 // Created and executed in |device_task_runnner_|. 334 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
260 335
261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 336 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
262 }; 337 };
263 338
264 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 339 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
265 content::DeviceMonitorMac* monitor, 340 content::DeviceMonitorMac* monitor,
266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 341 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
267 : DeviceMonitorMacImpl(monitor), 342 : DeviceMonitorMacImpl(monitor),
268 device_task_runner_(device_task_runner) { 343 device_task_runner_(device_task_runner),
344 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 345 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
270 device_arrival_ = 346 device_arrival_ =
271 [nc addObserverForName:AVFoundationGlue:: 347 [nc addObserverForName:AVFoundationGlue::
272 AVCaptureDeviceWasConnectedNotification() 348 AVCaptureDeviceWasConnectedNotification()
273 object:nil 349 object:nil
274 queue:nil 350 queue:nil
275 usingBlock:^(NSNotification* notification) { 351 usingBlock:^(NSNotification* notification) {
276 OnDeviceChanged();}]; 352 OnDeviceChanged();}];
277 device_removal_ = 353 device_removal_ =
278 [nc addObserverForName:AVFoundationGlue:: 354 [nc addObserverForName:AVFoundationGlue::
279 AVCaptureDeviceWasDisconnectedNotification() 355 AVCaptureDeviceWasDisconnectedNotification()
280 object:nil 356 object:nil
281 queue:nil 357 queue:nil
282 usingBlock:^(NSNotification* notification) { 358 usingBlock:^(NSNotification* notification) {
283 OnDeviceChanged();}]; 359 OnDeviceChanged();}];
284 device_task_runner_->PostTask(FROM_HERE, 360 device_task_runner_->PostTask(FROM_HERE,
285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread, 361 base::Bind(&SuspendObserverDelegate::StartObserver,
286 base::Unretained(this))); 362 suspend_observer_delegate_));
287 } 363 }
288 364
289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 365 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
366 DCHECK(thread_checker_.CalledOnValidThread());
367 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread();
290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 368 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
291 [nc removeObserver:device_arrival_]; 369 [nc removeObserver:device_arrival_];
292 [nc removeObserver:device_removal_]; 370 [nc removeObserver:device_removal_];
293 } 371 }
294 372
295 void AVFoundationMonitorImpl::OnDeviceChanged() { 373 void AVFoundationMonitorImpl::OnDeviceChanged() {
296 DCHECK(thread_checker_.CalledOnValidThread()); 374 DCHECK(thread_checker_.CalledOnValidThread());
297 device_task_runner_->PostTask(FROM_HERE, 375 device_task_runner_->PostTask(FROM_HERE,
298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread, 376 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
299 base::Unretained(this), 377 suspend_observer_delegate_));
300 base::MessageLoop::current()->message_loop_proxy()));
301 }
302
303 void AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread(
304 const scoped_refptr<base::MessageLoopProxy>& ui_thread) {
305 DCHECK(device_task_runner_->BelongsToCurrentThread());
306 NSArray* devices = [AVCaptureDeviceGlue devices];
307 std::vector<DeviceInfo> snapshot_devices;
308 for (CrAVCaptureDevice* device in devices) {
309 [suspend_observer_ startObserving:device];
310 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
311 [device isSuspended];
312 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
313 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
314 if (suspended)
315 continue;
316 device_type = DeviceInfo::kVideo;
317 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
318 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
319 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
320 device_type = DeviceInfo::kAudio;
321 }
322 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
323 device_type));
324 }
325 // Post the consolidation of enumerated devices to be done on UI thread.
326 ui_thread->PostTask(FROM_HERE,
327 base::Bind(&DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify,
328 base::Unretained(this), snapshot_devices));
329 }
330
331 void AVFoundationMonitorImpl::StartObserverOnDeviceThread() {
332 DCHECK(device_task_runner_->BelongsToCurrentThread());
333 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
334 initWithChangeReceiver:this]);
335 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
336 [suspend_observer_ startObserving:device];
337 } 378 }
338 379
339 } // namespace 380 } // namespace
340 381
341 @implementation CrAVFoundationDeviceObserver 382 @implementation CrAVFoundationDeviceObserver
342 383
343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { 384 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
344 if ((self = [super init])) { 385 if ((self = [super init])) {
345 DCHECK(receiver != NULL); 386 DCHECK(receiver != NULL);
346 receiver_ = receiver; 387 receiver_ = receiver;
347 } 388 }
348 return self; 389 return self;
349 } 390 }
350 391
351 - (void)dealloc { 392 - (void)dealloc {
352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 393 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
353 while (it != monitoredDevices_.end()) 394 while (it != monitoredDevices_.end())
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 468 }
428 469
429 void DeviceMonitorMac::NotifyDeviceChanged( 470 void DeviceMonitorMac::NotifyDeviceChanged(
430 base::SystemMonitor::DeviceType type) { 471 base::SystemMonitor::DeviceType type) {
431 DCHECK(thread_checker_.CalledOnValidThread()); 472 DCHECK(thread_checker_.CalledOnValidThread());
432 // TODO(xians): Remove the global variable for SystemMonitor. 473 // TODO(xians): Remove the global variable for SystemMonitor.
433 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 474 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
434 } 475 }
435 476
436 } // namespace content 477 } // 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