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 |