| Index: media/capture/device_monitor_mac.mm
|
| diff --git a/media/capture/device_monitor_mac.mm b/media/capture/device_monitor_mac.mm
|
| deleted file mode 100644
|
| index 2ff63e0adcca95bf05e0c00ee319ffe45605c8d5..0000000000000000000000000000000000000000
|
| --- a/media/capture/device_monitor_mac.mm
|
| +++ /dev/null
|
| @@ -1,475 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "media/capture/device_monitor_mac.h"
|
| -
|
| -#include <set>
|
| -
|
| -#include "base/bind_helpers.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/bind_objc_block.h"
|
| -#include "base/mac/scoped_nsobject.h"
|
| -#include "base/macros.h"
|
| -#include "base/profiler/scoped_tracker.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/threading/thread_checker.h"
|
| -#import "media/base/mac/avfoundation_glue.h"
|
| -
|
| -namespace {
|
| -
|
| -// This class is used to keep track of system devices names and their types.
|
| -class DeviceInfo {
|
| - public:
|
| - enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid };
|
| -
|
| - DeviceInfo(const std::string& unique_id, DeviceType type)
|
| - : unique_id_(unique_id), type_(type) {}
|
| -
|
| - // Operator== is needed here to use this class in a std::find. A given
|
| - // |unique_id_| always has the same |type_| so for comparison purposes the
|
| - // latter can be safely ignored.
|
| - bool operator==(const DeviceInfo& device) const {
|
| - return unique_id_ == device.unique_id_;
|
| - }
|
| -
|
| - const std::string& unique_id() const { return unique_id_; }
|
| - DeviceType type() const { return type_; }
|
| -
|
| - private:
|
| - std::string unique_id_;
|
| - DeviceType type_;
|
| - // Allow generated copy constructor and assignment.
|
| -};
|
| -
|
| -// Base abstract class used by DeviceMonitorMac.
|
| -class DeviceMonitorMacImpl {
|
| - public:
|
| - explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor)
|
| - : monitor_(monitor),
|
| - cached_devices_(),
|
| - device_arrival_(nil),
|
| - device_removal_(nil) {
|
| - DCHECK(monitor);
|
| - // Initialise the devices_cache_ with a not-valid entry. For the case in
|
| - // which there is one single device in the system and we get notified when
|
| - // it gets removed, this will prevent the system from thinking that no
|
| - // devices were added nor removed and not notifying the |monitor_|.
|
| - cached_devices_.push_back(DeviceInfo("invalid", DeviceInfo::kInvalid));
|
| - }
|
| - virtual ~DeviceMonitorMacImpl() {}
|
| -
|
| - virtual void OnDeviceChanged() = 0;
|
| -
|
| - // Method called by the default notification center when a device is removed
|
| - // or added to the system. It will compare the |cached_devices_| with the
|
| - // current situation, update it, and, if there's an update, signal to
|
| - // |monitor_| with the appropriate device type.
|
| - void ConsolidateDevicesListAndNotify(
|
| - const std::vector<DeviceInfo>& snapshot_devices);
|
| -
|
| - protected:
|
| - media::DeviceMonitorMac* monitor_;
|
| - std::vector<DeviceInfo> cached_devices_;
|
| -
|
| - // Handles to NSNotificationCenter block observers.
|
| - id device_arrival_;
|
| - id device_removal_;
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl);
|
| -};
|
| -
|
| -void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
|
| - const std::vector<DeviceInfo>& snapshot_devices) {
|
| - bool video_device_added = false;
|
| - bool audio_device_added = false;
|
| - bool video_device_removed = false;
|
| - bool audio_device_removed = false;
|
| -
|
| - // Compare the current system devices snapshot with the ones cached to detect
|
| - // additions, present in the former but not in the latter. If we find a device
|
| - // in snapshot_devices entry also present in cached_devices, we remove it from
|
| - // the latter vector.
|
| - std::vector<DeviceInfo>::const_iterator it;
|
| - for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
|
| - std::vector<DeviceInfo>::iterator cached_devices_iterator =
|
| - std::find(cached_devices_.begin(), cached_devices_.end(), *it);
|
| - if (cached_devices_iterator == cached_devices_.end()) {
|
| - video_device_added |= ((it->type() == DeviceInfo::kVideo) ||
|
| - (it->type() == DeviceInfo::kMuxed));
|
| - audio_device_added |= ((it->type() == DeviceInfo::kAudio) ||
|
| - (it->type() == DeviceInfo::kMuxed));
|
| - DVLOG(1) << "Device has been added, id: " << it->unique_id();
|
| - } else {
|
| - cached_devices_.erase(cached_devices_iterator);
|
| - }
|
| - }
|
| - // All the remaining entries in cached_devices are removed devices.
|
| - for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
|
| - video_device_removed |= ((it->type() == DeviceInfo::kVideo) ||
|
| - (it->type() == DeviceInfo::kMuxed) ||
|
| - (it->type() == DeviceInfo::kInvalid));
|
| - audio_device_removed |= ((it->type() == DeviceInfo::kAudio) ||
|
| - (it->type() == DeviceInfo::kMuxed) ||
|
| - (it->type() == DeviceInfo::kInvalid));
|
| - DVLOG(1) << "Device has been removed, id: " << it->unique_id();
|
| - }
|
| - // Update the cached devices with the current system snapshot.
|
| - cached_devices_ = snapshot_devices;
|
| -
|
| - if (video_device_added || video_device_removed)
|
| - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
|
| - if (audio_device_added || audio_device_removed)
|
| - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
|
| -}
|
| -
|
| -// Forward declaration for use by CrAVFoundationDeviceObserver.
|
| -class SuspendObserverDelegate;
|
| -
|
| -} // namespace
|
| -
|
| -// 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 UI Thread by SuspendObserverDelegate.
|
| -@interface CrAVFoundationDeviceObserver : NSObject {
|
| - @private
|
| - // 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<base::scoped_nsobject<CrAVCaptureDevice>> monitoredDevices_;
|
| -
|
| - // Pegged to the "main" thread -- usually content::BrowserThread::UI.
|
| - base::ThreadChecker mainThreadChecker_;
|
| -}
|
| -
|
| -- (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.
|
| -// It is created and destroyed on AVFoundationMonitorImpl's main thread (usually
|
| -// browser's UI thread), 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);
|
| -
|
| - // 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();
|
| -
|
| - // 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::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
|
| - DeviceMonitorMacImpl* avfoundation_monitor_impl_;
|
| -
|
| - // Pegged to the "main" thread -- usually content::BrowserThread::UI.
|
| - base::ThreadChecker main_thread_checker_;
|
| -};
|
| -
|
| -SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
|
| - : avfoundation_monitor_impl_(monitor) {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| -}
|
| -
|
| -void SuspendObserverDelegate::StartObserver(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| -
|
| - 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(main_thread_checker_.CalledOnValidThread());
|
| - // Enumerate the devices in Device thread and post the consolidation of the
|
| - // new devices and the old ones to be done on main 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(main_thread_checker_.CalledOnValidThread());
|
| - avfoundation_monitor_impl_ = NULL;
|
| - [suspend_observer_ clearOnDeviceChangedCallback];
|
| -}
|
| -
|
| -SuspendObserverDelegate::~SuspendObserverDelegate() {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| -}
|
| -
|
| -void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| - 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(main_thread_checker_.CalledOnValidThread());
|
| - base::scoped_nsobject<NSArray> auto_release(devices);
|
| - std::vector<DeviceInfo> snapshot_devices;
|
| - for (CrAVCaptureDevice* device in devices) {
|
| - 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;
|
| - if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
|
| - if (suspended)
|
| - continue;
|
| - device_type = DeviceInfo::kVideo;
|
| - } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
|
| - device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
|
| - } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
|
| - device_type = DeviceInfo::kAudio;
|
| - }
|
| - snapshot_devices.push_back(
|
| - DeviceInfo([[device uniqueID] UTF8String], device_type));
|
| - }
|
| - // Make sure no references are held to |devices| when
|
| - // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager
|
| - // and AudioCaptureManagers also enumerates the available devices but on
|
| - // another thread.
|
| - auto_release.reset();
|
| - // |avfoundation_monitor_impl_| might have been NULLed asynchronously before
|
| - // arriving at this line.
|
| - if (avfoundation_monitor_impl_) {
|
| - avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
|
| - snapshot_devices);
|
| - }
|
| -}
|
| -
|
| -// AVFoundation implementation of the Mac Device Monitor, registers as a global
|
| -// device connect/disconnect observer and plugs suspend/wake up device observers
|
| -// per device. This class is created and lives on the main Application thread
|
| -// (UI for content). Owns a SuspendObserverDelegate that notifies when a device
|
| -// is suspended/resumed.
|
| -class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
|
| - public:
|
| - AVFoundationMonitorImpl(
|
| - media::DeviceMonitorMac* monitor,
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
|
| - ~AVFoundationMonitorImpl() override;
|
| -
|
| - void OnDeviceChanged() override;
|
| -
|
| - private:
|
| - // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
|
| - // posting tasks to |suspend_observer_delegate_|;
|
| - const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
|
| -
|
| - // Pegged to the "main" thread -- usually content::BrowserThread::UI.
|
| - base::ThreadChecker main_thread_checker_;
|
| -
|
| - scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
|
| -};
|
| -
|
| -AVFoundationMonitorImpl::AVFoundationMonitorImpl(
|
| - media::DeviceMonitorMac* monitor,
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
|
| - : DeviceMonitorMacImpl(monitor),
|
| - device_task_runner_(device_task_runner),
|
| - suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
| - device_arrival_ =
|
| - [nc addObserverForName:AVFoundationGlue::
|
| - AVCaptureDeviceWasConnectedNotification()
|
| - object:nil
|
| - queue:nil
|
| - usingBlock:^(NSNotification* notification) {
|
| - OnDeviceChanged();
|
| - }];
|
| - device_removal_ =
|
| - [nc addObserverForName:AVFoundationGlue::
|
| - AVCaptureDeviceWasDisconnectedNotification()
|
| - object:nil
|
| - queue:nil
|
| - usingBlock:^(NSNotification* notification) {
|
| - OnDeviceChanged();
|
| - }];
|
| - suspend_observer_delegate_->StartObserver(device_task_runner_);
|
| -}
|
| -
|
| -AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| - suspend_observer_delegate_->ResetDeviceMonitor();
|
| - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
| - [nc removeObserver:device_arrival_];
|
| - [nc removeObserver:device_removal_];
|
| -}
|
| -
|
| -void AVFoundationMonitorImpl::OnDeviceChanged() {
|
| - DCHECK(main_thread_checker_.CalledOnValidThread());
|
| - suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -@implementation CrAVFoundationDeviceObserver
|
| -
|
| -- (id)initWithOnChangedCallback:(const base::Closure&)callback {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - if ((self = [super init])) {
|
| - DCHECK(!callback.is_null());
|
| - onDeviceChangedCallback_ = callback;
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (void)dealloc {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator it =
|
| - monitoredDevices_.begin();
|
| - while (it != monitoredDevices_.end())
|
| - [self removeObservers:*(it++)];
|
| - [super dealloc];
|
| -}
|
| -
|
| -- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - DCHECK(device != nil);
|
| - // Skip this device if there are already observers connected to it.
|
| - if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
|
| - monitoredDevices_.end()) {
|
| - return;
|
| - }
|
| - [device addObserver:self
|
| - forKeyPath:@"suspended"
|
| - options:0
|
| - context:device.get()];
|
| - [device addObserver:self
|
| - forKeyPath:@"connected"
|
| - options:0
|
| - context:device.get()];
|
| - monitoredDevices_.insert(device);
|
| -}
|
| -
|
| -- (void)stopObserving:(CrAVCaptureDevice*)device {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - DCHECK(device != nil);
|
| -
|
| - std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator found =
|
| - std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
|
| - DCHECK(found != monitoredDevices_.end());
|
| - [self removeObservers:*found];
|
| - monitoredDevices_.erase(found);
|
| -}
|
| -
|
| -- (void)clearOnDeviceChangedCallback {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - onDeviceChangedCallback_.Reset();
|
| -}
|
| -
|
| -- (void)removeObservers:(CrAVCaptureDevice*)device {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
|
| - if ([device observationInfo]) {
|
| - [device removeObserver:self
|
| - forKeyPath:@"suspended"];
|
| - [device removeObserver:self
|
| - forKeyPath:@"connected"];
|
| - }
|
| -}
|
| -
|
| -- (void)observeValueForKeyPath:(NSString*)keyPath
|
| - ofObject:(id)object
|
| - change:(NSDictionary*)change
|
| - context:(void*)context {
|
| - DCHECK(mainThreadChecker_.CalledOnValidThread());
|
| - if ([keyPath isEqual:@"suspended"])
|
| - onDeviceChangedCallback_.Run();
|
| - if ([keyPath isEqual:@"connected"])
|
| - [self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
|
| -}
|
| -
|
| -@end // @implementation CrAVFoundationDeviceObserver
|
| -
|
| -namespace media {
|
| -
|
| -DeviceMonitorMac::DeviceMonitorMac() {
|
| - // AVFoundation do not need to be fired up until the user
|
| - // exercises a GetUserMedia. Bringing up either library and enumerating the
|
| - // devices in the system is an operation taking in the range of hundred of ms,
|
| - // so it is triggered explicitly from MediaStreamManager::StartMonitoring().
|
| -}
|
| -
|
| -DeviceMonitorMac::~DeviceMonitorMac() {}
|
| -
|
| -void DeviceMonitorMac::StartMonitoring(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // We're on the UI thread so let's try to initialize AVFoundation.
|
| - AVFoundationGlue::InitializeAVFoundation();
|
| -
|
| - // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
|
| - // is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "458404 DeviceMonitorMac::StartMonitoring::AVFoundation"));
|
| - DVLOG(1) << "Monitoring via AVFoundation";
|
| - device_monitor_impl_.reset(
|
| - new AVFoundationMonitorImpl(this, device_task_runner));
|
| -}
|
| -
|
| -void DeviceMonitorMac::NotifyDeviceChanged(
|
| - base::SystemMonitor::DeviceType type) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - // TODO(xians): Remove the global variable for SystemMonitor.
|
| - base::SystemMonitor::Get()->ProcessDevicesChanged(type);
|
| -}
|
| -
|
| -} // namespace media
|
|
|