| Index: content/browser/device_monitor_mac.mm
|
| ===================================================================
|
| --- content/browser/device_monitor_mac.mm (revision 0)
|
| +++ content/browser/device_monitor_mac.mm (revision 0)
|
| @@ -0,0 +1,147 @@
|
| +// 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 <CoreFoundation/CFNumber.h>
|
| +#include <CoreFoundation/CoreFoundation.h>
|
| +#include <IOKit/usb/IOUSBLib.h>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/system_monitor/system_monitor.h"
|
| +
|
| +namespace {
|
| +
|
| +struct {
|
| + base::SystemMonitor::DeviceType device_type;
|
| + SInt32 interface_class_code;
|
| + SInt32 interface_subclass_code;
|
| +} kInterfaceTypeMap[] = {
|
| + // Add new types here if needed.
|
| + { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kUSBAudioInterfaceClass,
|
| + kUSBAudioControlSubClass },
|
| + { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kUSBVideoInterfaceClass,
|
| + kUSBVideoControlSubClass },
|
| +};
|
| +
|
| +void AddValueToDictionary(CFMutableDictionaryRef dictionary,
|
| + SInt32 code,
|
| + const void *key) {
|
| + CFNumberRef number_ref = CFNumberCreate(kCFAllocatorDefault,
|
| + kCFNumberSInt32Type,
|
| + &code);
|
| + if (!number_ref) {
|
| + NOTREACHED() << "failed to create CFNumberRef for " << code;
|
| + return;
|
| + }
|
| +
|
| + CFDictionaryAddValue(dictionary, key, number_ref);
|
| + CFRelease(number_ref);
|
| +}
|
| +
|
| +CFMutableDictionaryRef CreateMatchingDictionary(
|
| + SInt32 interface_class_code,
|
| + SInt32 interface_subclass_code) {
|
| + CFMutableDictionaryRef matching_dictionary = IOServiceMatching(
|
| + kIOUSBInterfaceClassName);
|
| + AddValueToDictionary(matching_dictionary, interface_class_code,
|
| + CFSTR(kUSBInterfaceClass));
|
| + AddValueToDictionary(matching_dictionary, interface_subclass_code,
|
| + CFSTR(kUSBInterfaceSubClass));
|
| +
|
| + return matching_dictionary;
|
| +}
|
| +
|
| +void AddCallbackToIOService(IONotificationPortRef port,
|
| + const io_name_t type,
|
| + CFMutableDictionaryRef dictionary,
|
| + IOServiceMatchingCallback callback,
|
| + void* context) {
|
| + // Retain additional dictionary references because each call to
|
| + // IOServiceAddMatchingNotification consumes one reference.
|
| + dictionary = (CFMutableDictionaryRef)(CFRetain(dictionary));
|
| +
|
| + io_iterator_t devices_iterator = 0;
|
| + kern_return_t err = IOServiceAddMatchingNotification(port,
|
| + type,
|
| + dictionary,
|
| + callback,
|
| + context,
|
| + &devices_iterator);
|
| + if (err) {
|
| + NOTREACHED() << "Failed to register the IO matched notification for type "
|
| + << type;
|
| + return;
|
| + }
|
| +
|
| + // Iterate over set of matching devices to access already-present devices
|
| + // and to arm the notification.
|
| + io_object_t this_object;
|
| + while ((this_object = IOIteratorNext(devices_iterator)))
|
| + IOObjectRelease(this_object);
|
| +}
|
| +
|
| +// For now, context is a cast of device_type. If |this| is needed,
|
| +// DeviceMonitorMac can keep an list of objects of
|
| +// struct Context {
|
| +// base::SystemMonitor::DeviceType device_type;
|
| +// DeviceMonitorMac* instance;
|
| +// };
|
| +void DevicesChangedCallback(void *context, io_iterator_t devices) {
|
| + io_object_t this_object;
|
| + while ((this_object = IOIteratorNext(devices))) {
|
| + if (context) {
|
| + base::SystemMonitor::DeviceType device_type =
|
| + *(static_cast<base::SystemMonitor::DeviceType*>(context));
|
| + base::SystemMonitor::Get()->ProcessDevicesChanged(device_type);
|
| + }
|
| + IOObjectRelease(this_object);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace content {
|
| +
|
| +DeviceMonitorMac::DeviceMonitorMac() {
|
| + CFRunLoopRef runloop = CFRunLoopGetCurrent();
|
| + CFRetain(runloop);
|
| +
|
| + // Add the notification port to the run loop.
|
| + IONotificationPortRef notification_port =
|
| + IONotificationPortCreate(kIOMasterPortDefault);
|
| + CFRunLoopSourceRef notification_cfsource =
|
| + IONotificationPortGetRunLoopSource(notification_port);
|
| +
|
| + RegisterCallbacks(notification_port);
|
| + CFRunLoopAddSource(runloop, notification_cfsource, kCFRunLoopCommonModes);
|
| +}
|
| +
|
| +DeviceMonitorMac::~DeviceMonitorMac() {}
|
| +
|
| +void DeviceMonitorMac::RegisterCallbacks(IONotificationPortRef port) {
|
| + for (size_t i = 0; i < arraysize(kInterfaceTypeMap); i++) {
|
| + CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary(
|
| + kInterfaceTypeMap[i].interface_class_code,
|
| + kInterfaceTypeMap[i].interface_subclass_code);
|
| +
|
| + // Add a callback which will be called when a device is plugged in.
|
| + AddCallbackToIOService(
|
| + port,
|
| + kIOMatchedNotification,
|
| + matching_dictionary,
|
| + &DevicesChangedCallback,
|
| + static_cast<void*>(&kInterfaceTypeMap[i].device_type));
|
| +
|
| + // Add a callback which will be called when a video device is terminated.
|
| + AddCallbackToIOService(
|
| + port,
|
| + kIOTerminatedNotification,
|
| + matching_dictionary,
|
| + &DevicesChangedCallback,
|
| + static_cast<void*>(&kInterfaceTypeMap[i].device_type));
|
| + }
|
| +}
|
| +
|
| +} // namespace content
|
|
|
| Property changes on: content/browser/device_monitor_mac.mm
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|