Commit 14625448 authored by xians@chromium.org's avatar xians@chromium.org

Add DeviceMonitorMac to BrowserMainLoop.

DeviceMonitorMac detects device changing and forwards the notifications to the system monitor.



BUG=137799


Review URL: https://chromiumcodereview.appspot.com/10824162

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151689 0039d316-1c4b-4281-b951-d872f2087c98
parent f2d73616
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
#if defined(OS_LINUX) #if defined(OS_LINUX)
#include "content/browser/device_monitor_linux.h" #include "content/browser/device_monitor_linux.h"
#elif defined(OS_MACOSX)
#include "content/browser/device_monitor_mac.h"
#endif #endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -505,6 +507,17 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() { ...@@ -505,6 +507,17 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
GamepadService::GetInstance()->Terminate(); GamepadService::GetInstance()->Terminate();
// The device monitors are using |system_monitor_| as dependency, so delete
// them before |system_monitor_| goes away.
// On Mac and windows, the monitor needs to be destroyed on the same thread
// as they were created. On Linux, the monitor will be deleted when IO thread
// goes away.
#if defined(OS_WIN)
system_message_window_.reset();
#elif defined(OS_MACOSX)
device_monitor_mac_.reset();
#endif
// Must be size_t so we can subtract from it. // Must be size_t so we can subtract from it.
for (size_t thread_id = BrowserThread::ID_COUNT - 1; for (size_t thread_id = BrowserThread::ID_COUNT - 1;
thread_id >= (BrowserThread::UI + 1); thread_id >= (BrowserThread::UI + 1);
...@@ -619,6 +632,8 @@ void BrowserMainLoop::BrowserThreadsStarted() { ...@@ -619,6 +632,8 @@ void BrowserMainLoop::BrowserThreadsStarted() {
#if defined(OS_LINUX) #if defined(OS_LINUX)
device_monitor_linux_.reset(new DeviceMonitorLinux()); device_monitor_linux_.reset(new DeviceMonitorLinux());
#elif defined(OS_MACOSX)
device_monitor_mac_.reset(new DeviceMonitorMac());
#endif #endif
// RDH needs the IO thread to be created. // RDH needs the IO thread to be created.
......
...@@ -50,6 +50,8 @@ struct MainFunctionParams; ...@@ -50,6 +50,8 @@ struct MainFunctionParams;
#if defined(OS_LINUX) #if defined(OS_LINUX)
class DeviceMonitorLinux; class DeviceMonitorLinux;
#elif defined(OS_MACOSX)
class DeviceMonitorMac;
#endif #endif
// Implements the main browser loop stages called from BrowserMainRunner. // Implements the main browser loop stages called from BrowserMainRunner.
...@@ -111,6 +113,8 @@ class BrowserMainLoop { ...@@ -111,6 +113,8 @@ class BrowserMainLoop {
scoped_ptr<SystemMessageWindowWin> system_message_window_; scoped_ptr<SystemMessageWindowWin> system_message_window_;
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
scoped_ptr<DeviceMonitorLinux> device_monitor_linux_; scoped_ptr<DeviceMonitorLinux> device_monitor_linux_;
#elif defined(OS_MACOSX)
scoped_ptr<DeviceMonitorMac> device_monitor_mac_;
#endif #endif
// Destroy parts_ before main_message_loop_ (required) and before other // Destroy parts_ before main_message_loop_ (required) and before other
......
// 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 "content/browser/device_monitor_mac.h"
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/usb/IOUSBLib.h>
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_ioobject.h"
namespace content {
namespace {
const io_name_t kServices[] = {
kIOFirstPublishNotification,
kIOTerminatedNotification,
};
CFMutableDictionaryRef CreateMatchingDictionaryForUSBDevices(
SInt32 interface_class_code, SInt32 interface_subclass_code) {
CFMutableDictionaryRef matching_dictionary =
IOServiceMatching(kIOUSBInterfaceClassName);
base::mac::ScopedCFTypeRef<CFNumberRef> number_ref(CFNumberCreate(
kCFAllocatorDefault, kCFNumberSInt32Type, &interface_class_code));
DCHECK(number_ref);
CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceClass),
number_ref);
number_ref.reset(CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&interface_subclass_code));
DCHECK(number_ref);
CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceSubClass),
number_ref);
return matching_dictionary;
}
void RegisterCallbackToIOService(IONotificationPortRef port,
const io_name_t type,
CFMutableDictionaryRef dictionary,
IOServiceMatchingCallback callback,
void* context,
io_iterator_t* service) {
kern_return_t err = IOServiceAddMatchingNotification(port,
type,
dictionary,
callback,
context,
service);
if (err) {
NOTREACHED() << "Failed to register the IO matched notification for type "
<< type;
return;
}
DCHECK(*service);
// Iterate over set of matching devices to access already-present devices
// and to arm the notification.
for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(*service));
object;
object.reset(IOIteratorNext(*service))) {};
}
} // namespace
DeviceMonitorMac::DeviceMonitorMac() {
// Add the notification port to the run loop.
notification_port_ = IONotificationPortCreate(kIOMasterPortDefault);
DCHECK(notification_port_);
RegisterAudioServices();
RegisterVideoServices();
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notification_port_),
kCFRunLoopCommonModes);
}
DeviceMonitorMac::~DeviceMonitorMac() {
// Stop the notifications and free the objects.
for (size_t i = 0; i < notification_iterators_.size(); ++i) {
IOObjectRelease(*notification_iterators_[i]);
}
notification_iterators_.clear();
// Remove the notification port from the message runloop.
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notification_port_),
kCFRunLoopCommonModes);
// Destroy the notification port allocated by IONotificationPortCreate.
IONotificationPortDestroy(notification_port_);
}
void DeviceMonitorMac::RegisterAudioServices() {
CFMutableDictionaryRef dictionary =
IOServiceMatching(kIOAudioDeviceClassName);
RegisterServices(dictionary, &AudioDeviceCallback);
}
void DeviceMonitorMac::RegisterVideoServices() {
CFMutableDictionaryRef dictionary = CreateMatchingDictionaryForUSBDevices(
kUSBVideoInterfaceClass, kUSBVideoControlSubClass);
RegisterServices(dictionary, &VideoDeviceCallback);
}
void DeviceMonitorMac::RegisterServices(CFMutableDictionaryRef dictionary,
IOServiceMatchingCallback callback) {
// Add callback to the service.
for (size_t i = 0; i < arraysize(kServices); ++i) {
// |dictionary| comes in with a reference count as 1. Since each call to
// IOServiceAddMatchingNotification consumes one reference, we need to
// retain |arraysize(kServices) -1| additional dictionary references.
if (i < (arraysize(kServices) - 1))
CFRetain(dictionary);
// Register callback to each service.
io_iterator_t service;
RegisterCallbackToIOService(notification_port_,
kServices[i],
dictionary,
callback,
this,
&service);
// Store the pointer of the object to release the memory when shutting
// down the services.
notification_iterators_.push_back(&service);
}
}
void DeviceMonitorMac::AudioDeviceCallback(void *context,
io_iterator_t iterator) {
for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(iterator));
object;
object.reset(IOIteratorNext(iterator))) {
if (context) {
reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged(
base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
}
}
}
void DeviceMonitorMac::VideoDeviceCallback(void *context,
io_iterator_t iterator) {
for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(iterator));
object;
object.reset(IOIteratorNext(iterator))) {
if (context) {
reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged(
base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
}
}
}
void DeviceMonitorMac::NotifyDeviceChanged(
base::SystemMonitor::DeviceType type) {
// TODO(xians): Remove the global variable for SystemMonitor.
base::SystemMonitor::Get()->ProcessDevicesChanged(type);
}
} // namespace content
// 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.
#ifndef CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
#define CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
#include <IOKit/IOKitLib.h>
#include <vector>
#include "base/basictypes.h"
#include "base/system_monitor/system_monitor.h"
namespace content {
class DeviceMonitorMac {
public:
DeviceMonitorMac();
~DeviceMonitorMac();
private:
void RegisterAudioServices();
void RegisterVideoServices();
static void AudioDeviceCallback(void *context, io_iterator_t iterator);
static void VideoDeviceCallback(void *context, io_iterator_t iterator);
// Forward the notifications to system monitor.
void NotifyDeviceChanged(base::SystemMonitor::DeviceType type);
// Helper.
void RegisterServices(CFMutableDictionaryRef dictionary,
IOServiceMatchingCallback callback);
IONotificationPortRef notification_port_;
std::vector<io_iterator_t*> notification_iterators_;
DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMac);
};
} // namespace content
#endif // CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
...@@ -276,6 +276,8 @@ ...@@ -276,6 +276,8 @@
'browser/debugger/worker_devtools_message_filter.h', 'browser/debugger/worker_devtools_message_filter.h',
'browser/device_monitor_linux.cc', 'browser/device_monitor_linux.cc',
'browser/device_monitor_linux.h', 'browser/device_monitor_linux.h',
'browser/device_monitor_mac.cc',
'browser/device_monitor_mac.h',
'browser/device_orientation/accelerometer_mac.cc', 'browser/device_orientation/accelerometer_mac.cc',
'browser/device_orientation/accelerometer_mac.h', 'browser/device_orientation/accelerometer_mac.h',
'browser/device_orientation/data_fetcher.h', 'browser/device_orientation/data_fetcher.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment