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

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: rsesek@ 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. Created, manipulated, and
217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a. 219 // destroyed on the Device Thread by SuspendedObserverDelegate.
218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread.
219 @interface CrAVFoundationDeviceObserver : NSObject { 220 @interface CrAVFoundationDeviceObserver : NSObject {
220 @private 221 @private
221 AVFoundationMonitorImpl* receiver_; 222 SuspendObserverDelegate* receiver_; // weak
222 // Member to keep track of the devices we are already monitoring. 223 // Member to keep track of the devices we are already monitoring.
223 std::set<CrAVCaptureDevice*> monitoredDevices_; 224 std::set<CrAVCaptureDevice*> monitoredDevices_;
224 } 225 }
225 226
226 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; 227 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver;
227 - (void)startObserving:(CrAVCaptureDevice*)device; 228 - (void)startObserving:(CrAVCaptureDevice*)device;
228 - (void)stopObserving:(CrAVCaptureDevice*)device; 229 - (void)stopObserving:(CrAVCaptureDevice*)device;
229 230
230 @end 231 @end
231 232
232 namespace { 233 namespace {
233 234
235 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
236 // Provides a callback for this device observer to indicate that there has been
237 // a device change of some kind. Created by AVFoundationMonitorImpl in UI thread
238 // but living in Device Thread.
239 class SuspendObserverDelegate :
240 public base::RefCountedThreadSafe<SuspendObserverDelegate> {
241 public:
242 explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
243 : avfoundation_monitor_impl_(monitor) {
244 device_thread_checker_.DetachFromThread();
245 }
246
247 void OnDeviceChanged();
248 void StartObserver();
249 void ResetDeviceMonitorOnUIThread();
250
251 private:
252 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
253
254 virtual ~SuspendObserverDelegate() {}
255
256 void OnDeviceChangedOnUIThread(
257 const std::vector<DeviceInfo>& snapshot_devices);
258
259 base::ThreadChecker device_thread_checker_;
260 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
261 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
262 };
263
264 void SuspendObserverDelegate::OnDeviceChanged() {
265 DCHECK(device_thread_checker_.CalledOnValidThread());
266 NSArray* devices = [AVCaptureDeviceGlue devices];
267 std::vector<DeviceInfo> snapshot_devices;
268 for (CrAVCaptureDevice* device in devices) {
269 [suspend_observer_ startObserving:device];
270 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
271 [device isSuspended];
272 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
273 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
274 if (suspended)
275 continue;
276 device_type = DeviceInfo::kVideo;
277 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
278 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
279 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
280 device_type = DeviceInfo::kAudio;
281 }
282 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
283 device_type));
284 }
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
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
308 // arriving at this line.
309 if (avfoundation_monitor_impl_) {
310 avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
311 snapshot_devices);
312 }
313 }
314
234 // AVFoundation implementation of the Mac Device Monitor, registers as a global 315 // AVFoundation implementation of the Mac Device Monitor, registers as a global
235 // device connect/disconnect observer and plugs suspend/wake up device observers 316 // 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 317 // per device. Owns a SuspendObserverDelegate living in |device_task_runner_|
237 // and operations involving |suspend_observer_| happen on |device_task_runner_|. 318 // and gets notified when a device is suspended/resumed. This class is created
319 // and lives in UI thread;
238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 320 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
239 public: 321 public:
240 AVFoundationMonitorImpl( 322 AVFoundationMonitorImpl(
241 content::DeviceMonitorMac* monitor, 323 content::DeviceMonitorMac* monitor,
242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 324 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
243 virtual ~AVFoundationMonitorImpl(); 325 virtual ~AVFoundationMonitorImpl();
244 326
245 virtual void OnDeviceChanged() OVERRIDE; 327 virtual void OnDeviceChanged() OVERRIDE;
246 328
247 private: 329 private:
248 void OnDeviceChangedOnDeviceThread(
249 const scoped_refptr<base::MessageLoopProxy>& ui_thread);
250 void StartObserverOnDeviceThread();
251
252 base::ThreadChecker thread_checker_; 330 base::ThreadChecker thread_checker_;
253 331
254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 332 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
255 // device enumeration, valid after MediaStreamManager calls StartMonitoring(). 333 // posting tasks to |suspend_observer_delegate_|; valid after
334 // MediaStreamManager calls StartMonitoring().
256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 335 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
257 336
258 // Created and executed in |device_task_runnner_|. 337 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
260 338
261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 339 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
262 }; 340 };
263 341
264 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 342 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
265 content::DeviceMonitorMac* monitor, 343 content::DeviceMonitorMac* monitor,
266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 344 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
267 : DeviceMonitorMacImpl(monitor), 345 : DeviceMonitorMacImpl(monitor),
268 device_task_runner_(device_task_runner) { 346 device_task_runner_(device_task_runner),
347 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 348 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
270 device_arrival_ = 349 device_arrival_ =
271 [nc addObserverForName:AVFoundationGlue:: 350 [nc addObserverForName:AVFoundationGlue::
272 AVCaptureDeviceWasConnectedNotification() 351 AVCaptureDeviceWasConnectedNotification()
273 object:nil 352 object:nil
274 queue:nil 353 queue:nil
275 usingBlock:^(NSNotification* notification) { 354 usingBlock:^(NSNotification* notification) {
276 OnDeviceChanged();}]; 355 OnDeviceChanged();}];
277 device_removal_ = 356 device_removal_ =
278 [nc addObserverForName:AVFoundationGlue:: 357 [nc addObserverForName:AVFoundationGlue::
279 AVCaptureDeviceWasDisconnectedNotification() 358 AVCaptureDeviceWasDisconnectedNotification()
280 object:nil 359 object:nil
281 queue:nil 360 queue:nil
282 usingBlock:^(NSNotification* notification) { 361 usingBlock:^(NSNotification* notification) {
283 OnDeviceChanged();}]; 362 OnDeviceChanged();}];
284 device_task_runner_->PostTask(FROM_HERE, 363 device_task_runner_->PostTask(FROM_HERE,
285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread, 364 base::Bind(&SuspendObserverDelegate::StartObserver,
286 base::Unretained(this))); 365 suspend_observer_delegate_));
287 } 366 }
288 367
289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 368 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
369 DCHECK(thread_checker_.CalledOnValidThread());
370 suspend_observer_delegate_->ResetDeviceMonitorOnUIThread();
290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 371 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
291 [nc removeObserver:device_arrival_]; 372 [nc removeObserver:device_arrival_];
292 [nc removeObserver:device_removal_]; 373 [nc removeObserver:device_removal_];
293 } 374 }
294 375
295 void AVFoundationMonitorImpl::OnDeviceChanged() { 376 void AVFoundationMonitorImpl::OnDeviceChanged() {
296 DCHECK(thread_checker_.CalledOnValidThread()); 377 DCHECK(thread_checker_.CalledOnValidThread());
297 device_task_runner_->PostTask(FROM_HERE, 378 device_task_runner_->PostTask(FROM_HERE,
298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread, 379 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
299 base::Unretained(this), 380 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 } 381 }
338 382
339 } // namespace 383 } // namespace
340 384
341 @implementation CrAVFoundationDeviceObserver 385 @implementation CrAVFoundationDeviceObserver
342 386
343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { 387 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
344 if ((self = [super init])) { 388 if ((self = [super init])) {
345 DCHECK(receiver != NULL); 389 DCHECK(receiver != NULL);
346 receiver_ = receiver; 390 receiver_ = receiver;
347 } 391 }
348 return self; 392 return self;
349 } 393 }
350 394
351 - (void)dealloc { 395 - (void)dealloc {
352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 396 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
353 while (it != monitoredDevices_.end()) 397 while (it != monitoredDevices_.end())
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 471 }
428 472
429 void DeviceMonitorMac::NotifyDeviceChanged( 473 void DeviceMonitorMac::NotifyDeviceChanged(
430 base::SystemMonitor::DeviceType type) { 474 base::SystemMonitor::DeviceType type) {
431 DCHECK(thread_checker_.CalledOnValidThread()); 475 DCHECK(thread_checker_.CalledOnValidThread());
432 // TODO(xians): Remove the global variable for SystemMonitor. 476 // TODO(xians): Remove the global variable for SystemMonitor.
433 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 477 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
434 } 478 }
435 479
436 } // namespace content 480 } // 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