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

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