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

Unified Diff: content/browser/device_monitor_mac.mm

Issue 368613002: DeviceMonitorMac: move CrAVFoundationDeviceObserver and most of SuspendObserverDelegate to UI Thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tommi@s 2nd round of comments Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/device_monitor_mac.mm
diff --git a/content/browser/device_monitor_mac.mm b/content/browser/device_monitor_mac.mm
index eb429afe6402bb07bfc3f100ec31e9c05e2665e9..ccea3a9d4e4de889c09884467654a33d266242e5 100644
--- a/content/browser/device_monitor_mac.mm
+++ b/content/browser/device_monitor_mac.mm
@@ -10,9 +10,11 @@
#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"
+#include "media/base/bind_to_current_loop.h"
#import "media/video/capture/mac/avfoundation_glue.h"
namespace {
@@ -47,6 +49,18 @@ class DeviceInfo {
// Allow generated copy constructor and assignment.
};
+class CrAVCaptureDeviceRefCounted :
Robert Sesek 2014/07/07 22:47:50 I don't understand the point of this class. CrAVCa
mcasas 2014/07/08 15:11:46 Gone; you're right it wasn't needed.
+ public base::RefCountedThreadSafe<CrAVCaptureDeviceRefCounted> {
+ public:
+ explicit CrAVCaptureDeviceRefCounted(CrAVCaptureDevice* device)
+ : device_(device) {}
+ private:
+ friend class base::RefCountedThreadSafe<CrAVCaptureDeviceRefCounted>;
+ ~CrAVCaptureDeviceRefCounted() {};
+
+ CrAVCaptureDevice* device_;
+};
+
// Base abstract class used by DeviceMonitorMac to interact with either a QTKit
// or an AVFoundation implementation of events and notifications.
class DeviceMonitorMacImpl {
@@ -216,15 +230,15 @@ 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
+ base::Closure onDeviceChangedCallback_;
Robert Sesek 2014/07/07 22:47:49 nit: blank line after, and a comment (e.g. on what
mcasas 2014/07/08 15:11:45 Done.
// Member to keep track of the devices we are already monitoring.
std::set<CrAVCaptureDevice*> monitoredDevices_;
}
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver;
+- (id)initWithOnChangedCallback:(const base::Closure&)callback;
- (void)startObserving:(CrAVCaptureDevice*)device;
- (void)stopObserving:(CrAVCaptureDevice*)device;
@@ -233,14 +247,15 @@ class SuspendObserverDelegate;
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.
+// AVFoundationMonitorImpl creates and destroys it in UI thread. Runs the
+// expensive device enumerations in OnDeviceChanged() and StartObserver() on
+// Device Thread.
class SuspendObserverDelegate :
public base::RefCountedThreadSafe<SuspendObserverDelegate> {
public:
explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
: avfoundation_monitor_impl_(monitor) {
Robert Sesek 2014/07/07 22:47:49 Please move the ctor and dtor out of line, like th
mcasas 2014/07/08 15:11:46 Done.
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
device_thread_checker_.DetachFromThread();
}
@@ -251,22 +266,27 @@ class SuspendObserverDelegate :
private:
friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
- virtual ~SuspendObserverDelegate() {}
+ virtual ~SuspendObserverDelegate() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
Robert Sesek 2014/07/07 22:47:49 You could add a |using content::BrowserThread| if
mcasas 2014/07/08 15:11:46 Great, less verbosity, done.
+ }
void OnDeviceChangedOnUIThread(
const std::vector<DeviceInfo>& snapshot_devices);
base::ThreadChecker device_thread_checker_;
+ // Created, used and released in UI thread.
base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
DeviceMonitorMacImpl* avfoundation_monitor_impl_;
};
void SuspendObserverDelegate::OnDeviceChanged() {
DCHECK(device_thread_checker_.CalledOnValidThread());
- NSArray* devices = [AVCaptureDeviceGlue devices];
std::vector<DeviceInfo> snapshot_devices;
- for (CrAVCaptureDevice* device in devices) {
- [suspend_observer_ startObserving:device];
+ for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) {
+ scoped_refptr<CrAVCaptureDeviceRefCounted> device_refptr =
+ new CrAVCaptureDeviceRefCounted(device);
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::BindBlock(^{ [suspend_observer_ startObserving:device]; }));
BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
[device isSuspended];
DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
@@ -290,10 +310,20 @@ void SuspendObserverDelegate::OnDeviceChanged() {
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];
+
+ base::Closure on_device_changed_callback = media::BindToCurrentLoop(
+ base::Bind(&SuspendObserverDelegate::OnDeviceChanged, this));
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::BindBlock(^{ suspend_observer_.reset(
Robert Sesek 2014/07/07 22:47:50 nit: keep ^{ on this line but start the content of
mcasas 2014/07/08 15:11:45 Done.
+ [[CrAVFoundationDeviceObserver alloc]
+ initWithOnChangedCallback:on_device_changed_callback]);
+ }));
+ for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices]) {
+ scoped_refptr<CrAVCaptureDeviceRefCounted> device_refptr =
+ new CrAVCaptureDeviceRefCounted(device);
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::BindBlock(^{ [suspend_observer_ startObserving:device]; }));
+ }
}
void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() {
@@ -384,22 +414,27 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
@implementation CrAVFoundationDeviceObserver
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
+- (id)initWithOnChangedCallback:(const base::Closure&)callback {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if ((self = [super init])) {
- DCHECK(receiver != NULL);
- receiver_ = receiver;
+ DCHECK(!callback.is_null());
+ onDeviceChangedCallback_ = callback;
}
return self;
}
- (void)dealloc {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
- while (it != monitoredDevices_.end())
- [self stopObserving:*it++];
+ while (it != monitoredDevices_.end()) {
+ [self removeObservers:*it];
+ monitoredDevices_.erase(it++);
+ }
[super dealloc];
}
- (void)startObserving:(CrAVCaptureDevice*)device {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(device != nil);
// Skip this device if there are already observers connected to it.
if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
@@ -418,28 +453,32 @@ void AVFoundationMonitorImpl::OnDeviceChanged() {
}
- (void)stopObserving:(CrAVCaptureDevice*)device {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(device != nil);
std::set<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)removeObservers:(CrAVCaptureDevice*)device {
+ // 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(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if ([keyPath isEqual:@"suspended"])
- receiver_->OnDeviceChanged();
+ onDeviceChangedCallback_.Run();
Robert Sesek 2014/07/07 22:47:50 Won't this run the callback on the UI thread, rath
mcasas 2014/07/08 15:11:46 l.314 media::BindToCurrentLoop does the magic of c
Robert Sesek 2014/07/08 17:05:39 Looks like this got dropped in the latest patch se
if ([keyPath isEqual:@"connected"])
[self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
}
« 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