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

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

Issue 252893003: Mac AVFoundation: Enumerate devices in device/audio thread. Take 2. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rsesek@ nit 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
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/logging.h" 12 #include "base/logging.h"
12 #include "base/mac/scoped_nsobject.h" 13 #include "base/mac/scoped_nsobject.h"
13 #import "media/video/capture/mac/avfoundation_glue.h" 14 #import "media/video/capture/mac/avfoundation_glue.h"
14 15
15 namespace { 16 namespace {
16 17
17 // This class is used to keep track of system devices names and their types. 18 // This class is used to keep track of system devices names and their types.
18 class DeviceInfo { 19 class DeviceInfo {
19 public: 20 public:
20 enum DeviceType { 21 enum DeviceType {
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 DeviceInfo([[device uniqueID] UTF8String], device_type)); 205 DeviceInfo([[device uniqueID] UTF8String], device_type));
205 } 206 }
206 ConsolidateDevicesListAndNotify(snapshot_devices); 207 ConsolidateDevicesListAndNotify(snapshot_devices);
207 } 208 }
208 209
209 // Forward declaration for use by CrAVFoundationDeviceObserver. 210 // Forward declaration for use by CrAVFoundationDeviceObserver.
210 class AVFoundationMonitorImpl; 211 class AVFoundationMonitorImpl;
211 212
212 } // namespace 213 } // namespace
213 214
214 // This class is a Key-Value Observer (KVO) shim. It is needed because C++ 215 // This class is a Key-Value Observer (KVO) shim. It is needed because C++
215 // classes cannot observe Key-Values directly. 216 // classes cannot observe Key-Values directly. This class is used by
217 // AVfoundationMonitorImpl and executed in its |device_task_runner_|, a.k.a.
218 // "Device Thread". -stopObserving is called dutifully on -dealloc on UI thread.
216 @interface CrAVFoundationDeviceObserver : NSObject { 219 @interface CrAVFoundationDeviceObserver : NSObject {
217 @private 220 @private
218 AVFoundationMonitorImpl* receiver_; 221 AVFoundationMonitorImpl* receiver_;
219 // Member to keep track of the devices we are already monitoring. 222 // Member to keep track of the devices we are already monitoring.
220 std::set<CrAVCaptureDevice*> monitoredDevices_; 223 std::set<CrAVCaptureDevice*> monitoredDevices_;
221 } 224 }
222 225
223 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver; 226 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver;
224 - (void)startObserving:(CrAVCaptureDevice*)device; 227 - (void)startObserving:(CrAVCaptureDevice*)device;
225 - (void)stopObserving:(CrAVCaptureDevice*)device; 228 - (void)stopObserving:(CrAVCaptureDevice*)device;
226 229
227 @end 230 @end
228 231
229 namespace { 232 namespace {
230 233
234 // AVFoundation implementation of the Mac Device Monitor, registers as a global
235 // 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
237 // and operations involving |suspend_observer_| happen on |device_task_runner_|.
231 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { 238 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
232 public: 239 public:
233 explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor); 240 AVFoundationMonitorImpl(
241 content::DeviceMonitorMac* monitor,
242 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
234 virtual ~AVFoundationMonitorImpl(); 243 virtual ~AVFoundationMonitorImpl();
235 244
236 virtual void OnDeviceChanged() OVERRIDE; 245 virtual void OnDeviceChanged() OVERRIDE;
237 246
238 private: 247 private:
248 void OnDeviceChangedOnDeviceThread(
249 const scoped_refptr<base::MessageLoopProxy>& ui_thread);
250 void StartObserverOnDeviceThread();
251
252 base::ThreadChecker thread_checker_;
253
254 // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
255 // device enumeration, valid after MediaStreamManager calls StartMonitoring().
256 const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
257
258 // Created and executed in |device_task_runnner_|.
239 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; 259 base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
260
240 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); 261 DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
241 }; 262 };
242 263
243 AVFoundationMonitorImpl::AVFoundationMonitorImpl( 264 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
244 content::DeviceMonitorMac* monitor) 265 content::DeviceMonitorMac* monitor,
245 : DeviceMonitorMacImpl(monitor) { 266 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
267 : DeviceMonitorMacImpl(monitor),
268 device_task_runner_(device_task_runner) {
246 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 269 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
247 device_arrival_ = 270 device_arrival_ =
248 [nc addObserverForName:AVFoundationGlue:: 271 [nc addObserverForName:AVFoundationGlue::
249 AVCaptureDeviceWasConnectedNotification() 272 AVCaptureDeviceWasConnectedNotification()
250 object:nil 273 object:nil
251 queue:nil 274 queue:nil
252 usingBlock:^(NSNotification* notification) { 275 usingBlock:^(NSNotification* notification) {
253 OnDeviceChanged();}]; 276 OnDeviceChanged();}];
254 device_removal_ = 277 device_removal_ =
255 [nc addObserverForName:AVFoundationGlue:: 278 [nc addObserverForName:AVFoundationGlue::
256 AVCaptureDeviceWasDisconnectedNotification() 279 AVCaptureDeviceWasDisconnectedNotification()
257 object:nil 280 object:nil
258 queue:nil 281 queue:nil
259 usingBlock:^(NSNotification* notification) { 282 usingBlock:^(NSNotification* notification) {
260 OnDeviceChanged();}]; 283 OnDeviceChanged();}];
261 suspend_observer_.reset( 284 device_task_runner_->PostTask(FROM_HERE,
262 [[CrAVFoundationDeviceObserver alloc] initWithChangeReceiver:this]); 285 base::Bind(&AVFoundationMonitorImpl::StartObserverOnDeviceThread,
263 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) 286 base::Unretained(this)));
264 [suspend_observer_ startObserving:device];
265 } 287 }
266 288
267 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { 289 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
268 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 290 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
269 [nc removeObserver:device_arrival_]; 291 [nc removeObserver:device_arrival_];
270 [nc removeObserver:device_removal_]; 292 [nc removeObserver:device_removal_];
271 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
272 [suspend_observer_ stopObserving:device];
273 } 293 }
274 294
275 void AVFoundationMonitorImpl::OnDeviceChanged() { 295 void AVFoundationMonitorImpl::OnDeviceChanged() {
296 DCHECK(thread_checker_.CalledOnValidThread());
297 device_task_runner_->PostTask(FROM_HERE,
298 base::Bind(&AVFoundationMonitorImpl::OnDeviceChangedOnDeviceThread,
299 base::Unretained(this),
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];
276 std::vector<DeviceInfo> snapshot_devices; 307 std::vector<DeviceInfo> snapshot_devices;
277 for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) { 308 for (CrAVCaptureDevice* device in devices) {
278 [suspend_observer_ startObserving:device]; 309 [suspend_observer_ startObserving:device];
279 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && 310 BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
280 [device isSuspended]; 311 [device isSuspended];
281 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; 312 DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
282 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { 313 if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
283 if (suspended) 314 if (suspended)
284 continue; 315 continue;
285 device_type = DeviceInfo::kVideo; 316 device_type = DeviceInfo::kVideo;
286 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { 317 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
287 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; 318 device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
288 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { 319 } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
289 device_type = DeviceInfo::kAudio; 320 device_type = DeviceInfo::kAudio;
290 } 321 }
291 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String], 322 snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
292 device_type)); 323 device_type));
293 } 324 }
294 ConsolidateDevicesListAndNotify(snapshot_devices); 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];
295 } 337 }
296 338
297 } // namespace 339 } // namespace
298 340
299 @implementation CrAVFoundationDeviceObserver 341 @implementation CrAVFoundationDeviceObserver
300 342
301 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver { 343 - (id)initWithChangeReceiver:(AVFoundationMonitorImpl*)receiver {
302 if ((self = [super init])) { 344 if ((self = [super init])) {
303 DCHECK(receiver != NULL); 345 DCHECK(receiver != NULL);
304 receiver_ = receiver; 346 receiver_ = receiver;
305 } 347 }
306 return self; 348 return self;
307 } 349 }
308 350
351 - (void)dealloc {
352 std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
353 while (it != monitoredDevices_.end())
354 [self stopObserving:*it++];
355 [super dealloc];
356 }
357
309 - (void)startObserving:(CrAVCaptureDevice*)device { 358 - (void)startObserving:(CrAVCaptureDevice*)device {
310 DCHECK(device != nil); 359 DCHECK(device != nil);
311 // Skip this device if there are already observers connected to it. 360 // Skip this device if there are already observers connected to it.
312 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != 361 if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
313 monitoredDevices_.end()) { 362 monitoredDevices_.end()) {
314 return; 363 return;
315 } 364 }
316 [device addObserver:self 365 [device addObserver:self
317 forKeyPath:@"suspended" 366 forKeyPath:@"suspended"
318 options:0 367 options:0
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 401
353 DeviceMonitorMac::DeviceMonitorMac() { 402 DeviceMonitorMac::DeviceMonitorMac() {
354 // Both QTKit and AVFoundation do not need to be fired up until the user 403 // Both QTKit and AVFoundation do not need to be fired up until the user
355 // exercises a GetUserMedia. Bringing up either library and enumerating the 404 // exercises a GetUserMedia. Bringing up either library and enumerating the
356 // devices in the system is an operation taking in the range of hundred of ms, 405 // devices in the system is an operation taking in the range of hundred of ms,
357 // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). 406 // so it is triggered explicitly from MediaStreamManager::StartMonitoring().
358 } 407 }
359 408
360 DeviceMonitorMac::~DeviceMonitorMac() {} 409 DeviceMonitorMac::~DeviceMonitorMac() {}
361 410
362 void DeviceMonitorMac::StartMonitoring() { 411 void DeviceMonitorMac::StartMonitoring(
412 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
363 DCHECK(thread_checker_.CalledOnValidThread()); 413 DCHECK(thread_checker_.CalledOnValidThread());
364 if (AVFoundationGlue::IsAVFoundationSupported()) { 414 if (AVFoundationGlue::IsAVFoundationSupported()) {
365 DVLOG(1) << "Monitoring via AVFoundation"; 415 DVLOG(1) << "Monitoring via AVFoundation";
366 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this)); 416 device_monitor_impl_.reset(new AVFoundationMonitorImpl(this,
417 device_task_runner));
367 } else { 418 } else {
368 DVLOG(1) << "Monitoring via QTKit"; 419 DVLOG(1) << "Monitoring via QTKit";
369 device_monitor_impl_.reset(new QTKitMonitorImpl(this)); 420 device_monitor_impl_.reset(new QTKitMonitorImpl(this));
370 } 421 }
371 } 422 }
372 423
373 void DeviceMonitorMac::NotifyDeviceChanged( 424 void DeviceMonitorMac::NotifyDeviceChanged(
374 base::SystemMonitor::DeviceType type) { 425 base::SystemMonitor::DeviceType type) {
426 DCHECK(thread_checker_.CalledOnValidThread());
375 // TODO(xians): Remove the global variable for SystemMonitor. 427 // TODO(xians): Remove the global variable for SystemMonitor.
376 base::SystemMonitor::Get()->ProcessDevicesChanged(type); 428 base::SystemMonitor::Get()->ProcessDevicesChanged(type);
377 } 429 }
378 430
379 } // namespace content 431 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | content/browser/renderer_host/media/media_stream_manager.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698