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

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: 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"
14 #import "media/video/capture/mac/avfoundation_glue.h" 15 #import "media/video/capture/mac/avfoundation_glue.h"
15 16
16 namespace { 17 namespace {
17 18
18 // This class is used to keep track of system devices names and their types. 19 // This class is used to keep track of system devices names and their types.
19 class DeviceInfo { 20 class DeviceInfo {
20 public: 21 public:
21 enum DeviceType { 22 enum DeviceType {
22 kAudio, 23 kAudio,
23 kVideo, 24 kVideo,
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 boolValue]) { 202 boolValue]) {
202 device_type = DeviceInfo::kAudio; 203 device_type = DeviceInfo::kAudio;
203 } 204 }
204 snapshot_devices.push_back( 205 snapshot_devices.push_back(
205 DeviceInfo([[device uniqueID] UTF8String], device_type)); 206 DeviceInfo([[device uniqueID] UTF8String], device_type));
206 } 207 }
207 ConsolidateDevicesListAndNotify(snapshot_devices); 208 ConsolidateDevicesListAndNotify(snapshot_devices);
208 } 209 }
209 210
210 // Forward declaration for use by CrAVFoundationDeviceObserver. 211 // Forward declaration for use by CrAVFoundationDeviceObserver.
211 class AVFoundationMonitorImpl; 212 class SuspendObserverDelegate;
212 213
213 } // namespace 214 } // namespace
214 215
215 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ 216 // 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 217 // classes cannot observe Key-Values directly. This class is used and
217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a. 218 // manipulated by SuspendObserverDelegate in Device Thread. -stopObserving is
218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread. 219 // called dutifully on -dealloc on Device Thread too.
219 @interface CrAVFoundationDeviceObserver : NSObject { 220 @interface CrAVFoundationDeviceObserver : NSObject {
220 @private 221 @private
221 AVFoundationMonitorImpl* receiver_; 222 SuspendObserverDelegate* receiver_;
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 SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
243 : avfoundation_monitor_impl_(monitor) {
244 thread_checker_.DetachFromThread();
245 }
246
247 void OnDeviceChanged();
248 void StartObserver();
249 private:
250 virtual ~SuspendObserverDelegate() {}
251
252 friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
253
254 base::ThreadChecker thread_checker_;
255 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
256 DeviceMonitorMacImpl* avfoundation_monitor_impl_;
tommi (sloooow) - chröme 2014/05/13 14:43:41 I don't see where this variable is NULLed. It nee
mcasas 2014/05/14 12:07:16 Done.
257 };
258
259 void SuspendObserverDelegate::OnDeviceChanged() {
260 DCHECK(thread_checker_.CalledOnValidThread());
261 NSArray* devices = [AVCaptureDeviceGlue devices];
262 std::vector<DeviceInfo> snapshot_devices;
263 for (CrAVCaptureDevice* device in devices) {
264 [suspend_observer_ startObserving:device];
265 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
266 [device isSuspended];
267 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
268 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
269 if (suspended)
270 continue;
271 device_type = DeviceInfo::kVideo;
272 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
273 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
274 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
275 device_type = DeviceInfo::kAudio;
276 }
277 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
278 device_type));
279 }
280 // Posts the consolidation of enumerated devices to be done on UI thread.
281 base::MessageLoopForUI::current()->PostTask(FROM_HERE,
tommi (sloooow) - chröme 2014/05/13 14:43:41 base::MessageLoopForUI::current() doesn't return t
mcasas 2014/05/14 12:07:16 You're totally right. I meant using: BrowserThread
282 base::Bind(&DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify,
283 base::Unretained(avfoundation_monitor_impl_), snapshot_devices));
284 }
285
286 void SuspendObserverDelegate::StartObserver() {
287 DCHECK(thread_checker_.CalledOnValidThread());
288 suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
289 initWithChangeReceiver:this]);
290 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
291 [suspend_observer_ startObserving:device];
292 }
293
234 // AVFoundation implementation of the Mac Device Monitor, registers as a global 294 // AVFoundation implementation of the Mac Device Monitor, registers as a global
235 // device connect/disconnect observer and plugs suspend/wake up device observers 295 // 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 296 // per device. Owns a SuspendObserverDelegate living in |deivce_task_runner_|
tommi (sloooow) - chröme 2014/05/13 14:43:41 device_task_runner_
mcasas 2014/05/14 12:07:16 Done.
237 // and operations involving |suspend_observer_| happen on |device_task_runner_|. 297 // and gets notified when a device is suspended/resumed. This class is created
298 // and lives in UI thread;
238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 299 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
239 public: 300 public:
240 AVFoundationMonitorImpl( 301 AVFoundationMonitorImpl(
241 content::DeviceMonitorMac* monitor, 302 content::DeviceMonitorMac* monitor,
242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); 303 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
243 virtual ~AVFoundationMonitorImpl(); 304 virtual ~AVFoundationMonitorImpl();
244 305
245 virtual void OnDeviceChanged() OVERRIDE; 306 virtual void OnDeviceChanged() OVERRIDE;
246 307
247 private: 308 private:
248 void OnDeviceChangedOnDeviceThread(
249 const scoped_refptr<base::MessageLoopProxy>& ui_thread);
250 void StartObserverOnDeviceThread();
251
252 base::ThreadChecker thread_checker_; 309 base::ThreadChecker thread_checker_;
253 310
254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for 311 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
255 // device enumeration, valid after MediaStreamManager calls StartMonitoring(). 312 // posting tasks to |suspend_observer_delegate_|; valid after
313 // MediaStreamManager calls StartMonitoring().
256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; 314 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
257 315
258 // Created and executed in |device_task_runnner_|. 316 scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
260 317
261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 318 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
262 }; 319 };
263 320
264 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 321 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
265 content::DeviceMonitorMac* monitor, 322 content::DeviceMonitorMac* monitor,
266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) 323 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
267 : DeviceMonitorMacImpl(monitor), 324 : DeviceMonitorMacImpl(monitor),
268 device_task_runner_(device_task_runner) { 325 device_task_runner_(device_task_runner),
326 suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 327 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
270 device_arrival_ = 328 device_arrival_ =
271 [nc addObserverForName:AVFoundationGlue:: 329 [nc addObserverForName:AVFoundationGlue::
272 AVCaptureDeviceWasConnectedNotification() 330 AVCaptureDeviceWasConnectedNotification()
273 object:nil 331 object:nil
274 queue:nil 332 queue:nil
275 usingBlock:^(NSNotification* notification) { 333 usingBlock:^(NSNotification* notification) {
276 OnDeviceChanged();}]; 334 OnDeviceChanged();}];
277 device_removal_ = 335 device_removal_ =
278 [nc addObserverForName:AVFoundationGlue:: 336 [nc addObserverForName:AVFoundationGlue::
279 AVCaptureDeviceWasDisconnectedNotification() 337 AVCaptureDeviceWasDisconnectedNotification()
280 object:nil 338 object:nil
281 queue:nil 339 queue:nil
282 usingBlock:^(NSNotification* notification) { 340 usingBlock:^(NSNotification* notification) {
283 OnDeviceChanged();}]; 341 OnDeviceChanged();}];
284 device_task_runner_->PostTask(FROM_HERE, 342 device_task_runner_->PostTask(FROM_HERE,
285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread, 343 base::Bind(&SuspendObserverDelegate::StartObserver,
286 base::Unretained(this))); 344 suspend_observer_delegate_));
287 } 345 }
288 346
289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 347 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
348 DCHECK(thread_checker_.CalledOnValidThread());
tommi (sloooow) - chröme 2014/05/13 14:43:41 here you would need to do something like: suspend
mcasas 2014/05/14 12:07:16 Done.
290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 349 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
291 [nc removeObserver:device_arrival_]; 350 [nc removeObserver:device_arrival_];
292 [nc removeObserver:device_removal_]; 351 [nc removeObserver:device_removal_];
293 } 352 }
294 353
295 void AVFoundationMonitorImpl::OnDeviceChanged() { 354 void AVFoundationMonitorImpl::OnDeviceChanged() {
296 DCHECK(thread_checker_.CalledOnValidThread()); 355 DCHECK(thread_checker_.CalledOnValidThread());
297 device_task_runner_->PostTask(FROM_HERE, 356 device_task_runner_->PostTask(FROM_HERE,
298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread, 357 base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
299 base::Unretained(this), 358 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 } 359 }
338 360
339 } // namespace 361 } // namespace
340 362
341 @implementation CrAVFoundationDeviceObserver 363 @implementation CrAVFoundationDeviceObserver
342 364
343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { 365 - (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
344 if ((self = [super init])) { 366 if ((self = [super init])) {
345 DCHECK(receiver != NULL); 367 DCHECK(receiver != NULL);
346 receiver_ = receiver; 368 receiver_ = receiver;
347 } 369 }
348 return self; 370 return self;
349 } 371 }
350 372
351 - (void)dealloc { 373 - (void)dealloc {
352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin(); 374 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
353 while (it != monitoredDevices_.end()) 375 while (it != monitoredDevices_.end())
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 449 }
428 450
429 void DeviceMonitorMac::NotifyDeviceChanged( 451 void DeviceMonitorMac::NotifyDeviceChanged(
430 base::SystemMonitor::DeviceType type) { 452 base::SystemMonitor::DeviceType type) {
431 DCHECK(thread_checker_.CalledOnValidThread()); 453 DCHECK(thread_checker_.CalledOnValidThread());
432 // TODO(xians): Remove the global variable for SystemMonitor. 454 // TODO(xians): Remove the global variable for SystemMonitor.
433 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 455 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
434 } 456 }
435 457
436 } // namespace content 458 } // 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