summaryrefslogtreecommitdiff
path: root/chromium/content/browser/device_monitor_mac.mm
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@theqtcompany.com>2014-12-05 15:04:29 +0100
committerAndras Becsi <andras.becsi@theqtcompany.com>2014-12-09 10:49:28 +0100
commitaf6588f8d723931a298c995fa97259bb7f7deb55 (patch)
tree060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/content/browser/device_monitor_mac.mm
parent2fff84d821cc7b1c785f6404e0f8091333283e74 (diff)
downloadqtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181 Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/content/browser/device_monitor_mac.mm')
-rw-r--r--chromium/content/browser/device_monitor_mac.mm224
1 files changed, 145 insertions, 79 deletions
diff --git a/chromium/content/browser/device_monitor_mac.mm b/chromium/content/browser/device_monitor_mac.mm
index eb429afe640..f33c09752ea 100644
--- a/chromium/content/browser/device_monitor_mac.mm
+++ b/chromium/content/browser/device_monitor_mac.mm
@@ -10,10 +10,13 @@
#include "base/bind_helpers.h"
#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
#include "base/mac/scoped_nsobject.h"
#include "base/threading/thread_checker.h"
#include "content/public/browser/browser_thread.h"
-#import "media/video/capture/mac/avfoundation_glue.h"
+#import "media/base/mac/avfoundation_glue.h"
+
+using content::BrowserThread;
namespace {
@@ -133,9 +136,10 @@ void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
class QTKitMonitorImpl : public DeviceMonitorMacImpl {
public:
explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
- virtual ~QTKitMonitorImpl();
+ ~QTKitMonitorImpl() override;
+
+ void OnDeviceChanged() override;
- virtual void OnDeviceChanged() OVERRIDE;
private:
void CountDevices();
void OnAttributeChanged(NSNotification* notification);
@@ -216,57 +220,131 @@ class SuspendObserverDelegate;
// This class is a Key-Value Observer (KVO) shim. It is needed because C++
// classes cannot observe Key-Values directly. Created, manipulated, and
-// destroyed on the Device Thread by SuspendedObserverDelegate.
+// destroyed on the UI Thread by SuspendObserverDelegate.
@interface CrAVFoundationDeviceObserver : NSObject {
@private
- SuspendObserverDelegate* receiver_; // weak
+ // Callback for device changed, has to run on Device Thread.
+ base::Closure onDeviceChangedCallback_;
+
// Member to keep track of the devices we are already monitoring.
- std::set<CrAVCaptureDevice*> monitoredDevices_;
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_;
}
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver;
-- (void)startObserving:(CrAVCaptureDevice*)device;
+- (id)initWithOnChangedCallback:(const base::Closure&)callback;
+- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device;
- (void)stopObserving:(CrAVCaptureDevice*)device;
+- (void)clearOnDeviceChangedCallback;
@end
namespace {
// This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
-// Provides a callback for this device observer to indicate that there has been
-// a device change of some kind. Created by AVFoundationMonitorImpl in UI thread
-// but living in Device Thread.
+// It is created and destroyed in UI thread by AVFoundationMonitorImpl, and it
+// operates on this thread except for the expensive device enumerations which
+// are run on Device Thread.
class SuspendObserverDelegate :
public base::RefCountedThreadSafe<SuspendObserverDelegate> {
public:
- explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
- : avfoundation_monitor_impl_(monitor) {
- device_thread_checker_.DetachFromThread();
- }
-
- void OnDeviceChanged();
- void StartObserver();
- void ResetDeviceMonitorOnUIThread();
+ explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor);
+
+ // Create |suspend_observer_| for all devices and register OnDeviceChanged()
+ // as its change callback. Schedule bottom half in DoStartObserver().
+ void StartObserver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
+ // Enumerate devices in |device_thread| and run the bottom half in
+ // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event,
+ // and our parent AVFoundationMonitorImpl calls on connect/disconnect device.
+ void OnDeviceChanged(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
+ // Remove the device monitor's weak reference. Remove ourselves as suspend
+ // notification observer from |suspend_observer_|.
+ void ResetDeviceMonitor();
private:
friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
- virtual ~SuspendObserverDelegate() {}
+ virtual ~SuspendObserverDelegate();
- void OnDeviceChangedOnUIThread(
- const std::vector<DeviceInfo>& snapshot_devices);
+ // Bottom half of StartObserver(), starts |suspend_observer_| for all devices.
+ // Assumes that |devices| has been retained prior to being called, and
+ // releases it internally.
+ void DoStartObserver(NSArray* devices);
+ // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current
+ // devices and composes a snapshot of them to send it to
+ // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained
+ // prior to being called, and releases it internally.
+ void DoOnDeviceChanged(NSArray* devices);
- base::ThreadChecker device_thread_checker_;
base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
DeviceMonitorMacImpl* avfoundation_monitor_impl_;
};
-void SuspendObserverDelegate::OnDeviceChanged() {
- DCHECK(device_thread_checker_.CalledOnValidThread());
- NSArray* devices = [AVCaptureDeviceGlue devices];
+SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
+ : avfoundation_monitor_impl_(monitor) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void SuspendObserverDelegate::StartObserver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ base::Closure on_device_changed_callback =
+ base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
+ this, device_thread);
+ suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
+ initWithOnChangedCallback:on_device_changed_callback]);
+
+ // Enumerate the devices in Device thread and post the observers start to be
+ // done on UI thread. The devices array is retained in |device_thread| and
+ // released in DoStartObserver().
+ base::PostTaskAndReplyWithResult(
+ device_thread.get(),
+ FROM_HERE,
+ base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
+ base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
+}
+
+void SuspendObserverDelegate::OnDeviceChanged(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Enumerate the devices in Device thread and post the consolidation of the
+ // new devices and the old ones to be done on UI thread. The devices array
+ // is retained in |device_thread| and released in DoOnDeviceChanged().
+ PostTaskAndReplyWithResult(
+ device_thread.get(),
+ FROM_HERE,
+ base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
+ base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
+}
+
+void SuspendObserverDelegate::ResetDeviceMonitor() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ avfoundation_monitor_impl_ = NULL;
+ [suspend_observer_ clearOnDeviceChangedCallback];
+}
+
+SuspendObserverDelegate::~SuspendObserverDelegate() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::scoped_nsobject<NSArray> auto_release(devices);
+ for (CrAVCaptureDevice* device in devices) {
+ base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
+ [suspend_observer_ startObserving:device_ptr];
+ }
+}
+
+void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::scoped_nsobject<NSArray> auto_release(devices);
std::vector<DeviceInfo> snapshot_devices;
for (CrAVCaptureDevice* device in devices) {
- [suspend_observer_ startObserving:device];
+ base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
+ [suspend_observer_ startObserving:device_ptr];
+
BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
[device isSuspended];
DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
@@ -282,28 +360,7 @@ void SuspendObserverDelegate::OnDeviceChanged() {
snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
device_type));
}
- // Post the consolidation of enumerated devices to be done on UI thread.
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(&SuspendObserverDelegate::OnDeviceChangedOnUIThread,
- this, snapshot_devices));
-}
-void SuspendObserverDelegate::StartObserver() {
- DCHECK(device_thread_checker_.CalledOnValidThread());
- suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
- initWithChangeReceiver:this]);
- for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
- [suspend_observer_ startObserving:device];
-}
-
-void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- avfoundation_monitor_impl_ = NULL;
-}
-
-void SuspendObserverDelegate::OnDeviceChangedOnUIThread(
- const std::vector<DeviceInfo>& snapshot_devices) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// |avfoundation_monitor_impl_| might have been NULLed asynchronously before
// arriving at this line.
if (avfoundation_monitor_impl_) {
@@ -314,21 +371,18 @@ void SuspendObserverDelegate::OnDeviceChangedOnUIThread(
// AVFoundation implementation of the Mac Device Monitor, registers as a global
// device connect/disconnect observer and plugs suspend/wake up device observers
-// per device. Owns a SuspendObserverDelegate living in |device_task_runner_|
-// and gets notified when a device is suspended/resumed. This class is created
-// and lives in UI thread;
+// per device. This class is created and lives in UI thread. Owns a
+// SuspendObserverDelegate that notifies when a device is suspended/resumed.
class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
public:
AVFoundationMonitorImpl(
content::DeviceMonitorMac* monitor,
const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
- virtual ~AVFoundationMonitorImpl();
+ ~AVFoundationMonitorImpl() override;
- virtual void OnDeviceChanged() OVERRIDE;
+ void OnDeviceChanged() override;
private:
- base::ThreadChecker thread_checker_;
-
// {Video,AudioInput}DeviceManager's "Device" thread task runner used for
// posting tasks to |suspend_observer_delegate_|; valid after
// MediaStreamManager calls StartMonitoring().
@@ -345,6 +399,7 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
: DeviceMonitorMacImpl(monitor),
device_task_runner_(device_task_runner),
suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
device_arrival_ =
[nc addObserverForName:AVFoundationGlue::
@@ -360,86 +415,97 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
queue:nil
usingBlock:^(NSNotification* notification) {
OnDeviceChanged();}];
- device_task_runner_->PostTask(FROM_HERE,
- base::Bind(&SuspendObserverDelegate::StartObserver,
- suspend_observer_delegate_));
+ suspend_observer_delegate_->StartObserver(device_task_runner_);
}
AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
- DCHECK(thread_checker_.CalledOnValidThread());
- suspend_observer_delegate_->ResetDeviceMonitorOnUIThread();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ suspend_observer_delegate_->ResetDeviceMonitor();
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:device_arrival_];
[nc removeObserver:device_removal_];
}
void AVFoundationMonitorImpl::OnDeviceChanged() {
- DCHECK(thread_checker_.CalledOnValidThread());
- device_task_runner_->PostTask(FROM_HERE,
- base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
- suspend_observer_delegate_));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
}
} // namespace
@implementation CrAVFoundationDeviceObserver
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
+- (id)initWithOnChangedCallback:(const base::Closure&)callback {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if ((self = [super init])) {
- DCHECK(receiver != NULL);
- receiver_ = receiver;
+ DCHECK(!callback.is_null());
+ onDeviceChangedCallback_ = callback;
}
return self;
}
- (void)dealloc {
- std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
+ monitoredDevices_.begin();
while (it != monitoredDevices_.end())
- [self stopObserving:*it++];
+ [self removeObservers:*(it++)];
[super dealloc];
}
-- (void)startObserving:(CrAVCaptureDevice*)device {
+- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(device != nil);
// Skip this device if there are already observers connected to it.
if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
- monitoredDevices_.end()) {
+ monitoredDevices_.end()) {
return;
}
[device addObserver:self
forKeyPath:@"suspended"
options:0
- context:device];
+ context:device.get()];
[device addObserver:self
forKeyPath:@"connected"
options:0
- context:device];
+ context:device.get()];
monitoredDevices_.insert(device);
}
- (void)stopObserving:(CrAVCaptureDevice*)device {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(device != nil);
- std::set<CrAVCaptureDevice*>::iterator found =
+
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
DCHECK(found != monitoredDevices_.end());
- // Every so seldom, |device| might be gone when getting here, in that case
- // removing the observer causes a crash. Try to avoid it by checking sanity of
- // the |device| via its -observationInfo. http://crbug.com/371271.
+ [self removeObservers:*found];
+ monitoredDevices_.erase(found);
+}
+
+- (void)clearOnDeviceChangedCallback {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ onDeviceChangedCallback_.Reset();
+}
+
+- (void)removeObservers:(CrAVCaptureDevice*)device {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
if ([device observationInfo]) {
[device removeObserver:self
forKeyPath:@"suspended"];
[device removeObserver:self
forKeyPath:@"connected"];
}
- monitoredDevices_.erase(found);
}
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if ([keyPath isEqual:@"suspended"])
- receiver_->OnDeviceChanged();
+ onDeviceChangedCallback_.Run();
if ([keyPath isEqual:@"connected"])
[self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
}